GNU bug report logs - #80323
[PATCH] Rewrite flex completion scoring with Gotoh algorithm

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: emacs; Reported by: João Távora <joaotavora@HIDDEN>; Keywords: patch; dated Tue, 3 Feb 2026 12:35:01 UTC; Maintainer for emacs is bug-gnu-emacs@HIDDEN.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 8 Feb 2026 16:58:41 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Feb 08 11:58:41 2026
Received: from localhost ([127.0.0.1]:53186 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vp87N-0002zF-7u
	for submit <at> debbugs.gnu.org; Sun, 08 Feb 2026 11:58:41 -0500
Received: from mailscanner.iro.umontreal.ca ([132.204.25.50]:26537)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <monnier@HIDDEN>)
 id 1vp87K-0002yL-Ko
 for 80323 <at> debbugs.gnu.org; Sun, 08 Feb 2026 11:58:39 -0500
Received: from pmg2.iro.umontreal.ca (localhost.localdomain [127.0.0.1])
 by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 2F20181BB1;
 Sun,  8 Feb 2026 11:58:33 -0500 (EST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=iro.umontreal.ca;
 s=mail; t=1770569911;
 bh=JMZc7U41aIK0hwDsoYaGuklSYp/d3IIg0JfrNLfhbuo=;
 h=From:To:Cc:Subject:In-Reply-To:References:Date:From;
 b=HsFKtmjz2U41V3Av7cMvQLzM7fefxhfb8lEaxoOH7JbXRGPDQ10fo8UZe8jaPznD3
 GHi8hFp0gsxYlmzQN2F8yLgMVAylqibfCrkVninV/NUzMWZhbyVK+DvCKGiSPUhnOV
 PuJc8pc5I6EYljSkE1QIBZjdy4LbFFbnRaKtWR+0CI7rBoabd14vjWEp1y6D4+EuXb
 vFDx0Nsbx7z0rRgQcWxiqA8mH/JaQD6CcgI13GURgeW21EHYmXvGfzGYO7bfRAoS5c
 R5hHQf6VF/j+PK8ryiiUdeNEkaTRG8KDiCzu/UFCJYcrKHeKzO+sPIESBVLUf0PKld
 A+ZX/yWa2rItA==
Received: from mail01.iro.umontreal.ca (unknown [172.31.2.1])
 by pmg2.iro.umontreal.ca (Proxmox) with ESMTP id 0D34880872;
 Sun,  8 Feb 2026 11:58:31 -0500 (EST)
Received: from pastel (104-195-243-38.cpe.teksavvy.com [104.195.243.38])
 by mail01.iro.umontreal.ca (Postfix) with ESMTPSA id BDF331208A4;
 Sun,  8 Feb 2026 11:58:30 -0500 (EST)
From: Stefan Monnier <monnier@HIDDEN>
To: =?windows-1252?B?Sm/jbyBU4XZvcmE=?= <joaotavora@HIDDEN>
Subject: Re: feature/newflex2 a0b5ff9bb79: Rewrite flex completion scoring
 with Gotoh algorithm
In-Reply-To: <20260207212515.0BD1CC06C63@HIDDEN>
Message-ID: <jwvqzqv2myy.fsf-monnier+emacs@HIDDEN>
References: <177049951444.27865.13520833628888303186@HIDDEN>
 <20260207212515.0BD1CC06C63@HIDDEN>
Date: Sun, 08 Feb 2026 11:58:30 -0500
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
X-SPAM-INFO: Spam detection results:  0
 ALL_TRUSTED                -1 Passed through trusted hosts only via SMTP
 AWL -0.142 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DKIM_SIGNED               0.1 Message has a DKIM or DK signature,
 not necessarily valid
 DKIM_VALID -0.1 Message has at least one valid DKIM or DK signature
 DKIM_VALID_AU -0.1 Message has a valid DKIM or DK signature from author's
 domain
 DKIM_VALID_EF -0.1 Message has a valid DKIM or DK signature from envelope-from
 domain
X-SPAM-LEVEL: 
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80323
Cc: Axel Forsman <axel@HIDDEN>, Eli Zaretskii <eliz@HIDDEN>,
 Sean Whitton <spwhitton@HIDDEN>, 80323 <at> debbugs.gnu.org,
 =?windows-1252?Q?St=E9phane?= Marks <shipmints@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Jo=E3o T=E1vora [2026-02-07 16:25:14] wrote:

> branch: feature/newflex2
> commit a0b5ff9bb79681279a351de47d379f247e14424d
> Author: Jo=E3o T=E1vora <joaotavora@HIDDEN>
> Commit: Jo=E3o T=E1vora <joaotavora@HIDDEN>
>
>     Rewrite flex completion scoring with Gotoh algorithm

LGTM!


=3D=3D=3D Stefan





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 7 Feb 2026 14:02:54 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sat Feb 07 09:02:54 2026
Received: from localhost ([127.0.0.1]:34827 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voith-0008E5-W5
	for submit <at> debbugs.gnu.org; Sat, 07 Feb 2026 09:02:54 -0500
Received: from sendmail.purelymail.com ([34.202.193.197]:44574)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <spwhitton@HIDDEN>)
 id 1voitf-0008Do-LL
 for 80323 <at> debbugs.gnu.org; Sat, 07 Feb 2026 09:02:52 -0500
DKIM-Signature: a=rsa-sha256;
 b=TrUBGvIKu9hJXG6EGydfhDPzX3MRcUwmQPNy/hwzPUbWT79bVzszTln8dD4u64Oax7iaZSOalR8vQCVOilcs0/52wbbsx2V7nOxPbwzNrWr7vC70fWMw3vo+yZxvQvimCUwylqxAolpjz97r2LimlNCfneYmaEqyJN9oOpWgVvUYK306NwC+QiGbUDIFwG/MD38/jME8sZQx+jlrWNSGhNgAaHmAs7x0Z3WHp2Vq58WtQZMRIgiggIAAkH5BjtiC+ghdwzUL1iZWsKEhFF3oqCg9qkSFBSKOcV9W8orusRL776x52kzIx6Bip++mjQ38l5TZ+9s+mm3oD/r7pbQXoA==;
 s=purelymail3; d=spwhitton.name; v=1;
 bh=p0lZsLcCskyX18PTPQOEFstBoDNWLCBW0OBlQRI5jOU=;
 h=Received:Received:From:To:Subject:Date; 
DKIM-Signature: a=rsa-sha256;
 b=RM1oKRhmqN12Sr30no77HaMkRbUFztLJ1L0KkIthg3qJ9g/xJQARWOeKdpHyYUeinBSizfD4lLQ5P3pS7ygUj6gMskxo3kksYfex7WTxkh8eOGc7P+/IHn8t0y5Ma/kkn85QikKdpO2OTH3T1UgoxLub3uVfWHQUMckIUARGiQBZfuW0rhRHlrWnil1DIdSlVpiLqUQc/OfiR/rZ0qMK7Dm4ksBZ9EPg+A+IjsSaPor1M/n3NuboxLH8JzRzohHaIU9L5hOlD9XKCrrAIin8ZKVjsyfvG3/5y+2ki+twHRcFFRJxPRHrh4NMOTQuZRwMfdKovKXtjEHikZTIgiznNg==;
 s=purelymail3; d=purelymail.com; v=1;
 bh=p0lZsLcCskyX18PTPQOEFstBoDNWLCBW0OBlQRI5jOU=;
 h=Feedback-ID:Received:Received:From:To:Subject:Date; 
Feedback-ID: 20115:3760:null:purelymail
X-Pm-Original-To: 80323 <at> debbugs.gnu.org
Received: by smtp.purelymail.com (Purelymail SMTP) with ESMTPSA id 1583924012; 
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384);
 Sat, 07 Feb 2026 14:02:45 +0000 (UTC)
Received: by zephyr.silentflame.com (Postfix, from userid 1000)
 id E53DE940445; Sat, 07 Feb 2026 14:02:44 +0000 (GMT)
From: Sean Whitton <spwhitton@HIDDEN>
To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
In-Reply-To: <CALDnm51COBHHWot_5rMBxqwECbW0pzx2XwcKSFZsJBOoHeJ++A@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
 <87v7gadm9s.fsf@HIDDEN>
 <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
 <87h5rttni6.fsf@HIDDEN>
 <CALDnm50RYodwE6D1keiXvcpU3KBW2q9qCiU6MRZXqzjR-wYjHQ@HIDDEN>
 <CALDnm51COBHHWot_5rMBxqwECbW0pzx2XwcKSFZsJBOoHeJ++A@HIDDEN>
Date: Sat, 07 Feb 2026 14:02:44 +0000
Message-ID: <87fr7cd52z.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80323
Cc: 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

Jo=C3=A3o T=C3=A1vora [07/Feb  1:54am GMT] wrote:
> On Sat, Feb 7, 2026 at 12:49=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavora=
@gmail.com> wrote:
>>
>> On Sat, Feb 7, 2026 at 12:18=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavor=
a@HIDDEN> wrote:
>> >
>> > Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:
>> >
>> > > Hmmm I can't reproduce this. Are you sure you're not loading stale f=
iles?Try:
>> > >
>> > > src/emacs -Q -f fido-vertical-mode -f project-find-file
>> > >
>> > > from the Emacs source tree.
>> > >
>> > > I do see highlighting mistakes, but the filtering and sorting looks =
solid.
>> >
>> > I've fixed the highlighting mistakes and simplified the code in the
>>
>> Never mind, I think I do see some errors occasionally.
>> They're not in the C-code, rather in the Elisp.  Probably its time
>> flex stops (ab)using the legacy "pcm" and "substring" styles
>> infrastructure.
>
> Think I fixed them.  Have a go at feature/newflex when you find the time.
>
> I'll still try to decouple flex from the PCM machinery though, should
> remove many hacks.

Thanks, my issue seems not to be reproducible with the current branch.

--=20
Sean Whitton




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 7 Feb 2026 01:55:07 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 06 20:55:07 2026
Received: from localhost ([127.0.0.1]:58810 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voXXP-0004pU-GP
	for submit <at> debbugs.gnu.org; Fri, 06 Feb 2026 20:55:07 -0500
Received: from mail-ot1-x336.google.com ([2607:f8b0:4864:20::336]:42214)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1voXXK-0004nB-MF
 for 80323 <at> debbugs.gnu.org; Fri, 06 Feb 2026 20:55:05 -0500
Received: by mail-ot1-x336.google.com with SMTP id
 46e09a7af769-7d1872504cbso2200422a34.0
 for <80323 <at> debbugs.gnu.org>; Fri, 06 Feb 2026 17:55:02 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770429301; cv=none;
 d=google.com; s=arc-20240605;
 b=CWvpSu9jhsNsOWOQk1Yk9Jsgob7UKG+uX7UE0ehcN7tUDzZWK9Fn24kt+OqbsfNsx9
 W4VGuaBW+YPN+L9o/OKxSiGjbrE4+RGKFDDwaE91NF1GjkB5YHyVBZxvzS8RMNtNWZTU
 Lsp/3tbWqDwJxj5arYdyGpQ0nOWlMpv86jmp7AHoyEuDjZGGlyZSdl0P/NcK/43bts6O
 qpYvzCNEBYHdL25uxJJOAAjqt0yTSFv5Z4+deooFUzU/i/CvmHpjO6Drm3k5c5PRFqhM
 tPxir35umkJCnoojL3t+HK0BFwsAIOGBKn8PMcWkBRwcc2LT1XJvGO9fdxZwybIjPYmX
 ElbA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:dkim-signature;
 bh=nP8gJv4wXFoRou49Y/iW/B8jJJ7BcPhdE3t8frCng5E=;
 fh=KXVSpnQI7fHeNqW1W1EkZX7Vh0/EVBulmzyl15jHwBY=;
 b=K7Ooyab+rugU98hejPLu1jXDZspBKsCNnfh1HaLR2JFbG8swJ3EhEQ1hIdvf/SgXgF
 1G4MZQpikZtD3cB6N477hs6eTWwR1jNequoe5C1IB9pHDDCdKLozELowHW3WrynbVTSx
 dEbyY2yUnH8PKmyYnosxmswy7BrkYMwUnVAqGNHvIn55il72NN5VoWq5ajg/M/O1lYFU
 xtu144+e38ZAyykxm9SgBHIJTZIBrac6de46cXjCHHWO78v+H6YfMBqpgyCwdZ0lYBIW
 2nFQHEKcljUOmF5La9zjyM8vCgNdAMDds/KLL4U6MgynqN1jbVCYjvuTLfbPYBXqZC2g
 iO3g==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770429301; x=1771034101; darn=debbugs.gnu.org;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:from:to:cc:subject:date
 :message-id:reply-to;
 bh=nP8gJv4wXFoRou49Y/iW/B8jJJ7BcPhdE3t8frCng5E=;
 b=Qm7eGvMmNjo5VAZut+6zyA2uY0yFhS6MedxHkYqavzRPgJ44LBF38sviiZmNWRxZtp
 MWn2cSoSBfvWytxwjaaLVeeYiooc/l+i/vgt+0vQRIuDmkL6ybmNO1hZTz1LWjaq8zkt
 QkEztohy4VLYt5Hfb0fRIqZu+5RXL42uT7ZB8kx0tg9cO30/JgpsK14MPKn7ltXdRfNP
 GmdW/8QiLjwbUIbiOMbEk0bXZRt1JBwLOeTBn8+2KXTY92ilLm27aMi56Ar9odeUj781
 eUj5LmXeh4XR1oZCVAS42hxo9WOWauY4E0FvDDYD3kHcq0uasNLfhwfeqjY8lk+341ip
 jlCg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770429301; x=1771034101;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=nP8gJv4wXFoRou49Y/iW/B8jJJ7BcPhdE3t8frCng5E=;
 b=RRSfz0H+AOKsC+aUljeqYT8cUL7e5XpoIp54/FUPeHmjUj3oihFe/Fn22LZWthb3YL
 qkI/jslAem3s3NePkX0dyi5lR+2HdJAVrSlB4TJqMLLAiQ8VeF4stCORHfilz0Q3bWUt
 XIrLbuot3D3DTiLmvV8AlYQejBUqNztphh2ULfckoqB8Utww/sSWT4pY3L7uBYmqzyCv
 uB5XdYO6+yrgJ7kRRLWLyfDWd6zU395ozu1vKajbjcZOLFYxcWxh624aSNRTQ26WMHol
 s3jnn1xcF1lvq3r6B/64limtJbDEy/DFydwaqbts40M1Ig8DvtTM64jgR8MVkVyr7o9k
 TeWQ==
X-Gm-Message-State: AOJu0YxcOZYKZi0U18QlE6yo2BnY5wGnWXz5bH+hoBbQnRT6t3pizf3J
 hF3W+1R9LYYYDwxDRtXGCERYvuYn5U+PIi5mYM/qdNiyaj0XtUfLbJNojmk77xI7GcHlvTlMIGA
 YPtZWl0xg0Y+cEdeMxwI+tlQKovKuaws=
X-Gm-Gg: AZuq6aI2Y6B/S+VlMuPg00PSTI3ijQP9tqcnCcCiCywZMQOy1PA9B2fpDc2CmZQb1pl
 UHt8DtYyHpHabsTj/5DEw3jOGBNXCGWx/EQjSHpSSjMrYyXhFDHh8oviYurWpHF8eIQr8SRrJDQ
 CGozo5MkaLeQXOBEiqHcPjEOwRspNBgxPz6Ms14pUreDq9y7ahDOMBLbYw8Sw3kbJjilZabMRBV
 k8AGBEfKM8ntq9PwyxAh8hhd7pOdIIT33QAtm7TrtK33Aw11FTFNu1Y5y7LTg/dsdWxsA==
X-Received: by 2002:a05:6830:661c:b0:7cf:cd54:f4bc with SMTP id
 46e09a7af769-7d4634194admr2736895a34.18.1770429301170; Fri, 06 Feb 2026
 17:55:01 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
 <87v7gadm9s.fsf@HIDDEN>
 <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
 <87h5rttni6.fsf@HIDDEN>
 <CALDnm50RYodwE6D1keiXvcpU3KBW2q9qCiU6MRZXqzjR-wYjHQ@HIDDEN>
In-Reply-To: <CALDnm50RYodwE6D1keiXvcpU3KBW2q9qCiU6MRZXqzjR-wYjHQ@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Sat, 7 Feb 2026 01:54:50 +0000
X-Gm-Features: AZwV_QhFhlvhKlJ4dNxUtMJvGRLPicd84iq5qW0zR252Mw7BsR5nAQdvBm5mu_s
Message-ID: <CALDnm51COBHHWot_5rMBxqwECbW0pzx2XwcKSFZsJBOoHeJ++A@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: Sean Whitton <spwhitton@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

On Sat, Feb 7, 2026 at 12:49=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavora@g=
mail.com> wrote:
>
> On Sat, Feb 7, 2026 at 12:18=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavora=
@gmail.com> wrote:
> >
> > Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:
> >
> > > Hmmm I can't reproduce this. Are you sure you're not loading stale fi=
les?Try:
> > >
> > > src/emacs -Q -f fido-vertical-mode -f project-find-file
> > >
> > > from the Emacs source tree.
> > >
> > > I do see highlighting mistakes, but the filtering and sorting looks s=
olid.
> >
> > I've fixed the highlighting mistakes and simplified the code in the
>
> Never mind, I think I do see some errors occasionally.
> They're not in the C-code, rather in the Elisp.  Probably its time
> flex stops (ab)using the legacy "pcm" and "substring" styles
> infrastructure.

Think I fixed them.  Have a go at feature/newflex when you find the time.

I'll still try to decouple flex from the PCM machinery though, should
remove many hacks.


--=20
Jo=C3=A3o T=C3=A1vora




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 7 Feb 2026 00:49:55 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 06 19:49:54 2026
Received: from localhost ([127.0.0.1]:58306 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voWWI-00013f-Kn
	for submit <at> debbugs.gnu.org; Fri, 06 Feb 2026 19:49:54 -0500
Received: from mail-ot1-x331.google.com ([2607:f8b0:4864:20::331]:45203)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1voWWF-00013U-Vz
 for 80323 <at> debbugs.gnu.org; Fri, 06 Feb 2026 19:49:52 -0500
Received: by mail-ot1-x331.google.com with SMTP id
 46e09a7af769-7d18a9d2b1aso2194072a34.2
 for <80323 <at> debbugs.gnu.org>; Fri, 06 Feb 2026 16:49:51 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770425390; cv=none;
 d=google.com; s=arc-20240605;
 b=PNSLaHVHzyJS+vYu/+hkULZ1FMfx9brF9qD3R+iAHKiXa3rNSJsgzUfe4sXePZUEuS
 O0pAHF+278VycOH8vmSyCCESoWa9GuVVZndObtjiK63di6EnlXcrbR1B0tH0wzo+PpbH
 m6YzxktRQo3s9u1avSVeH7RE1fhz9apLS1ZAmnL3hbipTO/plyn6RyhyRVBvGQ9dVSfF
 k644Zs3DJq5j7OldPma/jkDKA99EMeiOz0yFkxPNOqWR4P8fwcUDRW/y1nrczqd6FGPF
 jMND1AZe8DplfEi69JKdyWui2Sb7FSC8JzVtU6XN53Ww5FLr1T9wW/cC7Rs9Ot/0fuM+
 tcrg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:dkim-signature;
 bh=6RQh8WAynncQJLE6oYWmfMAlDqxtVEkV7ohpxF+bS0Q=;
 fh=9UkE8d2UXp2uy5oCUPNyofwz0gi9iC3+JO7kqnVpHUc=;
 b=ObpiScBdNpnMZQSyp3nAmpnp45hMwqtgL2yIOvutFBEI7jyxH2j40giqoyP0YwHNb+
 1Ft8D5q0cnQt9dY9OXp3a///tCGxdQekqi453Aaeiv6Vl5qCgMB6hCf5EpIvEN5C2NDC
 GJSEsILQ8TaWofSt+3ESIGrB5Fbhkp3z54mMbcma4mD6aFWbltGKah3Bss7JLNnwvQ09
 /pflwncra/oRi/n2TLF4Ffzpf6Pz4agT3vRSp6ZH7PDqdMi0sX9yMSDCu5na3R98kj4/
 zJGUGoQ9tnNKR+LM6hk487F/9MZQ8ijpkCkFt5rx9+eWZ2xWcOLj9f9oc2ykJF7le4RZ
 ZY8w==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770425390; x=1771030190; darn=debbugs.gnu.org;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:from:to:cc:subject:date
 :message-id:reply-to;
 bh=6RQh8WAynncQJLE6oYWmfMAlDqxtVEkV7ohpxF+bS0Q=;
 b=i1Xrx7NA7mAQllm3PnbD8qh8dpIdYou+fEzikkH4anW42ZCUFJkrM06H4sgP7rcdQ8
 skk375jULzO5jVtF8qA9FW2DZEMC+PZspi4yShiBDkmMgn6BF8dcIFPPmehghYnVja5K
 dXbd+odCRFbU6Msc2kWv4xI7h9FDtyUh/GNYW+IzLnvWAf9VRqSdVROuLSo5m+rGa8zt
 OAAcKq3WW9lHdBLJOxMiJZWazY1FiNcmsIfzKhqsQt4+ogmPU8XQ6BY0nF8ZvfkAf7Ye
 Wks2FYN67/clZuvB7Jj84nlNJJmDsOXG2M7FD9bZjmiQKtSzLhMCnjB3+kKXcAOp3fgY
 NwQQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770425390; x=1771030190;
 h=content-transfer-encoding:cc:to:subject:message-id:date:from
 :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from
 :to:cc:subject:date:message-id:reply-to;
 bh=6RQh8WAynncQJLE6oYWmfMAlDqxtVEkV7ohpxF+bS0Q=;
 b=F+a2Tm+OaE+u+RKLrEzv/B0Nr9IDyqJEN4KHeKJJMf0THDzkUQ8t6rsRjNwQdUYbCr
 nuuud+CJoK8+Za+UYuJNRz0WV9RAqteDdbg6G9SEQiVKVmU84BZGwNqMb+BP70k3y+CL
 bUzUQoxBpRkptxTOicgHKWxfuROj8OJUAVt00dGxBe2jLguD2NNtx0Ia9RaaKQNwj6Bv
 pBAvHTBKLQzGWTav9DggJ+yddfT3foK9nggj88q3d3XRiwb5FY+BQ5kuWkyWkteDIO4z
 OoLoOKvykep8JzUp9vPQytRIZkN+VtpmcK8nDbSQYsoF5dNc1VIv3/MFiNyfWyXnGop1
 X+NQ==
X-Gm-Message-State: AOJu0YyxgU675nsAA/i9srP6utuPn7lxtdhrkFJOxs+M3r/JjymXfgqU
 oKrdBDBmlN2JhJyH7gv2EW5z5yKI45vnF40U7TmPAmliw6AfpP/V6JVZa/CM7Uf51iu3pYxp+7G
 qWO/ijDEMakUUnBKsoB032AuxkE4nPuY=
X-Gm-Gg: AZuq6aLMcNJ5qw7xZigsT/KKNUfVYejoojkamc1CP137SoQg4A5yFYimqEUOOI1Wri5
 P1TeEJUK/nKtbcRFAmnKC+TBqRDdx115yBAG5EsBUmW4g3WNf7kylFQCiVEkxio7IOvRG5h+/B9
 QfKecNSUc+w8V/4IyqSlfYIjHC5UBZgYNyw1rukOoSj8NoDigOUGQEKilzzF72PjIVZVCSRoKM+
 heLUmCPkcvWwZ6/H0XxJWqF32COrIl7aqwr2ZxpfkOBoW/o+Tj8KqUSSo8Iha8qUVQ+oA==
X-Received: by 2002:a05:6830:6188:b0:771:5ae2:fce0 with SMTP id
 46e09a7af769-7d464488f2bmr2140669a34.20.1770425390601; Fri, 06 Feb 2026
 16:49:50 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
 <87v7gadm9s.fsf@HIDDEN>
 <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
 <87h5rttni6.fsf@HIDDEN>
In-Reply-To: <87h5rttni6.fsf@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Sat, 7 Feb 2026 00:49:39 +0000
X-Gm-Features: AZwV_QhLNwXhWDl-m6zLRnOiIETzxTKErkonrPqkczpSOZ-yh84-ykR0hyj0d-M
Message-ID: <CALDnm50RYodwE6D1keiXvcpU3KBW2q9qCiU6MRZXqzjR-wYjHQ@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: Sean Whitton <spwhitton@HIDDEN>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: Axel Forsman <axel@HIDDEN>, Eli Zaretskii <eliz@HIDDEN>,
 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>,
 =?UTF-8?Q?St=C3=A9phane_Marks?= <shipmints@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

On Sat, Feb 7, 2026 at 12:18=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavora@g=
mail.com> wrote:
>
> Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:
>
> > Hmmm I can't reproduce this. Are you sure you're not loading stale file=
s?Try:
> >
> > src/emacs -Q -f fido-vertical-mode -f project-find-file
> >
> > from the Emacs source tree.
> >
> > I do see highlighting mistakes, but the filtering and sorting looks sol=
id.
>
> I've fixed the highlighting mistakes and simplified the code in the

Never mind, I think I do see some errors occasionally.
They're not in the C-code, rather in the Elisp.  Probably its time
flex stops (ab)using the legacy "pcm" and "substring" styles
infrastructure.

Jo=C3=A3o




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 7 Feb 2026 00:18:17 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 06 19:18:17 2026
Received: from localhost ([127.0.0.1]:58126 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voW1h-0007rU-37
	for submit <at> debbugs.gnu.org; Fri, 06 Feb 2026 19:18:17 -0500
Received: from mail-wm1-x333.google.com ([2a00:1450:4864:20::333]:46222)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1voW1e-0007rF-Mb
 for 80323 <at> debbugs.gnu.org; Fri, 06 Feb 2026 19:18:15 -0500
Received: by mail-wm1-x333.google.com with SMTP id
 5b1f17b1804b1-48069a48629so24251725e9.0
 for <80323 <at> debbugs.gnu.org>; Fri, 06 Feb 2026 16:18:14 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770423493; x=1771028293; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=oWAx3tdmxvE4pL2o01uVS2Ul6lirt3B/HPz4jwSzZXM=;
 b=f3dZJOfZqdnSgBgHNXhiuQiBWvPkerUZQtGgp3/HmyiNDR9QGEn8DTIAHSh6OnbdCd
 qqL6UMYrsvejQ+xKxVOgB36Nt2SR3iYMZYTw4UUPn6kHmaY9lrN5yR22wkIbLZBR+ZIh
 MIVFCsxxJxn5nE38PxhyPutEnGedmPvHOG+6LAlMUWsJPkXN1GAwSPDGnO7Q9o8zOFdL
 /6sR7KYZiP9TBA/UuPuWvO9msT+djDXEaGj4DaYw6DBHyscFCxp08AYt0R4LANfwh3HX
 HyKAgejFGeLwC2SfUDU1R0+2TsiWOAerWNoaxrVZ46wGhxX/wb9WQK2Lhmp8blQbfvuZ
 YI1w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770423493; x=1771028293;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:x-gm-gg
 :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
 bh=oWAx3tdmxvE4pL2o01uVS2Ul6lirt3B/HPz4jwSzZXM=;
 b=Fs14xH9vysCcSkIr0ulJNqQ2xaem59Rri/5bPu+ElR/9FMePWsnlVA/kqMCcrRRj33
 TPz9BO09AqWV+HCiBSBPBIgtbgVslqwK1yGDP9oSlLq1ct/CfRjeGsVXJandu0CJcfb2
 THP+LroBFIvhOp4GQgkKgxfR35l2W4XG6unhRFlrCUM5/1ndnP83FIb20iWRQMLr6/Bl
 oaC36HOtQohzdUuCsOHzixDcJYBXoRa4D7ClJtwrKYMcMAv9Y4ACupK9aPtM1FSQdunD
 19LQqAtjV5uWHjC9ZSVNtTnGJB1euJ2yeLp/jS3aAY2YwRN/73A6pTjlTQrpp3rrSc18
 Wu1A==
X-Gm-Message-State: AOJu0Yyf2o0A9ZXC7hjiLOLJ/k3hPsy5AZf/G0yHffesy9yUdUxMVsz7
 WGTuaqoAxDGJqbGweiP1dXuy6hkd4GzwiStokaMOJ8kmLzcJ4gs7o7jB1CNmpQ==
X-Gm-Gg: AZuq6aJUNjN5NoKzgJ254siUmKM7GEudk4/rLmHT4sP6lO6KVmEsjlzRqfXiTbbv72M
 MLiPLLpPFA2G1aKAIXeegCD8CIdcrzcrFnHNSgvmGEPX9lq1jKXlBJ67LOzOcvtSVs/ywM+CaXV
 57aB64e8RSb1UkadvxkY0L/JxzyVggOZitqfB6CpadyoVQC9hdWEOA8LNjJBt5z5C9Z0/NWVa62
 2fsdU68e8g8hBYY+zyTh/QaSmMeqHzP4xwFomWPfurN8NtfcVVlnagA911aDISz9Pt1sMtfCXXh
 cxof3fftV58mMDrWiY9dsEV0gsa8S8XMe1LKqYGuki+1xPLcUSGLD/g/91E48Nftf4VpoGv9bOF
 xfOKYfdzV1ZF9Tdl00DlIhiFnPps8oBU7tbg4hB4E5Nvmh5GWPLGRi3Tbt8ZPmL4BsPtdZdOJWW
 PbU/tLORfYchjJBG9764D48En7LA==
X-Received: by 2002:a05:600c:474c:b0:482:ef72:5778 with SMTP id
 5b1f17b1804b1-483201dc4efmr68817435e9.8.1770423492972; 
 Fri, 06 Feb 2026 16:18:12 -0800 (PST)
Received: from krug (87-196-74-61.net.novis.pt. [87.196.74.61])
 by smtp.gmail.com with ESMTPSA id
 5b1f17b1804b1-48317d299bfsm146853795e9.2.2026.02.06.16.18.11
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Fri, 06 Feb 2026 16:18:11 -0800 (PST)
From: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
To: Sean Whitton <spwhitton@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
In-Reply-To: <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
 <87v7gadm9s.fsf@HIDDEN>
 <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
Date: Sat, 07 Feb 2026 00:18:09 +0000
Message-ID: <87h5rttni6.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: Axel Forsman <axel@HIDDEN>, Eli Zaretskii <eliz@HIDDEN>,
 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>,
 =?utf-8?Q?St=C3=A9phane?= Marks <shipmints@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:

> Hmmm I can't reproduce this. Are you sure you're not loading stale files?=
Try:=20
>
> src/emacs -Q -f fido-vertical-mode -f project-find-file
>
> from the Emacs source tree.
>
> I do see highlighting mistakes, but the filtering and sorting looks solid=
.=20

I've fixed the highlighting mistakes and simplified the code in the
latest version pushed to feature/newflex.  I've also that flex
occasionally manages to be slightly faster than hotfuzz in short
patterns (1-4 chars).

=E2=9D=AF src/emacs -Q --batch -l bench-completion-full.el -- flex  vc
Total time: 0.825 seconds (13.0 GCs taking 0.090 sec)
Time per call: 4.125 ms
=E2=9D=AF src/emacs -Q --batch -L ~/Source/Emacs/hotfuzz -l bench-completio=
n-full.el -- hotfuzz  vc
Total time: 0.909 seconds (26.0 GCs taking 0.204 sec)
Time per call: 4.545 ms

Jo=C3=A3o




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 6 Feb 2026 14:18:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 06 09:18:46 2026
Received: from localhost ([127.0.0.1]:53086 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voMfV-0002dp-R9
	for submit <at> debbugs.gnu.org; Fri, 06 Feb 2026 09:18:46 -0500
Received: from mail-oo1-xc2a.google.com ([2607:f8b0:4864:20::c2a]:43190)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1voMfS-0002dd-Nh
 for 80323 <at> debbugs.gnu.org; Fri, 06 Feb 2026 09:18:44 -0500
Received: by mail-oo1-xc2a.google.com with SMTP id
 006d021491bc7-662f91bba0fso1996717eaf.0
 for <80323 <at> debbugs.gnu.org>; Fri, 06 Feb 2026 06:18:42 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770387522; cv=none;
 d=google.com; s=arc-20240605;
 b=anh8XUTdGOqAwuFXpMzI6fHZ0A6u6bTO8557zeWsFEukMOJqtHPGXEl3DAchcg0Wk8
 +yPO6CK/8Ifktv9M031eXhFJp45zXMgX9KT598OFI0M/gbYzr4GDXXTNgzsKPV80++l3
 cT/+KYsaXQPT9JC6WoBc724ni1AYYcrCIOlzj7ourB9uQ343euquZNYrcdw3b2wkyDc6
 Gw71XSKhvKA5C5XXVQdVEaCgOwgpMT4XLPcO+xGhG+SP/n8OPN4MetbRIR5LM8voBn72
 hl/qJ2mLTm6czXxwFtoVfLYW88/qjw13ZkXuQS2hY80x/dlFNIdHU0RL0f8Id+OBDPQf
 3jQA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:dkim-signature;
 bh=XcGgvF6speofxb7JFmsxeV7N/sXUtehBuc6TBMolQ50=;
 fh=9UkE8d2UXp2uy5oCUPNyofwz0gi9iC3+JO7kqnVpHUc=;
 b=VQtB9UfjzCM30PrUkV+48EhD6WgI/lEDufscsuB2aho7+2kXyxqkZjZBMn0jwyguvL
 A3i3Z199+W7fVoTW/88gYRKr1N04rlmwbrLSAehOC6qM09cTgAnQOKygWsVK/EzIL1vQ
 howDJDqYKNl011PM4gmvUXSZMr0EGDABHBioYh1F5ToukC9G+66FV2aEJB7cB6xzemkD
 C89axCishOz1HzZMkO3xYglKDQ8/4WvUmrgIzo07tsR6be6zU0c3Ba8/Q6rNfrt2L7VO
 cQv+8g/1wb1qJqvCZXar5RwAZ18fuWAWuGJe0FW7S8HX2zMMsRWDf8bOjQ9ove0YEhJx
 JMOQ==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770387522; x=1770992322; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=XcGgvF6speofxb7JFmsxeV7N/sXUtehBuc6TBMolQ50=;
 b=BNooQLZImK0voOb2b6lU7JvZLj79ohoaDuASDDVrQZNtU7KA7ozgkbr1h6kEYMsp18
 OdkmqvqjmYy0T8PR/Ur61//WAqt7FBcm6u6yzbl8/Fd2++H/Cflv2BjxFCWhZe/Cm5TR
 7NIabss3xPia/GVXTc3sBEjZfmqWcCkNLPcbEiWKzb9fOr3UmSAeNH56k0Lhk0kxzLjF
 +0XAr1doI/G9m7G7Ende+Sun+jIkn0ZCTIby+LjnwfH2Xfd+/aeTkz5pATbukxLOfVmX
 AumeWEPCRQLcre8RCxdpy733e8eD9ENQIuKmejTufX3BTQq4EQy4jWIPRbWE577oect2
 VU+A==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770387522; x=1770992322;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=XcGgvF6speofxb7JFmsxeV7N/sXUtehBuc6TBMolQ50=;
 b=WIVOpzz68ZD5n5VcK77nmM3XaoK5E8yaL9MhSdEr2Ty22gfRBTuvxKwIaKaffLS5mk
 xp8z6dqIjx5NMQ4hQxa8btK2+yux5L7s25/LMXcW9u53D1PFRGyCcLDlg+KU6TJcpeIv
 mFY3uPlXTY47WatwTorRQ8HU0owUOVamGV/AZILwNJaFb4XndCfY/9au6crzYnSiUT7E
 21I6Vu+uDD2axNuX4TGaXKimjLqK5qP7vhvES0dI3bD3DxmJoTB89e63PwaPVQ0xY96w
 toJ00UPPDQwEvUzA0t/s8vA8/RjsR+ga631ceOI91VUYmx/AhGodTuXnfFIb3RMWXw/W
 PtZw==
X-Gm-Message-State: AOJu0YwFigTmcR8GV/bV/AfpMfJT5OV9YWq1OhR2zc15JjG7zO4/c4Oh
 kFi0P5Gj3zt89ihGhhRNjXgr3WNlBDCEnlEAFfPZZS5U4PfUdHWItoPTQSY8hdTY9GYX/EsNRmb
 /Mos/Xtj7k7TXsrs0jTKZ/Lt+IVfimtU=
X-Gm-Gg: AZuq6aKkSpZfoMB77N/Ca/YyRFz4lTsX4hS+JRarEQfav2VhXFY8/Q4/gm+7Gsm6Ptn
 3u7krl9mKd9fBZdYUJoCyO9c8l3L1+HDJXZXcI0a+g9J0euIuPb2WBoVOh0mPZ29nESlif5BwNG
 pNulT+YJCOU+pUiylyXN9zlBWSMBNPZELI/9iornpj9klGcMvrM3E0yugrgdSbHUfz+edeThBNt
 Bt1nWUqS7PHKmcdFJ3Bw/UAL7ZTDg4/eboIMZzuiY1a5ZfPvs/dGjTVXcvDA8zNnPtg5bg=
X-Received: by 2002:a05:6820:211:b0:662:ee28:1133 with SMTP id
 006d021491bc7-66d0f7f2c42mr1114001eaf.0.1770387521695; Fri, 06 Feb 2026
 06:18:41 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
 <87v7gadm9s.fsf@HIDDEN>
In-Reply-To: <87v7gadm9s.fsf@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Fri, 6 Feb 2026 14:18:32 +0000
X-Gm-Features: AZwV_Qg7K-FJMOlPlhsGgjNtUOEnDc-J_DtqecBLV6bndPdSFxa9Z2ggrWJ_h9s
Message-ID: <CALDnm51EU49u5XkmT0tX6WdhQxLEiQ5Og-31M7ynkfh_8FySaQ@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: Sean Whitton <spwhitton@HIDDEN>
Content-Type: multipart/alternative; boundary="0000000000005874c8064a28776c"
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: Axel Forsman <axel@HIDDEN>, Eli Zaretskii <eliz@HIDDEN>,
 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>,
 =?UTF-8?Q?St=C3=A9phane_Marks?= <shipmints@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

--0000000000005874c8064a28776c
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hmmm I can't reproduce this. Are you sure you're not loading stale
files?Try:

src/emacs -Q -f fido-vertical-mode -f project-find-file

from the Emacs source tree.

I do see highlighting mistakes, but the filtering and sorting looks solid.

Jo=C3=A3o

On Fri, Feb 6, 2026, 13:39 Sean Whitton <spwhitton@HIDDEN> wrote:

> Hello,
>
> Jo=C3=A3o T=C3=A1vora [05/Feb  3:40pm GMT] wrote:
> > Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:
> >
> >> Hi,
> >>
> >> The patch I'm attaching fixes them for good.
> >>
> >
> > I'm attaching a new version of the patch, which now also lives in the
> > feature/newflex branch of the Savannah repository.  It fixes the
> > problems with multibyte characters, adds comments to the code, and has
> > other improvements.  I've reviewed the flex unit tests and created a ne=
w
> > test with kanji characters.
> >
> > Please give it some testing.
>
> I did 'C-x p f' in emacs.git and typed 'vcvc' seeking to match
> 'lisp/vc/vc.el' and it got stuck again.  This is what I have in
> *Messages*:
>
> Error in post-command-hook (icomplete-post-command-hook): (error
> "Pattern vcvc. does not match
> test/lisp/emacs-lisp/package-resources/newer-versions/archive-contents")
>
> --
> Sean Whitton
>

--0000000000005874c8064a28776c
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div>Hmmm I can&#39;t reproduce this. Are you sure you&#3=
9;re not loading stale files?Try:=C2=A0</div><div dir=3D"auto"><br></div><d=
iv dir=3D"auto">src/emacs -Q -f fido-vertical-mode -f project-find-file</di=
v><div dir=3D"auto"><br></div><div dir=3D"auto">from the Emacs source tree.=
</div><div dir=3D"auto"><br></div><div dir=3D"auto">I do see highlighting m=
istakes, but the filtering and sorting looks solid.=C2=A0</div><div dir=3D"=
auto"><br></div><div dir=3D"auto">Jo=C3=A3o</div></div><br><div class=3D"gm=
ail_quote gmail_quote_container"><div dir=3D"ltr" class=3D"gmail_attr">On F=
ri, Feb 6, 2026, 13:39 Sean Whitton &lt;<a href=3D"mailto:spwhitton@spwhitt=
on.name">spwhitton@HIDDEN</a>&gt; wrote:<br></div><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex">Hello,<br>
<br>
Jo=C3=A3o T=C3=A1vora [05/Feb=C2=A0 3:40pm GMT] wrote:<br>
&gt; Jo=C3=A3o T=C3=A1vora &lt;<a href=3D"mailto:joaotavora@HIDDEN" targ=
et=3D"_blank" rel=3D"noreferrer">joaotavora@HIDDEN</a>&gt; writes:<br>
&gt;<br>
&gt;&gt; Hi,<br>
&gt;&gt;<br>
&gt;&gt; The patch I&#39;m attaching fixes them for good.<br>
&gt;&gt;<br>
&gt;<br>
&gt; I&#39;m attaching a new version of the patch, which now also lives in =
the<br>
&gt; feature/newflex branch of the Savannah repository.=C2=A0 It fixes the<=
br>
&gt; problems with multibyte characters, adds comments to the code, and has=
<br>
&gt; other improvements.=C2=A0 I&#39;ve reviewed the flex unit tests and cr=
eated a new<br>
&gt; test with kanji characters.<br>
&gt;<br>
&gt; Please give it some testing.<br>
<br>
I did &#39;C-x p f&#39; in emacs.git and typed &#39;vcvc&#39; seeking to ma=
tch<br>
&#39;lisp/vc/vc.el&#39; and it got stuck again.=C2=A0 This is what I have i=
n<br>
*Messages*:<br>
<br>
Error in post-command-hook (icomplete-post-command-hook): (error<br>
&quot;Pattern vcvc. does not match<br>
test/lisp/emacs-lisp/package-resources/newer-versions/archive-contents&quot=
;)<br>
<br>
-- <br>
Sean Whitton<br>
</blockquote></div>

--0000000000005874c8064a28776c--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 6 Feb 2026 13:39:22 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Feb 06 08:39:22 2026
Received: from localhost ([127.0.0.1]:52831 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1voM3O-0000hP-CR
	for submit <at> debbugs.gnu.org; Fri, 06 Feb 2026 08:39:22 -0500
Received: from sendmail.purelymail.com ([34.202.193.197]:59106)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <spwhitton@HIDDEN>)
 id 1voM3M-0000h9-8j
 for 80323 <at> debbugs.gnu.org; Fri, 06 Feb 2026 08:39:20 -0500
DKIM-Signature: a=rsa-sha256;
 b=We0PpQtUXN8QQahkIG+IGnbwel2ewHvP5kpK8O0RKda7ReRnu86nl10nbascePEfQqiM4RcNUeV8qhVy5+f94Ai0AWwrbS0DKC7HrnJVxRzJCjQ6OJ7fl6MCEWujBwEBI0xU9jyjrYUyuQpgQrQBcyT3+Z/UEZBOMTYwNt73OOAeqVKIwFkgy2bnTfawCRFO8dlOoYKr+iffNTl4HPD5Et7a1x7I6GYxwd53lsLmDtGA1DoAfSEi8gbBqYkUKLqXrBR/JBLp32IWou2Vc/dtS2aFCfdsG9sA/auBFF/QPMgXjeIrFVHpyp1iAqJg3vsHwSmibjcUBkqgwTxlNKv29Q==;
 s=purelymail3; d=spwhitton.name; v=1;
 bh=DOU9F8+fpZv5e9SEbMY/GaL3kur7wmKWvcs9UqYbNaA=;
 h=Received:Received:From:To:Subject:Date; 
DKIM-Signature: a=rsa-sha256;
 b=EGbGScZoSBMPOmuPvEZ3xkoEZ6n/1kEpPvnIFmwSgBK14/QXwsTneTImuOSuM4sU7uPvrIC0YyObgVbnbELnpMBFNKL1pYShPwZ0zjuOl6b+hfljdGhwly8D/vLTvAc4QQmXcs+XVBAJnMEeqs6fnVh+dzqn+QEXQ5I9mwKLNo8Js641/d/+mlfBrdfculHfNNhoik3WDfFIG0bAjwlHVhnG8bDMKmmXf7+L4+K/ymGsmUd9S/c+Cf1um/Qrl228qJKnCIsy0sXBo6DD3NUcfrBFCYn8kWZwtXOAS6HRR0rxrkJ1tb0DPT0dA8FmnCQ+klziDTYRyoqYzKx6gbsXdA==;
 s=purelymail3; d=purelymail.com; v=1;
 bh=DOU9F8+fpZv5e9SEbMY/GaL3kur7wmKWvcs9UqYbNaA=;
 h=Feedback-ID:Received:Received:From:To:Subject:Date; 
Feedback-ID: 20115:3760:null:purelymail
X-Pm-Original-To: 80323 <at> debbugs.gnu.org
Received: by smtp.purelymail.com (Purelymail SMTP) with ESMTPSA id 2017938127; 
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384);
 Fri, 06 Feb 2026 13:39:12 +0000 (UTC)
Received: by zephyr.silentflame.com (Postfix, from userid 1000)
 id 5A6DB9406A5; Fri, 06 Feb 2026 13:39:11 +0000 (GMT)
From: Sean Whitton <spwhitton@HIDDEN>
To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
In-Reply-To: <87fr7fjj1d.fsf@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN> <87fr7fjj1d.fsf@HIDDEN>
Date: Fri, 06 Feb 2026 13:39:11 +0000
Message-ID: <87v7gadm9s.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80323
Cc: axel@HIDDEN, Eli Zaretskii <eliz@HIDDEN>, 80323 <at> debbugs.gnu.org,
 monnier@HIDDEN,
 =?utf-8?Q?St=C3=A9phane?= Marks <shipmints@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

Jo=C3=A3o T=C3=A1vora [05/Feb  3:40pm GMT] wrote:
> Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:
>
>> Hi,
>>
>> The patch I'm attaching fixes them for good.
>>
>
> I'm attaching a new version of the patch, which now also lives in the
> feature/newflex branch of the Savannah repository.  It fixes the
> problems with multibyte characters, adds comments to the code, and has
> other improvements.  I've reviewed the flex unit tests and created a new
> test with kanji characters.
>
> Please give it some testing.

I did 'C-x p f' in emacs.git and typed 'vcvc' seeking to match
'lisp/vc/vc.el' and it got stuck again.  This is what I have in
*Messages*:

Error in post-command-hook (icomplete-post-command-hook): (error
"Pattern vcvc. does not match
test/lisp/emacs-lisp/package-resources/newer-versions/archive-contents")

--=20
Sean Whitton




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 5 Feb 2026 15:40:27 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Feb 05 10:40:27 2026
Received: from localhost ([127.0.0.1]:43898 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vo1Sz-0002fM-BF
	for submit <at> debbugs.gnu.org; Thu, 05 Feb 2026 10:40:27 -0500
Received: from mail-wr1-x431.google.com ([2a00:1450:4864:20::431]:43093)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vo1Sv-0002fA-7e
 for 80323 <at> debbugs.gnu.org; Thu, 05 Feb 2026 10:40:23 -0500
Received: by mail-wr1-x431.google.com with SMTP id
 ffacd0b85a97d-4359249bbacso1420362f8f.0
 for <80323 <at> debbugs.gnu.org>; Thu, 05 Feb 2026 07:40:21 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770306019; x=1770910819; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=M0P3doNGb63HVkhxN/vZHCuIGpEXonLDVp5CELsh/ac=;
 b=jKf9QJSDhgi478Sx7AREktN433+5k0n+f+EkSXoIW+umjzEFgbOICoTJqlyHTx54Ls
 BmzluVjIO6umNqFJHj/1g07PdcpdTIYyzl+QsgcCfZiaEPvYPb0/LKRM77LFSu9RLWoy
 I8AeV/GLtWufTuy6d45kln+r7IMMGang3+yTXfVDdtXf2vgXTit0r5BHAVA1Ap3ubfeB
 nupR7BjLpmqbBhMucwTtTWL2JNF+HgLOgQ5oTXRnIh5liBMuNokW+8mQUIxlBPDEf10Q
 GYCthwF6c/9mf90ErLegCGfn9FbmP/txNvsZhADLtrt38i5BMPd1hJlEP1w1vvWEy0eu
 OFtg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770306019; x=1770910819;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:x-gm-gg
 :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
 bh=M0P3doNGb63HVkhxN/vZHCuIGpEXonLDVp5CELsh/ac=;
 b=DrsaM48VCa1olKn5IDKbC5zI+rJZKsBkWL8NiMyUQXu1QVvL3Rlu9HfBXF/6L7BzA1
 dL6PducbU2zB+ht2w0YPXWgmRsGSMeghFK+U500yRnXXqEcXmBPLC1OMKhTb7HsvidUj
 XKqRYi1SPC6s9/W0G7uPC9/C1B79gGAy85/q3vCIh+U41NAbsKJhqo7ZaIHCb8OHZOED
 FPDAKrRHW2nsUr6Rt1FHIP5EcBKPZsL5yxzdSBhNILvBivIvSHqFusE9iuVuiQTPdJY7
 7NkzxA/ue/v/r38Upggh/my4LOM6FQLnzf3v56oS1gaSqkMuOaLJQogwQT18tLVQHFMR
 YN6Q==
X-Gm-Message-State: AOJu0YxoUqmazDvpV4YDtAmRmIDEiRYoN73TbV4LGs+haKYRxkyGpQ2V
 mO6P7NrFoqDyGp/JATpI0OjInc4HB/KqXH9g6epsgQm5L55FDnT6t32F
X-Gm-Gg: AZuq6aKBqfmkM2fgYJD/9ZGVf3j4Xd1GWmEPnzcUqbdoamFxNr8SaTRs1NOI1il4IDJ
 Vslu5RHZL/bJNVu/oCtVesXKNiITlQlDeeAU7K8XTOVzTp/GobrLvGAjxaxokwZZcI/D783n/8q
 bvRxdP0of53H8qpKFumURgZa5ocKtel97ua5MtmgmyIxYfiq2SVSHkZS1Agfz7vTe+fnYYscu/j
 qQXmcRzAZcnZsRZssEqHuFCIwR4dYlCmLA+aJ8LfzZkE+It5Ihn+80EvWQPVycJITMuP1W0PRpP
 KAGWTx14+tuvpNBpfkeiTOSrQvTJw+hhmBo/KNAjZcv5Zvzrx3kc5b04rfu/q/Ttf5hsUzxPohS
 v7tkgo+B3LBw6fWnYfQTxoX34qRoAf/THAG+wzLcE1+q8FynErvc4rCGFQHA8QQzV7esyJJWK9O
 YnUvdX8PC4nHcnLqauYTSxM5xyYQ==
X-Received: by 2002:a05:6000:2502:b0:431:8bf:f08c with SMTP id
 ffacd0b85a97d-436213e5dd2mr5671713f8f.21.1770306019035; 
 Thu, 05 Feb 2026 07:40:19 -0800 (PST)
Received: from krug (87-196-74-61.net.novis.pt. [87.196.74.61])
 by smtp.gmail.com with ESMTPSA id
 ffacd0b85a97d-43617e25d0dsm15373917f8f.7.2026.02.05.07.40.16
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Thu, 05 Feb 2026 07:40:17 -0800 (PST)
From: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
To: 80323 <at> debbugs.gnu.org
Subject: Re: [PATCH] Rewrite flex completion scoring with Gotoh algorithm
In-Reply-To: <87y0la2egy.fsf@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN>
Date: Thu, 05 Feb 2026 15:40:14 +0000
Message-ID: <87fr7fjj1d.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 4.6 (++++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  João Távora writes: > Hi, > > The patch I'm attaching fixes
    them for good. > I'm attaching a new version of the patch, which now also
    lives in the feature/newflex branch of the Savannah repository. It fixes
   the problems with multibyte characters, adds comments to the code, and [...]
    
 
 Content analysis details:   (4.6 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  3.6 RCVD_IN_SBL_CSS        RBL: Received via a relay in Spamhaus SBL-CSS
                             [87.196.74.61 listed in zen.spamhaus.org]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
                             provider (joaotavora[at]gmail.com)
  1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
                             headers
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
                              no trust
                             [2a00:1450:4864:20:0:0:0:431 listed in]
                             [list.dnswl.org]
X-Debbugs-Envelope-To: 80323
Cc: =?utf-8?Q?St=C3=A9phane?= Marks <shipmints@HIDDEN>,
 Sean Whitton <spwhitton@HIDDEN>, Eli Zaretskii <eliz@HIDDEN>,
 monnier@HIDDEN, axel@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 3.6 (+++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  João Távora writes: > Hi, > > The patch I'm attaching fixes
    them for good. > I'm attaching a new version of the patch, which now also
    lives in the feature/newflex branch of the Savannah repository. It fixes
   the problems with multibyte characters, adds comments to the code, and [...]
    
 
 Content analysis details:   (3.6 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  3.6 RCVD_IN_SBL_CSS        RBL: Received via a relay in Spamhaus SBL-CSS
                             [87.196.74.61 listed in zen.spamhaus.org]
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
                              no trust
                             [2a00:1450:4864:20:0:0:0:431 listed in]
                             [list.dnswl.org]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
                             provider (joaotavora[at]gmail.com)
  1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
                             headers
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN> writes:

> Hi,
>
> The patch I'm attaching fixes them for good.
>

I'm attaching a new version of the patch, which now also lives in the
feature/newflex branch of the Savannah repository.  It fixes the
problems with multibyte characters, adds comments to the code, and has
other improvements.  I've reviewed the flex unit tests and created a new
test with kanji characters.

Please give it some testing.

Regarding performance, I had said before that this was slightly faster
than 'hotfuzz' in certain scenarios.  That's mostly not true.  When its
multithreading, all-in-one sorting/filtering C module is used, hotfuzz
is faster, though not by much.  I don't think we'll ever get that
performance without significantly redoing the completion API and
leveraging multi-threading for such embarrassingly parallelisable
problems.

I also said it's slower than the old flex.  That's also not true, it's
now strictly faster (and of course much more correct).

See attached "benchmark-completion-full.el" for a utility to test both
styles.  It takes the style name and a pattern to match against every
symbol in obarray. Here are are possible invocations:

   $ src/emacs -Q --batch -l bench-completion-full.el -- flex  custgroup  2=
>&1
   [...]
   Total completions: 7
   First 10: (customize-group custom-group-of-mode custom-add-to-group cust=
om-declare-group custom-current-group customize-group-othe customize-apropo=
s-gr)
   [...]
   Total time: 1.699 seconds (2.0 GCs taking 0.015 sec)
   Time per call: 8.493 ms
=20=20=20
   $ src/emacs -Q --batch -L ~/Source/Emacs/hotfuzz -l bench-completion-ful=
l.el -- hotfuzz  custgroup  2>&1
   [...]
   Total completions: 7
   First 10: (customize-group custom-add-to-group custom-group-of-mode cust=
om-declare-group custom-current-group customize-apropos-gr customize-group-=
othe)
   [...]
   Total time: 1.016 seconds (25.0 GCs taking 0.207 sec)
   Time per call: 5.078 ms

The algorithm itself isn't the bottleneck, rather the logic in
minibuffer.el which hotfuzz sidesteps, in part.  To make the new flex
competitive I had to do some changes to that file's Elisp too.  They are
not too pretty, but then neither is that file.

I don't think I violated any tenets of the "PCM"completion API, but I'd
like Stefan to take a look if possible.

Patch after my sig,
Jo=C3=A3o

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index fc193fe54f0..5b5408a595c 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -4421,9 +4421,12 @@ completion-pcm--segments-point-idx
         (setq idx i)))
     idx))
=20
-(defun completion-pcm--all-completions (prefix pattern table pred)
+(defun completion-pcm--all-completions (prefix pattern table pred
+                                               &optional override-re)
   "Find all completions for PATTERN in TABLE obeying PRED.
-PATTERN is as returned by `completion-pcm--string->pattern'."
+PATTERN is as returned by `completion-pcm--string->pattern'.
+OVERRIDE-RE means to use this regular expression instead of grabbing one
+from PATTERN."
   ;; (cl-assert (=3D (car (completion-boundaries prefix table pred ""))
   ;;            (length prefix)))
   ;; Find an initial list of possible completions.
@@ -4435,7 +4438,7 @@ completion-pcm--all-completions
     ;; Use all-completions to do an initial cull.  This is a big win,
     ;; since all-completions is written in C!
     (let* (;; Convert search pattern to a standard regular expression.
-	   (regex (completion-pcm--pattern->regex pattern))
+           (regex (or override-re (completion-pcm--pattern->regex pattern)=
))
            (case-fold-search completion-ignore-case)
            (completion-regexp-list (cons regex completion-regexp-list))
 	   (compl (all-completions
@@ -4450,18 +4453,12 @@ completion-pcm--all-completions
 	    (when (string-match-p regex c) (push c poss)))
 	  (nreverse poss))))))
=20
-(defvar flex-score-match-tightness 3
-  "Controls how the `flex' completion style scores its matches.
+(defvar flex-score-match-tightness nil)
=20
-Value is a positive number.  A number smaller than 1 makes the
-scoring formula reward matches scattered along the string, while
-a number greater than one make the formula reward matches that
-are clumped together.  I.e \"foo\" matches both strings
-\"fbarbazoo\" and \"fabrobazo\", which are of equal length, but
-only a value greater than one will score the former (which has
-one large \"hole\" and a clumped-together \"oo\" match) higher
-than the latter (which has two \"holes\" and three
-one-letter-long matches).")
+(make-obsolete-variable
+ 'flex-score-match-tightness
+ "It never did anything very useful anyway."
+ "31.0")
=20
 (defvar completion-lazy-hilit nil
   "If non-nil, request lazy highlighting of completion candidates.
@@ -4502,133 +4499,49 @@ completion-lazy-hilit
       (funcall completion-lazy-hilit-fn (copy-sequence str))
     str))
=20
-(defun completion--hilit-from-re (string regexp &optional point-idx)
-  "Fontify STRING using REGEXP POINT-IDX.
-Uses `completions-common-part' and `completions-first-difference'
-faces to fontify STRING.
-POINT-IDX is the position of point in the presumed \"PCM\" pattern
-from which REGEXP was generated."
-  (let* ((md (and regexp (string-match regexp string) (cddr (match-data t)=
)))
-         (pos (if point-idx (match-beginning point-idx) (match-end 0)))
-         (me (and md (match-end 0)))
-         (from 0))
-    (while md
-      (add-face-text-property from (pop md)
-                              'completions-common-part nil string)
-      (setq from (pop md)))
-    (if (and (numberp pos) (> (length string) pos))
-        (add-face-text-property
-         pos (1+ pos)
-         'completions-first-difference
-         nil string))
-    (unless (or (not me) (=3D from me))
-      (add-face-text-property from me 'completions-common-part nil string))
-    string))
-
-(defun completion--flex-score-1 (md-groups match-end len)
-  "Compute matching score of completion.
-The score lies in the range between 0 and 1, where 1 corresponds to
-the full match.
-MD-GROUPS is the \"group\"  part of the match data.
-MATCH-END is the end of the match.
-LEN is the length of the completion string."
-  (let* ((from 0)
-         ;; To understand how this works, consider these simple
-         ;; ascii diagrams showing how the pattern "foo"
-         ;; flex-matches "fabrobazo", "fbarbazoo" and
-         ;; "barfoobaz":
-
-         ;;      f abr o baz o
-         ;;      + --- + --- +
-
-         ;;      f barbaz oo
-         ;;      + ------ ++
-
-         ;;      bar foo baz
-         ;;          +++
-
-         ;; "+" indicates parts where the pattern matched.  A
-         ;; "hole" in the middle of the string is indicated by
-         ;; "-".  Note that there are no "holes" near the edges
-         ;; of the string.  The completion score is a number
-         ;; bound by (0..1] (i.e., larger than (but not equal
-         ;; to) zero, and smaller or equal to one): the higher
-         ;; the better and only a perfect match (pattern equals
-         ;; string) will have score 1.  The formula takes the
-         ;; form of a quotient.  For the numerator, we use the
-         ;; number of +, i.e. the length of the pattern.  For
-         ;; the denominator, it first computes
-         ;;
-         ;;     hole_i_contrib =3D 1 + (Li-1)^(1/tightness)
-         ;;
-         ;; , for each hole "i" of length "Li", where tightness
-         ;; is given by `flex-score-match-tightness'.  The
-         ;; final value for the denominator is then given by:
-         ;;
-         ;;    (SUM_across_i(hole_i_contrib) + 1) * len
-         ;;
-         ;; , where "len" is the string's length.
-         (score-numerator 0)
-         (score-denominator 0)
-         (last-b 0))
-    (while (and md-groups (car md-groups))
-      (let ((a from)
-            (b (pop md-groups)))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b))
-      (setq from (pop md-groups)))
-    ;; If `pattern' doesn't have an explicit trailing any, the
-    ;; regex `re' won't produce match data representing the
-    ;; region after the match.  We need to account to account
-    ;; for that extra bit of match (bug#42149).
-    (unless (=3D from match-end)
-      (let ((a from)
-            (b match-end))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b)))
-    (/ score-numerator (* len (1+ score-denominator)) 1.0)))
-
-(defvar completion--flex-score-last-md nil
-  "Helper variable for `completion--flex-score'.")
-
-(defun completion--flex-score (str re &optional dont-error)
-  "Compute flex score of completion STR based on RE.
-If DONT-ERROR, just return nil if RE doesn't match STR."
-  (let ((case-fold-search completion-ignore-case))
-    (cond ((string-match re str)
-           (let* ((match-end (match-end 0))
-                  (md (cddr
-                       (setq
-                        completion--flex-score-last-md
-                        (match-data t completion--flex-score-last-md)))))
-             (completion--flex-score-1 md match-end (length str))))
-          ((not dont-error)
-           (error "Internal error: %s does not match %s" re str)))))
-
-(defvar completion-pcm--regexp nil
-  "Regexp from PCM pattern in `completion-pcm--hilit-commonality'.")
+(cl-defun completion--flex-score (pat str &optional dont-error)
+  "Compute flex score of STR matching PAT using Gotoh algorithm.
+If DONT-ERROR, return nil if PAT cannot match STR.
+Return (NORMALIZED-COST . MATCHES) where NORMALIZED-COST is a
+number (lower =3D better) and MATCHES is a list of match positions in STR."
+  (pcase-let ((`(,cost . ,matches)
+               (completion--flex-score-gotoh pat str)))
+    (unless cost
+      (if dont-error (cl-return-from completion--flex-score nil)
+        (error "Pattern %s does not match %s" pat str)))
+    (cons (* (1+ cost) (- (length str) (length pat))) matches)))
+
+(defun completion--flex-propertize (str matches point-idx segments)
+  "Add completion faces to STR based on MATCHES and POINT-IDX.
+MATCHES is a list of match positions.  POINT-IDX is a match group index
+from the PCM pattern.  SEGMENTS are extracted from the full PCM pattern.
+Adds `completions-common-part' for matched positions and
+`completions-first-difference' for the position corresponding to point."
+  (when point-idx
+    ;; Compute character position from segments
+    (let* ((pos (cl-loop for seg in segments
+                         for i from 1
+                         while (<=3D i point-idx)
+                         sum (length (car seg)))))
+      ;; Add first-difference after pos-th match, if in range
+      (let ((point-match (and (> pos 0)
+                              (<=3D pos (length matches))
+                              (nth (1- pos) matches))))
+        (when (and point-match (< (1+ point-match) (length str)))
+          (add-face-text-property
+           (1+ point-match) (+ 2 point-match)
+           'completions-first-difference nil str)))))
+  ;; Highlight matched positions
+  (dolist (pos matches)
+    (add-face-text-property pos (1+ pos)
+                           'completions-common-part
+                           nil str))
+  str)
+
+(defvar completion-flex--pattern-str nil
+  "Pattern string for flex completion scoring.
+This is the concatenated string parts from the PCM pattern,
+used by `completion--flex-score' for Gotoh algorithm matching.")
=20
 (defun completion-pcm--hilit-commonality (pattern completions)
   "Show where and how well PATTERN matches COMPLETIONS.
@@ -4645,22 +4558,37 @@ completion-pcm--hilit-commonality
 Else, if `completion-lazy-hilit' is t, return COMPLETIONS
 unchanged, but setup a suitable `completion-lazy-hilit-fn' (which
 see) for later lazy highlighting."
-  (setq completion-pcm--regexp nil
-        completion-lazy-hilit-fn nil)
+  (setq completion-lazy-hilit-fn nil
+        completion-flex--pattern-str nil)
   (cond
    ((and completions (cl-loop for e in pattern thereis (stringp e)))
     (let* ((segments (completion-pcm--pattern->segments pattern))
-           (re (completion-pcm--segments->regex segments 'group))
-           (point-idx (completion-pcm--segments-point-idx segments)))
-      (setq completion-pcm--regexp re)
+           (point-idx (completion-pcm--segments-point-idx segments))
+           ;; Extract pattern string (concatenate string elements)
+           (pat (mapconcat #'identity
+                           (delq nil (mapcar (lambda (x)
+                                               (if (stringp x) x nil))
+                                             pattern))
+                           "")))
+      (setq completion-flex--pattern-str pat)
       (cond (completion-lazy-hilit
              (setq completion-lazy-hilit-fn
-                   (lambda (str) (completion--hilit-from-re str re point-i=
dx)))
+                   (lambda (str)
+                     (let ((result (completion--flex-score pat str t)))
+                       (when result
+                         (completion--flex-propertize
+                          str (cdr result) point-idx segments)))
+                     str))
              completions)
             (t
              (mapcar
               (lambda (str)
-                (completion--hilit-from-re (copy-sequence str) re point-id=
x))
+                (setq str (copy-sequence str))
+                (let ((result (completion--flex-score pat str t)))
+                  (when result
+                    (completion--flex-propertize
+                     str (cdr result) point-idx segments)))
+                str)
               completions)))))
    (t completions)))
=20
@@ -4959,11 +4887,13 @@ completion-pcm-try-completion
 ;; Mostly derived from the code of `basic' completion.
=20
 (defun completion-substring--all-completions
-    (string table pred point &optional transform-pattern-fn)
+    (string table pred point &optional
+            transform-pattern-fn simple-re)
   "Match the presumed substring STRING to the entries in TABLE.
-Respect PRED and POINT.  The pattern used is a PCM-style
-substring pattern, but it be massaged by TRANSFORM-PATTERN-FN, if
-that is non-nil."
+Respect PRED and POINT.  The pattern used is a PCM-style substring
+pattern, but it be massaged by TRANSFORM-PATTERN-FN, if that is non-nil.
+SIMPLE-RE is means to pass a simpler faster regular expression to
+`completion-pcm--all-completions'"
   (let* ((beforepoint (substring string 0 point))
          (afterpoint (substring string point))
          (bounds (completion-boundaries beforepoint table pred afterpoint))
@@ -4978,7 +4908,13 @@ completion-substring--all-completions
                    (if transform-pattern-fn
                        (funcall transform-pattern-fn pattern)
                      pattern)))
-         (all (completion-pcm--all-completions prefix pattern table pred)))
+         (override-re (and simple-re
+                           (mapconcat #'identity
+                                      (split-string
+                                       (substring string (car bounds)
+                                                  (+ point (cdr bounds))) =
"" t)
+                                      ".*")))
+         (all (completion-pcm--all-completions prefix pattern table pred o=
verride-re)))
     (list all pattern prefix suffix (car bounds))))
=20
 (defun completion-substring-try-completion (string table pred point)
@@ -5009,7 +4945,7 @@ completion-flex-nospace
=20
 (defun completion--flex-adjust-metadata (metadata)
   "If `flex' is actually doing filtering, adjust sorting."
-  (let ((flex-is-filtering-p completion-pcm--regexp)
+  (let ((flex-is-filtering-p completion-flex--pattern-str)
         (existing-dsf
          (completion-metadata-get metadata 'display-sort-function))
         (existing-csf
@@ -5021,11 +4957,11 @@ completion--flex-adjust-metadata
                              (mapcar
                               (lambda (str)
                                 (cons
-                                 (- (completion--flex-score
-                                     (or (get-text-property
-                                          0 'completion--unquoted str)
-                                         str)
-                                     completion-pcm--regexp))
+                                 (car (completion--flex-score
+                                       completion-flex--pattern-str
+                                       (or (get-text-property
+                                            0 'completion--unquoted str)
+                                           str)))
                                  str))
                               (if existing-sort-fn
                                   (funcall existing-sort-fn completions)
@@ -5067,7 +5003,8 @@ completion-flex-try-completion
     (pcase-let ((`(,all ,pattern ,prefix ,suffix ,_carbounds)
                  (completion-substring--all-completions
                   string table pred point
-                  #'completion-flex--make-flex-pattern)))
+                  #'completion-flex--make-flex-pattern
+                  t)))
       (if minibuffer-completing-file-name
           (setq all (completion-pcm--filename-try-filter all)))
       ;; Try some "merging", meaning add as much as possible to the
@@ -5084,7 +5021,8 @@ completion-flex-all-completions
     (pcase-let ((`(,all ,pattern ,prefix ,_suffix ,_carbounds)
                  (completion-substring--all-completions
                   string table pred point
-                  #'completion-flex--make-flex-pattern)))
+                  #'completion-flex--make-flex-pattern
+                  t)))
       (when all
         (nconc (completion-pcm--hilit-commonality pattern all)
                (length prefix))))))
diff --git a/src/minibuf.c b/src/minibuf.c
index 5dc2b230883..f7dffc24b94 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -20,6 +20,7 @@ Copyright (C) 1985-1986, 1993-2026 Free Software Foundati=
on, Inc.
=20
 #include <config.h>
 #include <errno.h>
+#include <math.h>
=20
 #include <binary-io.h>
=20
@@ -2279,6 +2280,201 @@ init_minibuf_once_for_pdumper (void)
   last_minibuf_string =3D Qnil;
 }
=20
+/* FLEX/GOTOH algorithm for the 'flex' completion-style.  Adapted from
+   GOTOH, Osamu. An improved algorithm for matching biological
+   sequences. Journal of molecular biology, 1982, 162.3: 705-708.
+
+   This algorithm matches patterns to candidate strings, or needles to
+   haystacks.  It works with cost matrices: imagine rows of these
+   matrices as pattern characters, and columns as the candidate string
+   characters.  There is a -1 row, and a -1 column.  The values there
+   hold real costs used for situations "before the first ever" match of
+   a pattern character to a string character.
+
+   M and D are cost matrices.  At the end of the algorithm, M will have
+   non-infinite values only for the spots where a pattern character
+   matches a string character.  So a non-infinite M[i,j] means the i-th
+   character of the pattern matches the j-th character of the string.
+   The value stored is the lowest possible cost the algorithm had to
+   "pay" to be able to make that match there, given everything that may
+   have happened before/to the left.  An infinite value simply means no
+   match at this pattern/string position.  Note that both row and column
+   of M may have more than one match at multiple indices.  But this
+   particular implementation of the algorithm assumes they have at least
+   one match.
+
+   D (originally stands for 'Deletion' in the Gotoh paper) has "running
+   costs".  Each value D[i,j] represents what the algorithm has to pay
+   to make or extend a gap when a match is found at i+1, j+1.  By that
+   time, that cost may or may not be lower than continuing from a match
+   that had also been found at i,j.  We always pick the lowest cost, and
+   by the time we reach the final column, we know we have picked the
+   cheapest possible path choosing when to gap, and when to follow up.
+
+   Along the way, we construct P, a matrix used just for backtracking,
+   to reconstruct that path.  Maybe P isn't needed, and all the
+   information can be cleverly derived from the final state of M and D.
+   But I couldn't make it work.  */
+DEFUN ("completion--flex-score-gotoh", Fcompletion__flex_score_gotoh,
+       Scompletion__flex_score_gotoh, 2, 2, 0,
+       doc: /* Compute flex score of STR matching PAT using Gotoh
+algorithm.  Return nil if no match found, else return (COST . MATCHES)
+where COST is a fixnum (lower is better) and MATCHES is a list of match
+positions in STR.  */)
+  (Lisp_Object pat, Lisp_Object str)
+{
+  /* Pre-allocated matrices for flex completion scoring.  */
+#define FLEX_MAX_STR_SIZE 512
+#define FLEX_MAX_PAT_SIZE 128
+#define FLEX_MAX_MATRIX_SIZE FLEX_MAX_PAT_SIZE * FLEX_MAX_STR_SIZE
+  /* Macro for 2D indexing into "flat" arrays.  */
+#define MAT(matrix, i, j) ((matrix)[((i) + 1) * width + ((j) + 1)])
+
+  CHECK_STRING (pat);
+  CHECK_STRING (str);
+
+  size_t patlen =3D SCHARS (pat);
+  size_t strlen =3D SCHARS (str);
+  size_t width =3D strlen + 1;
+  size_t size =3D (patlen + 1) * width;
+
+  /* Bail if strings are empty or matrix too large.  */
+  if (patlen =3D=3D 0 || strlen =3D=3D 0)
+    return Qnil;
+
+  if (size > FLEX_MAX_MATRIX_SIZE)
+    return Qnil;
+
+  /* Cost constants (lower is better).  Maybe these could be
+     defcustom's?*/
+  const int gap_open_cost =3D 10;
+  const int gap_extend_cost =3D 1;
+  const int pos_inf =3D INT_MAX / 2;
+
+  static int M[FLEX_MAX_MATRIX_SIZE];
+  static int D[FLEX_MAX_MATRIX_SIZE];
+  static size_t P[FLEX_MAX_MATRIX_SIZE];
+
+  /* Initialize costs.  Fill both matrices with positive infinity.  */
+  for (int j =3D 0; j < size; j++) M[j] =3D pos_inf;
+  for (int j =3D 0; j < size; j++) D[j] =3D pos_inf;
+  /* Except for D[0,0], which is 0, for prioritizing matches at the
+     beginning.  Remaining elements on the first row are gap_open_cost/2
+     to represent cheaper leading gaps. */
+  for (int j =3D 0; j < width; j++) D[j] =3D gap_open_cost/2;
+  D[0] =3D 0;
+
+  /* Index of last match before gap started, as computed in the previous
+     row.  Used to build P.  */
+  int prev_gap_origin =3D -1;
+
+  /* Poor man's iterator type. */
+  typedef struct iter { int x; ptrdiff_t c; ptrdiff_t b; } iter_t;
+
+  /* Info about first match computed in the previous row. */
+  iter_t prev_match =3D {0,0,0};
+  /* Forward pass.  */
+  for (iter_t i =3D {0,0,0}; i.x < patlen; i.x++)
+    {
+      int pat_char =3D fetch_string_char_advance(pat, &i.c, &i.b);
+      int gap_origin =3D -1;
+      bool match_seen =3D false;
+
+      for (iter_t j =3D prev_match; j.x < strlen; j.x++)
+	{
+	  iter_t jcopy =3D j; /* else advance function destroys it... */
+	  int str_char
+	    =3D fetch_string_char_advance (str, &j.c, &j.b);
+
+	  /* Check if characters match (case-insensitive if needed).  */
+	  bool cmatch;
+	  if (completion_ignore_case)
+	    cmatch =3D (downcase (pat_char) =3D=3D downcase (str_char));
+	  else
+	    cmatch =3D (pat_char =3D=3D str_char);
+
+	  /* Compute match cost M[i][j], i.e. replace its infinite
+	     value with something finite. */
+	  if (cmatch)
+	    {
+	      if (!match_seen)
+		{
+		  match_seen =3D true;
+		  prev_match =3D jcopy;
+		}
+	      int pmatch_cost =3D MAT (M, i.x - 1, j.x - 1);
+	      int pgap_cost =3D MAT (D, i.x - 1, j.x - 1);
+
+	      if (pmatch_cost <=3D pgap_cost)
+		{
+		  /* Not only did the previous char also match (else
+		     pmatch_cost would have been infinite) but following
+		     it up with this match is best overall.  */
+		  MAT (M, i.x, j.x) =3D pmatch_cost;
+		  MAT (P, i.x, j.x) =3D j.x - 1;
+		}
+	      else
+		{
+		  /* Gapping is best, regardless of whether the previous
+		     char also matched.  That is, it's better to arrive at
+		     this match from a gap.  */
+		  MAT (M, i.x, j.x) =3D pgap_cost;
+		  MAT (P, i.x, j.x) =3D prev_gap_origin;
+		}
+	    }
+
+	  /* Regardless of a match here, compute D[i,j], the best
+	     accumulated gapping cost at this point, considering whether
+	     it's more advantageous to open from a previous match on
+	     this row (a cost which may well be infinite if no such
+	     match ever existed) or extend a gap started sometime
+	     before.  The next iteration will take this into account,
+	     and so will the next row when analyzing a possible match
+	     for the j+1-th string character.  */
+	  int open_cost =3D MAT (M, i.x, j.x - 1) + gap_open_cost;
+	  int extend_cost =3D MAT (D, i.x, j.x - 1) + gap_extend_cost;
+
+	  if (open_cost < extend_cost)
+	    {
+	      MAT (D, i.x, j.x) =3D open_cost;
+	      gap_origin =3D j.x - 1; /* New gap. */
+	    }
+	  else
+	    MAT (D, i.x, j.x) =3D extend_cost; /* Extend gap.  */
+	}
+      prev_gap_origin =3D gap_origin;
+    }
+
+  /* Find best (lowest) cost in last row.  */
+  int best_cost =3D pos_inf;
+  int lastcol =3D -1;
+
+  for (int j =3D 0; j < strlen; j++)
+    {
+      int cost =3D MAT (M, patlen - 1, j);
+      if (cost < best_cost)
+        {
+          best_cost =3D cost;
+          lastcol =3D j;
+        }
+    }
+
+  if (lastcol < 0 || best_cost >=3D pos_inf)
+    return Qnil;
+
+  /* Build match positions list by tracing back through P matrix.  */
+  Lisp_Object matches =3D Qnil;
+  for (int i =3D patlen - 1, l =3D lastcol; i >=3D 0 && l >=3D 0; i--)
+    {
+      matches =3D Fcons (make_fixnum (l), matches);
+      l =3D MAT (P, i, l);
+    }
+
+  return Fcons (make_fixnum (best_cost), matches);
+#undef MAT
+
+}
+
 void
 syms_of_minibuf (void)
 {
@@ -2541,6 +2737,7 @@ syms_of_minibuf (void)
   defsubr (&Stest_completion);
   defsubr (&Sassoc_string);
   defsubr (&Scompleting_read);
+  defsubr (&Scompletion__flex_score_gotoh);
   DEFSYM (Qminibuffer_quit_recursive_edit, "minibuffer-quit-recursive-edit=
");
   DEFSYM (Qinternal_complete_buffer, "internal-complete-buffer");
   DEFSYM (Qcompleting_read_function, "completing-read-function");
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 79ffb1d3fc7..02df7661c75 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -205,11 +205,6 @@ completion-all-sorted-completions
                   '("some/alpha" "base/epsilon" "base/delta"))
                  `("epsilon" "delta" "beta" "alpha" "gamma"  . 5))))
=20
-(defun completion--pcm-score (comp)
-  "Get `completion-score' from COMP."
-  ;; FIXME, uses minibuffer.el implementation details
-  (completion--flex-score comp completion-pcm--regexp))
-
 (defun completion--pcm-first-difference-pos (comp)
   "Get `completions-first-difference' from COMP."
   (cl-loop for pos =3D (next-single-property-change 0 'face comp)
@@ -244,20 +239,11 @@ completion-pcm-test-2
            "barfoobar")))
=20
 (ert-deftest completion-pcm-test-3 ()
-  ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-pcm-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion-pcm-all-completions
+                "R" '("R" "hello") nil 1))))
=20
 (ert-deftest completion-pcm-test-4 ()
-  ;; One fourth of a match and no match due to point being at the end
-  (should (eql
-           (completion--pcm-score
-            (car (completion-pcm-all-completions
-                  "RO" '("RaOb") nil 1)))
-           (/ 1.0 4.0)))
+  ;; No match due to point being at the end
   (should (null
            (completion-pcm-all-completions
             "RO" '("RaOb") nil 2))))
@@ -420,24 +406,14 @@ completion-pcm-bug4219
            "a")))
=20
 (ert-deftest completion-substring-test-1 ()
-  ;; One third of a match!
   (should (equal
            (car (completion-substring-all-completions
                  "foo" '("hello" "world" "barfoobar") nil 3))
-           "barfoobar"))
-  (should (eql
-           (completion--pcm-score
-            (car (completion-substring-all-completions
-                  "foo" '("hello" "world" "barfoobar") nil 3)))
-           (/ 1.0 3.0))))
+           "barfoobar")))
=20
 (ert-deftest completion-substring-test-2 ()
-  ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-substring-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion-substring-all-completions
+                "R" '("R" "hello") nil 1))))
=20
 (ert-deftest completion-substring-test-3 ()
   ;; Substring match
@@ -495,39 +471,70 @@ completion-substring-test-5
            (completion-substring-try-completion "b" '("ab" "ab") nil 0)
            '("ab" . 2))))
=20
+(defun completion--sorted-flex-completions (pat list &optional point)
+  "Flex test helper"
+  (let ((all (completion-flex-all-completions pat list nil point)))
+    (setcdr (last all) nil)
+    (sort all
+          (lambda (a b)
+            (< (car (completion--flex-score pat a))
+               (car (completion--flex-score pat b)))))))
+
 (ert-deftest completion-flex-test-1 ()
-  ;; Fuzzy match
   (should (equal
            (car (completion-flex-all-completions
                  "foo" '("hello" "world" "fabrobazo") nil 3))
            "fabrobazo")))
=20
 (ert-deftest completion-flex-test-2 ()
-  ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-flex-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion--sorted-flex-completions
+                "R" '("R" "hello") 1))))
=20
 (ert-deftest completion-flex-test-3 ()
-  ;; Another fuzzy match, but more of a "substring" one
   (should (equal
-           (car (completion-flex-all-completions
-                 "custgroup" '("customize-group-other-window") nil 4))
+           (car (completion--sorted-flex-completions
+                 "custgroup" '("customize-group-other-window") 4))
            "customize-group-other-window"))
   ;; `completions-first-difference' should be at the right place
   (should (equal
            (completion--pcm-first-difference-pos
-            (car (completion-flex-all-completions
-                  "custgroup" '("customize-group-other-window") nil 4)))
+            (car (completion--sorted-flex-completions
+                  "custgroup" '("customize-group-other-window") 4)))
            4))
   (should (equal
            (completion--pcm-first-difference-pos
-            (car (completion-flex-all-completions
-                  "custgroup" '("customize-group-other-window") nil 9)))
+            (car (completion--sorted-flex-completions
+                  "custgroup" '("customize-group-other-window") 9)))
            15)))
=20
+(ert-deftest completion-flex-test-non-ascii ()
+  "Test flex completion with variable-width UTF-8 characters."
+  ;; Uses Japanese Kanji to test multi-byte character handling.
+
+  ;; =E6=97=A5=E6=9C=AC =3D "nihon" (Japan), =E6=9D=B1=E4=BA=AC =3D "t=C5=
=8Dky=C5=8D" (Tokyo)
+  (should (equal
+           (car (completion--sorted-flex-completions
+                 "=E6=97=A5=E6=9C=AC" '("=E6=97=A5=E6=9C=AC=E8=AA=9E" "=E6=
=97=A5=E6=9C=AC" "=E4=B8=AD=E5=9B=BD") 2))
+           "=E6=97=A5=E6=9C=AC"))
+
+  ;; =E5=9B=B3=E6=9B=B8=E9=A4=A8 =3D "toshokan" (library)
+  (should (equal
+           (car (completion--sorted-flex-completions
+                 "tsk" '("=E5=9B=B3=E6=9B=B8=E9=A4=A8-toshokan" "task" "de=
sk") 3))
+           "task"))
+
+  ;; Mixed pattern (Kanji + ASCII) matching mixed string
+  ;; =E5=AD=A6=E6=A0=A1 =3D "gakk=C5=8D" (school)
+  (should (equal
+           (car (completion--sorted-flex-completions
+                 "=E5=AD=A6s" '("=E5=AD=A6=E6=A0=A1-school" "school" "=E5=
=AD=A6=E7=94=9F") 2))
+           "=E5=AD=A6=E6=A0=A1-school"))
+
+  ;; Pattern "=E6=9D=B1" should match "=E6=9D=B1=E4=BA=AC" better than "=
=E9=96=A2=E6=9D=B1"
+  (let ((results (completion--sorted-flex-completions
+                  "=E6=9D=B1" '("=E6=9D=B1=E4=BA=AC" "=E9=96=A2=E6=9D=B1")=
 1)))
+    (should (equal (car results) "=E6=9D=B1=E4=BA=AC"))))
+
 
 (defmacro with-minibuffer-setup (completing-read &rest body)
   (declare (indent 1) (debug t))





Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 20:44:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 15:44:29 2026
Received: from localhost ([127.0.0.1]:35676 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnjjh-0000ek-5b
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 15:44:29 -0500
Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a]:48253)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vnjje-0000eb-7m
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 15:44:27 -0500
Received: by mail-wm1-x32a.google.com with SMTP id
 5b1f17b1804b1-4805ef35864so1583025e9.0
 for <80323 <at> debbugs.gnu.org>; Wed, 04 Feb 2026 12:44:26 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770237865; x=1770842665; darn=debbugs.gnu.org;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:from:to:cc:subject:date
 :message-id:reply-to;
 bh=6lAmBtpiatm9ADH51xVbxWiAchWXfdeHfPt320Tc0qM=;
 b=gIGJN0qGjEjBuoNZwlMVInu0D545U96Wluqss8GmO1apAdWgJHzEXPTlChcdjXDrPF
 z6GQrUboPDjATHtN5MJEAdhqvDR8cLYb/2TisWa4WNtm3Nt1FlOYQ7CKZrAZQzmYtpDA
 rBPZRHS3ISHqTMXPv+B4xyej2chHjLoHpHf7SeItHxau6713eBrWB0e/61k07dFhZt/R
 8Psq4vMcelygyLX2GMhn7erpisr4dzAZxIwcVyRjyskKWeXT1XonbMdRNeQpi0NDywjf
 Z5sTEIZTSK1p1fb9laPztjsOkc+JTrYHJMAtQYp57EFgitXilFDkDhpccewQAQnlQpCO
 ydMg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770237865; x=1770842665;
 h=content-transfer-encoding:mime-version:user-agent:message-id:date
 :references:in-reply-to:subject:cc:to:from:x-gm-gg
 :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to;
 bh=6lAmBtpiatm9ADH51xVbxWiAchWXfdeHfPt320Tc0qM=;
 b=TYzS+UioCGXFDDs8wHC6GiitaAJe22RlQGyne5Yo1o4QavUf84sN87dq63LyU/5/9b
 4x742sYazaOC0rOp6Vm2284rE/t+JOMkpw5+cldJFNPxje39HQj5TIWmlJf4x14nWFBe
 S1gf4/esH8vjKcHJFkmLJBPgF8142VPXmppsTrtTSwq/zQaJ1wGSkdI9tmBfhRqS1l7G
 cmbvMvoJDE56f8ssB/4bL6tE0Mxq/vQAodCRtMbQVR9D/ygeWRjV8ouyxGYWrtLohjxC
 jjpab47lCFOVpjN9V3IzeDnLUBX93XHMuEWTdhARGHYRfCznH1WEM+SV9T83GFVW4JJ9
 OeiQ==
X-Forwarded-Encrypted: i=1;
 AJvYcCUYBxLdbm4G6CvP13JuzE4hAlvFcWk/LGgYZNzZwsLE1w9QuPF+nJSXhv+83R/TP3YLc6K+jQ==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YwcA4liSZoP+7YIAUHJnL280zq3bDbK8DG8KgUxkJSAmT/BZMOQ
 wE89WpXsODPY7k2E+dxa9o6LlCmrrEKSlMivAq+1+Zh+VGmeJU+vkRze
X-Gm-Gg: AZuq6aIEoB8m8SGhqoomebfBRnP+3n1Wua+n9JsAZO47eBXyyxHaKoDVWAgP+jbMG4C
 pZ3rId9HbOiqS38iluFWEuxlWCzyyI9B+dPGZZl1u49uvu2K9lbyASwq047MHf9ZTfUQcUBPSaJ
 EK/zkzsgszKyYtgui6N1j+7MqfbA6wbVXMkMg9l2rp+qomP1AghbPywc7sRnqVhPhTgqL2vcUdV
 3uu9gaH5Lm7eKkLk8/gKC1HUwf2yZ+Q0ipIeMsyGWgWiBkcJEH4kNB5SXiVBXzwwx2L3BvOJWTM
 Gt/OkRi1dfnzXMnrftHAY6ZtULBDSJCyRTNVmFtE2mx/td0oGNCDsYLBfDlFg3OpOx2sfYU9Ud4
 ubV5EJvVMBdJ1UfULXh4agSWdJC2wF9zThk2WQmKLJooWDF7+A7aETz7O/aX7bqCniWEwklRRpo
 /sDncxWNebHDLDE5+QGrILXj6onQ==
X-Received: by 2002:a05:6000:288a:b0:430:f7dc:7e8e with SMTP id
 ffacd0b85a97d-4361805271fmr5357384f8f.34.1770237864753; 
 Wed, 04 Feb 2026 12:44:24 -0800 (PST)
Received: from krug (87-196-74-61.net.novis.pt. [87.196.74.61])
 by smtp.gmail.com with ESMTPSA id
 ffacd0b85a97d-43618064844sm8636234f8f.42.2026.02.04.12.44.23
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Wed, 04 Feb 2026 12:44:24 -0800 (PST)
From: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
To: Eli Zaretskii <eliz@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
In-Reply-To: <86y0l8xyor.fsf@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
 <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
 <jwv4inwcxpt.fsf-monnier+emacs@HIDDEN>
 <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
 <86y0l8xyor.fsf@HIDDEN>
Date: Wed, 04 Feb 2026 20:44:22 +0000
Message-ID: <87qzr06xy1.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 4.6 (++++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Eli Zaretskii writes: >> Cc: 80323 <at> debbugs.gnu.org, Sean Whitton
    >> From: João Távora >> Date: Wed, 4 Feb 2026 15:58:24 +0000 >> >> I don't
    know if it does for sure, but the algo needs to compare character s, and
   cur [...] 
 
 Content analysis details:   (4.6 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  3.6 RCVD_IN_SBL_CSS        RBL: Received via a relay in Spamhaus SBL-CSS
                             [87.196.74.61 listed in zen.spamhaus.org]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
                             provider (joaotavora[at]gmail.com)
  1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
                             headers
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
                              no trust
                             [2a00:1450:4864:20:0:0:0:32a listed in]
                             [list.dnswl.org]
X-Debbugs-Envelope-To: 80323
Cc: spwhitton@HIDDEN, monnier@HIDDEN, 80323 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 3.6 (+++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 
 Content preview:  Eli Zaretskii writes: >> Cc: 80323 <at> debbugs.gnu.org, Sean Whitton
    >> From: João Távora >> Date: Wed, 4 Feb 2026 15:58:24 +0000 >> >> I don't
    know if it does for sure, but the algo needs to compare character s, and
   cur [...] 
 
 Content analysis details:   (3.6 points, 10.0 required)
 
  pts rule name              description
 ---- ---------------------- --------------------------------------------------
  3.6 RCVD_IN_SBL_CSS        RBL: Received via a relay in Spamhaus SBL-CSS
                             [87.196.74.61 listed in zen.spamhaus.org]
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
                              no trust
                             [2a00:1450:4864:20:0:0:0:32a listed in]
                             [list.dnswl.org]
  0.0 SPF_HELO_NONE          SPF: HELO does not publish an SPF Record
 -0.0 SPF_PASS               SPF: sender matches SPF record
  0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
                             provider (joaotavora[at]gmail.com)
  1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
                             headers
 -1.0 MAILING_LIST_MULTI     Multiple indicators imply a widely-seen list
                             manager

Eli Zaretskii <eliz@HIDDEN> writes:

>> Cc: 80323 <at> debbugs.gnu.org, Sean Whitton <spwhitton@HIDDEN>
>> From: Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN>
>> Date: Wed, 4 Feb 2026 15:58:24 +0000
>>=20
>> I don't know if it does for sure, but the algo needs to compare characte=
r s, and currently addresses memory
>> like bytes naively with [] as if I were using C++ and that did the right=
 thing. It does mostly and the patch
>> passes all the current tests, but then all these tests are for ASCII. Bu=
t in C the [] is very dumb and so some
>> macro salad is probably required.
>
> I think it's a terminology issue.  AFAIU, by "wide characters" you
> mean characters whose internal representation in a string takes more
> than 1 byte.  For that, string_char_and_length is the function to use:
> it returns to you the Unicode codepoint of a character and the number
> of bytes its multibyte sequence takes (which you can then use to
> advance your 'char *' pointer to the beginning of the next character's
> multibyte sequence).  Or you can use fetch_string_char_advance, which
> will do all that for you in one go.

Thanks.  That's the info I was looking for.

Jo=C3=A3o

PS: BTW, just to correct myself, using [] probably be a bad idea for
variable charsize strings in C++ too, iterators would be preferable,
which I understand is what I'm going to do here.






Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 16:29:13 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 11:29:12 2026
Received: from localhost ([127.0.0.1]:33887 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnfke-00058Z-HO
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 11:29:12 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:37084)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vnfkb-00058D-Ko
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 11:29:10 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1vnfkM-0006G9-MB; Wed, 04 Feb 2026 11:29:03 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=BXxntAMdmlm1QHDPR9NoFx5XTnqs/0hujnTc9M24oyU=; b=k7JQDUO5l/utxrq/pfs0
 zksj3jbx4AoJ08r6taIyuqlCnPH1qJP+c59ppcv1BpS3no62uc8ypoqDDCSbKUBHA8/TdvOSkMtl2
 tLpS8OEo1ZwVtEsb5GMaQnG2K+TALt6Wr0531AAWdVSGVVdfnvdUSEqY6szLEu7saKNjJ7b73ioYM
 YguR2+kIsMlkdBaxjeH+KOI5S9uGGB+FbKoG5NLeYJ2iuNG7CPO7O83qRE21AhVREJgjfGUzQfptN
 TQAGfnHh3CrqvM8ELIfoU+jDd49oWGA/UJEReL/8jvtEC3lgWKpoYwQCkgPYFWe1QQ9v+XMJoGGFf
 deXkRzto1x+feA==;
Date: Wed, 04 Feb 2026 18:26:12 +0200
Message-Id: <86y0l8xyor.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
In-Reply-To: <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
 (message from =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= on Wed, 4 Feb 2026 15:58:24
 +0000)
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
 <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
 <jwv4inwcxpt.fsf-monnier+emacs@HIDDEN>
 <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80323
Cc: spwhitton@HIDDEN, monnier@HIDDEN, 80323 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Cc: 80323 <at> debbugs.gnu.org, Sean Whitton <spwhitton@HIDDEN>
> From: João Távora <joaotavora@HIDDEN>
> Date: Wed, 4 Feb 2026 15:58:24 +0000
> 
> I don't know if it does for sure, but the algo needs to compare character s, and currently addresses memory
> like bytes naively with [] as if I were using C++ and that did the right thing. It does mostly and the patch
> passes all the current tests, but then all these tests are for ASCII. But in C the [] is very dumb and so some
> macro salad is probably required.

I think it's a terminology issue.  AFAIU, by "wide characters" you
mean characters whose internal representation in a string takes more
than 1 byte.  For that, string_char_and_length is the function to use:
it returns to you the Unicode codepoint of a character and the number
of bytes its multibyte sequence takes (which you can then use to
advance your 'char *' pointer to the beginning of the next character's
multibyte sequence).  Or you can use fetch_string_char_advance, which
will do all that for you in one go.

Stefan, AFAIU, means "width" as in "character width on display".




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 16:28:52 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 11:28:52 2026
Received: from localhost ([127.0.0.1]:33881 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnfkK-00057S-1Q
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 11:28:52 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10]:41448)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <eliz@HIDDEN>) id 1vnfkH-00057B-Qh
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 11:28:50 -0500
Received: from fencepost.gnu.org ([2001:470:142:3::e])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <eliz@HIDDEN>)
 id 1vnfkB-0006EN-Kj; Wed, 04 Feb 2026 11:28:44 -0500
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org;
 s=fencepost-gnu-org; h=MIME-version:References:Subject:In-Reply-To:To:From:
 Date; bh=BXxntAMdmlm1QHDPR9NoFx5XTnqs/0hujnTc9M24oyU=; b=oweVJjbTCnLzdEbI+1u5
 nimev9UJ5HwvrFu6zmHjEO4h73rAr7c/7bT/qA2qRGyzo+mfVuOorBJpdFj8vBPCWWpJDRUjsZwgH
 8bdiQjiroYNqvmZPVtbKz7pE5UxUUh23kcG32/mm2zdZor+YRybwXq+/Zfm1g/AWSoi6ylKJC62Fl
 bI+QKbFKhhw0CalNln18JDXMiKOkgiZZsDmKfWwQ70MXWUcubocmArLCBHanISYYY8iCln2A3+cfS
 FTPuIQh7sQbpSEOUri3pY9QbaaU4Odhu9oZqXHFIGeom8Wf/5BYY68nhkdwLhyUGpb0SwAqY5fVZy
 b1dHWMRaLzsSbQ==;
Date: Wed, 04 Feb 2026 18:20:11 +0200
Message-Id: <86zf5oxyys.fsf@HIDDEN>
From: Eli Zaretskii <eliz@HIDDEN>
To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
In-Reply-To: <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
 (message from =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= on Wed, 4 Feb 2026 15:58:24
 +0000)
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
 <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
 <jwv4inwcxpt.fsf-monnier+emacs@HIDDEN>
 <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
MIME-version: 1.0
Content-type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 80323
Cc: spwhitton@HIDDEN, monnier@HIDDEN, 80323 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

> Cc: 80323 <at> debbugs.gnu.org, Sean Whitton <spwhitton@HIDDEN>
> From: João Távora <joaotavora@HIDDEN>
> Date: Wed, 4 Feb 2026 15:58:24 +0000
> 
> I don't know if it does for sure, but the algo needs to compare character s, and currently addresses memory
> like bytes naively with [] as if I were using C++ and that did the right thing. It does mostly and the patch
> passes all the current tests, but then all these tests are for ASCII. But in C the [] is very dumb and so some
> macro salad is probably required.

I think it's a terminology issue.  AFAIU, by "wide characters" you
mean characters whose internal representation in a string takes more
than 1 byte.  For that, string_char_and_length is the function to use:
it returns to you the Unicode codepoint of a character and the number
of bytes its multibyte sequence takes (which you can then use to
advance your 'char *' pointer to the beginning of the next character's
multibyte sequence).  Or you can use fetch_string_char_advance, which
will do all that for you in one go.

Stefan, AFAIU, means "width" as in "character width on display".




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 15:58:39 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 10:58:39 2026
Received: from localhost ([127.0.0.1]:33663 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnfH4-0003bj-Ny
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 10:58:39 -0500
Received: from mail-oi1-x231.google.com ([2607:f8b0:4864:20::231]:51291)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vnfH1-0003ba-M8
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 10:58:36 -0500
Received: by mail-oi1-x231.google.com with SMTP id
 5614622812f47-45c962424daso2813409b6e.2
 for <80323 <at> debbugs.gnu.org>; Wed, 04 Feb 2026 07:58:35 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770220715; cv=none;
 d=google.com; s=arc-20240605;
 b=EadOd6zEbx8bHBGGqGxNpHPuPERgq+1LBOAVmelrZIQ+DkLZJC95qJHxIWQ5APjV0n
 CChHyOPvc+ryfFqWQPNqp0Ql1cRg97vRj9wo2imTyhshRYsLbaj/CP20HOhAlv9wh/GX
 SpsTihY7e6EOtxGyoDSmLYJrHCUoMiEywYa+Ea4DDmDXdo3wCWot70NBvfhvpnU23i65
 XoSZBWTDPUhK2AWwFJOh4WhTGkqqq3hccqv9UvzcGLKI97xQGGqhmq/cAMH+DWAhoZyn
 7MdlVvYXZyRYKeRYUSa1IsolDE0DoxnV4/lBl6V7vzYMACk4Xv5b0/bFZCBGyt9nrTxl
 MO1A==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:dkim-signature;
 bh=v3AkcNX6ddqeXvjwFr8SlMGwU5RbuYGlk6js9/QayKM=;
 fh=fattA/Lbu7M/Ba5BzE8F9o64SJlL0j/WyN012wjpVuo=;
 b=bRokyxvSUn6FDaIPQh1Yg/u9/lodarCrbUVZlSv9O1IQ+WL0tghNyVZe3n6m4elXQU
 n4X6clQtMTD4MrIxNlEi3X071wnSFOrlxBqPFeGVSwgYnGRbeLAg5a5vUurcXCUcLhSA
 M1cgQHN89TsRrKPKBZVDpdYH4WemZcp0bxF4mMHsPLauSOyG1kTPKILYGGUL8JyC21Ux
 mFivE85r9ElBTG91X+oWWakqsFMnnkfapoWxFMqQ3a9a6Bw/KZvQeLb8+uyO5XI87bj4
 BGdPGdoOC5hfd6Ai/tREql7LRbWMNxmSjmxkK70VpCjezDpYAsi/MmQ8+/kbmEv71qpx
 k/EA==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770220715; x=1770825515; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=v3AkcNX6ddqeXvjwFr8SlMGwU5RbuYGlk6js9/QayKM=;
 b=WWggO9IZJLy1L5v4/BWYhGEGcv0Y6nRU+t6VAC42iUcVL9ptl5MpdYbqMrgq+D0k03
 6tXishbOA2M5XEhL19X9XGdGRx4dN82NsWJk5vrUuLi0AARCn5yqlMAw8S8XVe5nazAC
 x03DmIDMM1m5EOD+grbx39ikGugRlPu767QXq/PSQ+Jage23ATpmFJke4VFObsu7qIdY
 w3XmKK3Jn8UzpDNjBrbc8L4J0K1SoGtTPHe+UcovZfIaIC7r0d8yi36251Hr8Rljmfdh
 yT2pRFpoxsC6w5RMvAtbWmArY0bdrUhtZ12sYw0U12M1CMH7m2tsZd4nN1l1pbdRQB56
 Dsjg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770220715; x=1770825515;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=v3AkcNX6ddqeXvjwFr8SlMGwU5RbuYGlk6js9/QayKM=;
 b=YjYNz9N5dX8YsKGa1EmdD0VcpPl5lwsp/rrQxnuUD1cxs6+8qmMpw6xetv21Qd/G1t
 B4MImbyGrnfWYr94eaPdm+DAL0F1VQaVxdIQdq15e/8wz3QKWeRE90g9cvTtCB9hCNgC
 V8UvjjHzp8GcPFcSZa10hrNrEe3KUVHt4VwvOqGmmloamK+/G+DjClAGu0RVAAcrAetF
 k4VAt6paDgekkJ4ucAp3FSzCzC00dpCsHw35JS/lGq5g8vyBi9Ln3sRfF8rKa8j9FIom
 tkFnlJmUoyoztXy3121z7LB40nK9MZLkNeLPoxqT1QE305PRscwESf742cdAclUowJ8c
 h6Gw==
X-Forwarded-Encrypted: i=1;
 AJvYcCV0Pe7GbMFtW3CxyWJ/PbMf8ibmWyqvvCuFVSMIp0RBFyfgTuSgpFdrrbcL1IoB7tfJymOaVA==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YzEw9PH46ixBZWIaTCBFydskV1eB0ac7HdNWtXKHpB50TaKemb/
 46DFIxrb3499yXYp5Dlry53XsWa/vVZJ0HawdS3S8DgEmF+Rd9oMyW6SGhse764QsXMyEhNPvwh
 VrFviDcCffa1LFhY+GW5GPAJHYg+koHzGyw==
X-Gm-Gg: AZuq6aJoWAyEeIlskr+f9Uvtody6MpfjxCpYIlcu8SsDj/KqrkZmuk0XXjXIiGS+edc
 4Y1QODtunUyCsLGY/7dKe9k5npqTNA3Pffq+F5J553+rMmihW6hv6UWxHMQC2jlTT7TdeBUx3N1
 ZBWpskLmlkf4trGtApVw1PPY8P7xCi+6lb/l2QtlrbCVFB9W2PVEk7UYazyC38IVg/KZHfMVv/M
 R5qm3D4J+EevZ7Cby9LvH1sYIZSDgNNyDXVmFVqYizPKOr7JRLkE6QO4z61LCVncR3vF/I=
X-Received: by 2002:a05:6808:c2a2:b0:450:c602:751d with SMTP id
 5614622812f47-462d58e42c7mr1927906b6e.21.1770220714591; Wed, 04 Feb 2026
 07:58:34 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
 <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
 <jwv4inwcxpt.fsf-monnier+emacs@HIDDEN>
In-Reply-To: <jwv4inwcxpt.fsf-monnier+emacs@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Wed, 4 Feb 2026 15:58:24 +0000
X-Gm-Features: AZwV_Qhb7ZP_EZISe8OmLJXUJJEt14wRmTGnzZB2CPMFjwR3vA0rCaQlNx9SgXs
Message-ID: <CALDnm50HQJnS7i89-x0UcZ2GZ8raWE6mL_a-_drQV06u4Gbg7A@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: Stefan Monnier <monnier@HIDDEN>
Content-Type: multipart/alternative; boundary="000000000000de089f064a01a09b"
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: 80323 <at> debbugs.gnu.org, Sean Whitton <spwhitton@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

--000000000000de089f064a01a09b
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

I don't know if it does for sure, but the algo needs to compare character
s, and currently addresses memory like bytes naively with [] as if I were
using C++ and that did the right thing. It does mostly and the patch passes
all the current tests, but then all these tests are for ASCII. But in C the
[] is very dumb and so some macro salad is probably required.

On Wed, Feb 4, 2026, 15:53 Stefan Monnier <monnier@HIDDEN> wrote:

> > Seems like my patch is too naive regarding wide chars. Gotta fix that.
> > What's the recommended way to iterate such strings in C code?
>
> I'm missing something: why does the width of characters matter?
>
>
> =3D=3D=3D Stefan
>
> Jo=C3=A3o T=C3=A1vora

--000000000000de089f064a01a09b
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div><div>I don&#39;t know if it does for sure, but the a=
lgo needs to compare character s, and currently addresses memory like bytes=
 naively with [] as if I were using C++ and that did the right thing. It do=
es mostly and the patch passes all the current tests, but then all these te=
sts are for ASCII. But in C the [] is very dumb and so some macro salad is =
probably required.</div><br><div class=3D"gmail_quote"><div dir=3D"ltr" cla=
ss=3D"gmail_attr">On Wed, Feb 4, 2026, 15:53 Stefan Monnier &lt;<a href=3D"=
mailto:monnier@HIDDEN" target=3D"_blank" rel=3D"noreferrer">monni=
er@HIDDEN</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quot=
e" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204)=
;padding-left:1ex">&gt; Seems like my patch is too naive regarding wide cha=
rs. Gotta fix that.<br>
&gt; What&#39;s the recommended way to iterate such strings in C code?<br>
<br>
I&#39;m missing something: why does the width of characters matter?<br>
<br>
<br>
=3D=3D=3D Stefan<br>
<br>
</blockquote></div></div><div data-smartmail=3D"gmail_signature">Jo=C3=A3o =
T=C3=A1vora</div></div>

--000000000000de089f064a01a09b--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 13:31:48 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 08:31:48 2026
Received: from localhost ([127.0.0.1]:59835 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vncyv-0004iS-Gy
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:31:48 -0500
Received: from mail-oa1-x2d.google.com ([2001:4860:4864:20::2d]:50343)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vncyp-0004iD-ND
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:31:43 -0500
Received: by mail-oa1-x2d.google.com with SMTP id
 586e51a60fabf-409470ad5bbso2563955fac.0
 for <80323 <at> debbugs.gnu.org>; Wed, 04 Feb 2026 05:31:39 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770211898; cv=none;
 d=google.com; s=arc-20240605;
 b=YGPr+e8F2A+OJBKyjX9+Jnlt0Ys1F9arVqltAUQA+K+inS0aTtUnZATIQVDp1XBY6r
 tV0UFcoklArg44+D6p43Jg1R8GfwT7LWlHlCcueRu6Qf8KO+0/Ekz0l645Ts5VQmbZ+v
 fvN7hZrRZLbdZGL4oY8L9P/0WemJBNGl0+Kt3EIY2pyfE8E+dO4/sdcXG5O6ZMqecnTQ
 TQQBtOzQigoxD0fQxDunqmKp/+3DtRchO/U0p8/V5ZS783Ia23ocqtosA1ZUSOgImTcK
 e+/k2OIV5YMPdTBIEVr18bm/+EFS9OL4A8TWi1b/U6NwM4Z8cUs7jNdcdWtJ/Ij5sqDC
 GbXw==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=to:subject:message-id:date:from:in-reply-to:references:mime-version
 :dkim-signature;
 bh=vVNCc2yncqJoDmPerpFO7zlV+NWL2PH8LCjj/GTMxDQ=;
 fh=vn0RqOen5tsrdBRE0q4SRfweiUNyML0qzMfGNW7lHs8=;
 b=hnd5H53ps8kh89yL9i4VTL+jL7IUWH9EawS3Q9EeVYeevE7O5RP1/Cd5LTlrVjrxij
 BYtA4sz2+WAC8T0IwhbMBjuNNcQqhv9E6KTlGCZagGWt9TKjIzkIAykudXaPk7gx1CX0
 RLMBbyr9R3I17BsLuOw/xwhOeAPqbWA04UskOYs0hdmsKwPnT+fS4hNm1+0hMJseZou8
 374XnMdwqQPbh9N6Ctw3R3XlZxZ1gaDX4G9ddofigE4W9nH/UL6mYNyOCv2SUAQmA0c6
 XP5kAKk28FWHH1o9TqohW9xlc9X3IcxX+Tmh+8PJoYEtHgKp5DoljD4G6USNP3wLj86L
 +GzQ==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770211898; x=1770816698; darn=debbugs.gnu.org;
 h=to:subject:message-id:date:from:in-reply-to:references:mime-version
 :from:to:cc:subject:date:message-id:reply-to;
 bh=vVNCc2yncqJoDmPerpFO7zlV+NWL2PH8LCjj/GTMxDQ=;
 b=PnwsJz80k39PpGeafisRXYjKegqn0cKEWpvWhknJ5Mi526TbFWs/1Cl/sY+4h6ZS/y
 FQ0n+KXfzT6hWjqrVkPa9znVRTzjqx1mI0EzU/NGd7yhNoyidLFoVoS6XV/YaHeGGsG9
 CsatY17DyiZ+Y3ibH32xcu0snT6t/pJmm7pRDCilIeC3JouQDEKh53cNmZh8q7+YUuVw
 TJkpG8dTiwpZ3JiWy719+g+DEECNlJqg7+IC+et+UZDgI08d0YapdRFrBIKzT+h4pvZ8
 jJW8hh4KQ4/3dM79y3Ut4YI9q3ZPDflLZlv3rRx32YuQlxzPkpiWLspDTlHkzbx04Eli
 ghjw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770211898; x=1770816698;
 h=to:subject:message-id:date:from:in-reply-to:references:mime-version
 :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=vVNCc2yncqJoDmPerpFO7zlV+NWL2PH8LCjj/GTMxDQ=;
 b=wb0W/6bko+h0vyo928gngp6MGWvbvmPwOQG9btTFuGHRNkB/c/Nk7TVqkvdRPMbUN9
 8bmeTmuUWheRhXo3BJrdaMBj0I1rACSecqnrSExENJw653lHVoiCHaDR58RcLnN1Ti5P
 NKdlqvu1Fp1OvKqKR64xLW8BKxcDq980L/JLZBZJkGVhSVEg5m9CqXdUCpRa0lU7v3gE
 pRM8ptu8JcISeY0n/QMvTLDd46JwPTuKqX3b3Oqh3Mi8JJr9qoVC0oaNzj2U5xng7P8L
 7BtA53WpFSyc7ZeACgR6dMfnz6etInj/zYpbDPD87x4hwnXjQ2k7XmN8V51yB2w5SrJH
 7Oiw==
X-Gm-Message-State: AOJu0YyXQh3pseAmpmrk9Say3B5oEbWlHBemUIPr8sGrzorNa0XTuziw
 oeInLXEa7Ek3QGOdJVs4iqFpk1dt4JgDTKyK4ngWsQ5sYIDw7gTNBjWuQ8bZ4baZAVW12Wcg4uR
 I0nvKDJpoCObpkmo7e0nn86bgBalKP/F+9A==
X-Gm-Gg: AZuq6aJ1zUPTdT+Y80FmsYULkP/dmifNB6kRJUHVHMD28Hg8EQMgWtxT+TdHqH7TFCH
 fLIkI0Z8tTncMT1ThH/Rr0SUnfi9jlLdcr7SCxZkfNIg3BEPw1F3zQDYc0ZOc69Ww6xQE8TsmU0
 gm6e5D6Q785SWYkZoBPbANvVdX1Ug0pBgO3ThUbF0krg8HeumwH6l2fipxZhgsvt8ClzfuYhUNo
 ePTkB4VRMfh6El/WYhJ3owXD7XphON3K/fNE/npATNy5/b5zrhb+SgKou46S1zCnhdP9fc=
X-Received: by 2002:a05:6820:2295:b0:66a:1886:e4c2 with SMTP id
 006d021491bc7-66a207899d7mr1311296eaf.20.1770211898392; Wed, 04 Feb 2026
 05:31:38 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN>
In-Reply-To: <87zf5p7362.fsf@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Wed, 4 Feb 2026 13:31:27 +0000
X-Gm-Features: AZwV_Qh64J4jrJ7_OLikFa-tAe2uaBe-CP0PQJveTgAFIxhDrgjHRFyflhUr5QE
Message-ID: <CALDnm51X1FZXk3JVRfxL3yPWsFSYmB9YVOe0u+0SDO-cpLM9SA@HIDDEN>
Subject: Fwd: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: 80323 <at> debbugs.gnu.org
Content-Type: multipart/alternative; boundary="00000000000061872d0649ff9353"
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

--00000000000061872d0649ff9353
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Seems like I didn't send the latest patch to the bug tracker...

Jo=C3=A3o T=C3=A1vora

---------- Forwarded message ---------
From: Jo=C3=A3o T=C3=A1vora <joaotavora@HIDDEN>
Date: Wed, Feb 4, 2026, 00:39
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
algorithm
To: St=C3=A9phane Marks <shipmints@HIDDEN>
Cc: Sean Whitton <spwhitton@HIDDEN>, <axel@HIDDEN>, <
monnier@HIDDEN>


St=C3=A9phane Marks <shipmints@HIDDEN> writes:

> - list
>
> In my past doing some computational biology work, I'd also done a little
dabbling.  I found this guy's ideas useful
> especially with regard to using integer arithmetic vs. floats and that
might help the efficiency of this adaptation for
> Emacs https://florianerhard.github.io/2016/gotoh3
>
https://github.com/florianerhard/florianerhard.github.io/tree/master/assets=
/gotoh
>
> I have not read the code beyond eyeballing the double-precision float
matrices which is what prompted my ancient memory
> cells to reactivate.

I've rewritten the patch to be cost-based, which is much cleaner.  I
also cleaned up some C silliness along the way (like the indiscrimate
use of ptrdiff_t for loop indexes)

I've tried also some optimizations, like simplifying the "gap origin"
memory, using just a two-row matrix for match and using ints instead of
doubles.  Neither made any practical difference.  In a final version we
could consider removing them if we find they obfuscate the code
needlessly.

So The code is just as fast as before and only slightly faster than
hotfuzz.  But now since it's cost-based too maybe it will be easier to
compare the implementations.  I think hotfuzz's uses a simpler
backtracking method for highlighting somehow.

Also, I read the article, perhaps that guy did his PHD a long time ago
when CPU architectures were very different?

Anyway, the latest patch to play around with is after my sig.

Jo=C3=A3o

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index fc193fe54f0..47652d2bda4 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -4450,18 +4450,12 @@ completion-pcm--all-completions
            (when (string-match-p regex c) (push c poss)))
          (nreverse poss))))))

-(defvar flex-score-match-tightness 3
-  "Controls how the `flex' completion style scores its matches.
-
-Value is a positive number.  A number smaller than 1 makes the
-scoring formula reward matches scattered along the string, while
-a number greater than one make the formula reward matches that
-are clumped together.  I.e \"foo\" matches both strings
-\"fbarbazoo\" and \"fabrobazo\", which are of equal length, but
-only a value greater than one will score the former (which has
-one large \"hole\" and a clumped-together \"oo\" match) higher
-than the latter (which has two \"holes\" and three
-one-letter-long matches).")
+(defvar flex-score-match-tightness nil)
+
+(make-obsolete-variable
+ 'flex-score-match-tightness
+ "It never did anything very useful anyway."
+ "31.0")

 (defvar completion-lazy-hilit nil
   "If non-nil, request lazy highlighting of completion candidates.
@@ -4502,133 +4496,46 @@ completion-lazy-hilit
       (funcall completion-lazy-hilit-fn (copy-sequence str))
     str))

-(defun completion--hilit-from-re (string regexp &optional point-idx)
-  "Fontify STRING using REGEXP POINT-IDX.
-Uses `completions-common-part' and `completions-first-difference'
-faces to fontify STRING.
-POINT-IDX is the position of point in the presumed \"PCM\" pattern
-from which REGEXP was generated."
-  (let* ((md (and regexp (string-match regexp string) (cddr (match-data
t))))
-         (pos (if point-idx (match-beginning point-idx) (match-end 0)))
-         (me (and md (match-end 0)))
-         (from 0))
-    (while md
-      (add-face-text-property from (pop md)
-                              'completions-common-part nil string)
-      (setq from (pop md)))
-    (if (and (numberp pos) (> (length string) pos))
-        (add-face-text-property
-         pos (1+ pos)
-         'completions-first-difference
-         nil string))
-    (unless (or (not me) (=3D from me))
-      (add-face-text-property from me 'completions-common-part nil string)=
)
-    string))
-
-(defun completion--flex-score-1 (md-groups match-end len)
-  "Compute matching score of completion.
-The score lies in the range between 0 and 1, where 1 corresponds to
-the full match.
-MD-GROUPS is the \"group\"  part of the match data.
-MATCH-END is the end of the match.
-LEN is the length of the completion string."
-  (let* ((from 0)
-         ;; To understand how this works, consider these simple
-         ;; ascii diagrams showing how the pattern "foo"
-         ;; flex-matches "fabrobazo", "fbarbazoo" and
-         ;; "barfoobaz":
-
-         ;;      f abr o baz o
-         ;;      + --- + --- +
-
-         ;;      f barbaz oo
-         ;;      + ------ ++
-
-         ;;      bar foo baz
-         ;;          +++
-
-         ;; "+" indicates parts where the pattern matched.  A
-         ;; "hole" in the middle of the string is indicated by
-         ;; "-".  Note that there are no "holes" near the edges
-         ;; of the string.  The completion score is a number
-         ;; bound by (0..1] (i.e., larger than (but not equal
-         ;; to) zero, and smaller or equal to one): the higher
-         ;; the better and only a perfect match (pattern equals
-         ;; string) will have score 1.  The formula takes the
-         ;; form of a quotient.  For the numerator, we use the
-         ;; number of +, i.e. the length of the pattern.  For
-         ;; the denominator, it first computes
-         ;;
-         ;;     hole_i_contrib =3D 1 + (Li-1)^(1/tightness)
-         ;;
-         ;; , for each hole "i" of length "Li", where tightness
-         ;; is given by `flex-score-match-tightness'.  The
-         ;; final value for the denominator is then given by:
-         ;;
-         ;;    (SUM_across_i(hole_i_contrib) + 1) * len
-         ;;
-         ;; , where "len" is the string's length.
-         (score-numerator 0)
-         (score-denominator 0)
-         (last-b 0))
-    (while (and md-groups (car md-groups))
-      (let ((a from)
-            (b (pop md-groups)))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b))
-      (setq from (pop md-groups)))
-    ;; If `pattern' doesn't have an explicit trailing any, the
-    ;; regex `re' won't produce match data representing the
-    ;; region after the match.  We need to account to account
-    ;; for that extra bit of match (bug#42149).
-    (unless (=3D from match-end)
-      (let ((a from)
-            (b match-end))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b)))
-    (/ score-numerator (* len (1+ score-denominator)) 1.0)))
-
-(defvar completion--flex-score-last-md nil
-  "Helper variable for `completion--flex-score'.")
-
-(defun completion--flex-score (str re &optional dont-error)
-  "Compute flex score of completion STR based on RE.
-If DONT-ERROR, just return nil if RE doesn't match STR."
-  (let ((case-fold-search completion-ignore-case))
-    (cond ((string-match re str)
-           (let* ((match-end (match-end 0))
-                  (md (cddr
-                       (setq
-                        completion--flex-score-last-md
-                        (match-data t completion--flex-score-last-md)))))
-             (completion--flex-score-1 md match-end (length str))))
-          ((not dont-error)
-           (error "Internal error: %s does not match %s" re str)))))
-
-(defvar completion-pcm--regexp nil
-  "Regexp from PCM pattern in `completion-pcm--hilit-commonality'.")
+(cl-defun completion--flex-score (pat str &optional dont-error)
+  "Compute flex score of STR matching PAT using Gotoh algorithm.
+If DONT-ERROR, return nil if PAT cannot match STR.
+Returns (COST . MATCHES) where COST is a float (lower is better) and
+MATCHES is a list of match positions in STR."
+  (or (completion--flex-score-gotoh pat str)
+      (unless dont-error
+        (error "Pattern %s does not match %s" pat str))))
+
+(defun completion--flex-propertize (str matches point-idx segments)
+  "Add completion faces to STR based on MATCHES and POINT-IDX.
+MATCHES is a list of match positions.  POINT-IDX is a match group index
+from the PCM pattern.  SEGMENTS are extracted from the full PCM pattern.
+Adds `completions-common-part' for matched positions and
+`completions-first-difference' for the position corresponding to point."
+  (when point-idx
+    ;; Compute character position from segments
+    (let* ((pos (cl-loop for seg in segments
+                         for i from 1
+                         while (<=3D i point-idx)
+                         sum (length (car seg)))))
+      ;; Add first-difference after pos-th match, if in range
+      (let ((point-match (and (> pos 0)
+                              (<=3D pos (length matches))
+                              (nth (1- pos) matches))))
+        (when (and point-match (< (1+ point-match) (length str)))
+          (add-face-text-property
+           (1+ point-match) (+ 2 point-match)
+           'completions-first-difference nil str)))))
+  ;; Highlight matched positions
+  (dolist (pos matches)
+    (add-face-text-property pos (1+ pos)
+                           'completions-common-part
+                           nil str))
+  str)
+
+(defvar completion-flex--pattern-str nil
+  "Pattern string for flex completion scoring.
+This is the concatenated string parts from the PCM pattern,
+used by `completion--flex-score' for Gotoh algorithm matching.")

 (defun completion-pcm--hilit-commonality (pattern completions)
   "Show where and how well PATTERN matches COMPLETIONS.
@@ -4645,22 +4552,37 @@ completion-pcm--hilit-commonality
 Else, if `completion-lazy-hilit' is t, return COMPLETIONS
 unchanged, but setup a suitable `completion-lazy-hilit-fn' (which
 see) for later lazy highlighting."
-  (setq completion-pcm--regexp nil
-        completion-lazy-hilit-fn nil)
+  (setq completion-lazy-hilit-fn nil
+        completion-flex--pattern-str nil)
   (cond
    ((and completions (cl-loop for e in pattern thereis (stringp e)))
     (let* ((segments (completion-pcm--pattern->segments pattern))
-           (re (completion-pcm--segments->regex segments 'group))
-           (point-idx (completion-pcm--segments-point-idx segments)))
-      (setq completion-pcm--regexp re)
+           (point-idx (completion-pcm--segments-point-idx segments))
+           ;; Extract pattern string (concatenate string elements)
+           (pat (mapconcat #'identity
+                           (delq nil (mapcar (lambda (x)
+                                               (if (stringp x) x nil))
+                                             pattern))
+                           "")))
+      (setq completion-flex--pattern-str pat)
       (cond (completion-lazy-hilit
              (setq completion-lazy-hilit-fn
-                   (lambda (str) (completion--hilit-from-re str re
point-idx)))
+                   (lambda (str)
+                     (let ((result (completion--flex-score pat str t)))
+                       (when result
+                         (completion--flex-propertize
+                          str (cdr result) point-idx segments)))
+                     str))
              completions)
             (t
              (mapcar
               (lambda (str)
-                (completion--hilit-from-re (copy-sequence str) re
point-idx))
+                (setq str (copy-sequence str))
+                (let ((result (completion--flex-score pat str t)))
+                  (when result
+                    (completion--flex-propertize
+                     str (cdr result) point-idx segments)))
+                str)
               completions)))))
    (t completions)))

@@ -5009,7 +4931,7 @@ completion-flex-nospace

 (defun completion--flex-adjust-metadata (metadata)
   "If `flex' is actually doing filtering, adjust sorting."
-  (let ((flex-is-filtering-p completion-pcm--regexp)
+  (let ((flex-is-filtering-p completion-flex--pattern-str)
         (existing-dsf
          (completion-metadata-get metadata 'display-sort-function))
         (existing-csf
@@ -5021,11 +4943,11 @@ completion--flex-adjust-metadata
                              (mapcar
                               (lambda (str)
                                 (cons
-                                 (- (completion--flex-score
-                                     (or (get-text-property
-                                          0 'completion--unquoted str)
-                                         str)
-                                     completion-pcm--regexp))
+                                 (car (completion--flex-score
+                                       completion-flex--pattern-str
+                                       (or (get-text-property
+                                            0 'completion--unquoted str)
+                                           str)))
                                  str))
                               (if existing-sort-fn
                                   (funcall existing-sort-fn completions)
diff --git a/src/minibuf.c b/src/minibuf.c
index 5dc2b230883..a3a93454383 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -20,6 +20,7 @@ Copyright (C) 1985-1986, 1993-2026 Free Software
Foundation, Inc.

 #include <config.h>
 #include <errno.h>
+#include <math.h>

 #include <binary-io.h>

@@ -2279,6 +2280,147 @@ init_minibuf_once_for_pdumper (void)
   last_minibuf_string =3D Qnil;
 }

+DEFUN ("completion--flex-score-gotoh", Fcompletion__flex_score_gotoh,
+       Scompletion__flex_score_gotoh, 2, 2, 0,
+       doc: /* Compute flex score of STR matching PAT using Gotoh
algorithm.
+Returns (COST . MATCHES) where COST is a float (lower is better) and
+MATCHES is a list of match positions in STR, or nil if no match found.  */=
)
+  (Lisp_Object pat, Lisp_Object str)
+{
+  /* Pre-allocated matrices for flex completion scoring.  */
+#define FLEX_MAX_STR_SIZE 512
+#define FLEX_MAX_PAT_SIZE 128
+
+  /* Only two rows actually needed for M and D */
+  static int M[2 * FLEX_MAX_STR_SIZE];
+  static int D[2 * FLEX_MAX_STR_SIZE];
+  static size_t P[FLEX_MAX_STR_SIZE * FLEX_MAX_PAT_SIZE];
+  /* Macro for 2D indexing.  MAT uses only 2 rows for M and D,
+     alternating via bitmask.  MAT uses full indexing for P.  */
+#define MAT2(matrix, i, j) ((matrix)[(((i) + 1) & 1) * width + ((j) + 1)])
+#define MAT(matrix, i, j) ((matrix)[((i) + 1) * width + ((j) + 1)])
+
+  CHECK_STRING (pat);
+  CHECK_STRING (str);
+
+  size_t m =3D SCHARS (pat);
+  size_t n =3D SCHARS (str);
+  size_t width =3D n + 1;
+  size_t size =3D (m + 1) * width;
+
+  /* Bail if strings are empty or matrix too large.  */
+  if (m =3D=3D 0 || n =3D=3D 0)
+    return Qnil;
+
+  if (size > sizeof(P))
+    return Qnil;
+
+  /* Extract string data.  */
+  unsigned char *pat_data =3D SDATA (pat);
+  unsigned char *str_data =3D SDATA (str);
+
+  /* Cost constants (lower is better).  */
+  const int gap_open_cost =3D 100;
+  const int gap_extend_cost =3D 10;
+  const int pos_inf =3D INT_MAX / 2;
+
+  /* Base case: can start matching at any position in str. Its a free
+     leading gap.  So set the first row of D (row -1) to 0.  */
+  for (int j =3D 0; j < width; j++)
+    D[j] =3D 0;
+
+  int prev_gap_origin =3D -1;
+
+  /* Forward pass - compute M and D matrices (minimize cost).  */
+  for (int i =3D 0; i < m; i++)
+    {
+      unsigned char pat_char =3D pat_data[i];
+      int gap_origin =3D -1; /* Index of last match before a gap started *=
/
+
+      MAT2 (M, i, -1) =3D pos_inf;
+      MAT2 (D, i, -1) =3D pos_inf;
+
+      for (int j =3D 0; j < n; j++)
+        {
+          unsigned char str_char =3D str_data[j];
+
+          /* Compute gap cost D[i][j].  */
+          int from_match =3D MAT2 (M, i, j - 1) + gap_open_cost;
+          int from_gap =3D MAT2 (D, i, j - 1) + gap_extend_cost;
+
+         if (from_match < from_gap)
+           {
+             MAT2 (D, i, j) =3D from_match;
+             gap_origin =3D j - 1;  /* New gap. */
+           }
+         else
+           MAT2 (D, i, j) =3D from_gap;  /* Extend gap.  */
+
+          /* Check if characters match (case-insensitive if needed).  */
+          bool chars_match;
+          if (completion_ignore_case)
+            chars_match =3D (downcase (pat_char) =3D=3D downcase (str_char=
));
+          else
+            chars_match =3D (pat_char =3D=3D str_char);
+
+          /* Compute match cost M[i][j] (no cost for matching).  */
+          MAT2 (M, i, j) =3D pos_inf;
+          if (chars_match)
+            {
+              int prev_match =3D MAT2 (M, i - 1, j - 1);
+              int prev_gap =3D MAT2 (D, i - 1, j - 1);
+
+              if (prev_match <=3D prev_gap)
+                {
+                  MAT2 (M, i, j) =3D prev_match;
+                  MAT (P, i, j) =3D j - 1;
+                }
+              else
+                {
+                  MAT2 (M, i, j) =3D prev_gap;
+                  MAT (P, i, j) =3D prev_gap_origin;
+                }
+            }
+        }
+      prev_gap_origin =3D gap_origin;
+    }
+
+  /* Find best (lowest) cost in last row.  */
+  int best_cost =3D pos_inf;
+  int lastcol =3D -1;
+
+  for (int j =3D 0; j < n; j++)
+    {
+      int cost =3D MAT2 (M, m - 1, j);
+      if (cost < best_cost)
+        {
+          best_cost =3D cost;
+          lastcol =3D j;
+        }
+    }
+
+  if (lastcol < 0 || best_cost >=3D pos_inf)
+    return Qnil;
+
+  /* Normalize cost to penalize longer strings.  Lower is better.  */
+  double normalized_cost =3D best_cost + (double) (n - m) / (double) m;
+
+  /* Build match positions list by tracing back through P matrix.  */
+  Lisp_Object matches =3D Qnil;
+  int k =3D lastcol;
+
+  for (int i =3D m - 1; i >=3D 0 && k >=3D 0; i--)
+    {
+      matches =3D Fcons (make_fixnum (k), matches);
+      k =3D MAT (P, i, k);
+    }
+
+#undef MAT2
+#undef MAT
+
+  return Fcons (make_float (normalized_cost), matches);
+}
+
 void
 syms_of_minibuf (void)
 {
@@ -2541,6 +2683,7 @@ syms_of_minibuf (void)
   defsubr (&Stest_completion);
   defsubr (&Sassoc_string);
   defsubr (&Scompleting_read);
+  defsubr (&Scompletion__flex_score_gotoh);
   DEFSYM (Qminibuffer_quit_recursive_edit,
"minibuffer-quit-recursive-edit");
   DEFSYM (Qinternal_complete_buffer, "internal-complete-buffer");
   DEFSYM (Qcompleting_read_function, "completing-read-function");
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 79ffb1d3fc7..005d7c500d4 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -205,11 +205,6 @@ completion-all-sorted-completions
                   '("some/alpha" "base/epsilon" "base/delta"))
                  `("epsilon" "delta" "beta" "alpha" "gamma"  . 5))))

-(defun completion--pcm-score (comp)
-  "Get `completion-score' from COMP."
-  ;; FIXME, uses minibuffer.el implementation details
-  (completion--flex-score comp completion-pcm--regexp))
-
 (defun completion--pcm-first-difference-pos (comp)
   "Get `completions-first-difference' from COMP."
   (cl-loop for pos =3D (next-single-property-change 0 'face comp)
@@ -244,20 +239,11 @@ completion-pcm-test-2
            "barfoobar")))

 (ert-deftest completion-pcm-test-3 ()
-  ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-pcm-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion-pcm-all-completions
+                "R" '("R" "hello") nil 1))))

 (ert-deftest completion-pcm-test-4 ()
-  ;; One fourth of a match and no match due to point being at the end
-  (should (eql
-           (completion--pcm-score
-            (car (completion-pcm-all-completions
-                  "RO" '("RaOb") nil 1)))
-           (/ 1.0 4.0)))
+  ;; No match due to point being at the end
   (should (null
            (completion-pcm-all-completions
             "RO" '("RaOb") nil 2))))
@@ -420,24 +406,14 @@ completion-pcm-bug4219
            "a")))

 (ert-deftest completion-substring-test-1 ()
-  ;; One third of a match!
   (should (equal
            (car (completion-substring-all-completions
                  "foo" '("hello" "world" "barfoobar") nil 3))
-           "barfoobar"))
-  (should (eql
-           (completion--pcm-score
-            (car (completion-substring-all-completions
-                  "foo" '("hello" "world" "barfoobar") nil 3)))
-           (/ 1.0 3.0))))
+           "barfoobar")))

 (ert-deftest completion-substring-test-2 ()
-  ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-substring-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion-substring-all-completions
+                "R" '("R" "hello") nil 1))))

 (ert-deftest completion-substring-test-3 ()
   ;; Substring match
@@ -504,11 +480,8 @@ completion-flex-test-1

 (ert-deftest completion-flex-test-2 ()
   ;; Full match!
-  (should (eql
-           (completion--pcm-score
-            (car (completion-flex-all-completions
-                  "R" '("R" "hello") nil 1)))
-           1.0)))
+  (should (car (completion-flex-all-completions
+                "R" '("R" "hello") nil 1))))

 (ert-deftest completion-flex-test-3 ()
   ;; Another fuzzy match, but more of a "substring" one

--00000000000061872d0649ff9353
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div>Seems like I didn&#39;t send the latest patch to the=
 bug tracker...</div><div><br></div><div data-smartmail=3D"gmail_signature"=
>Jo=C3=A3o T=C3=A1vora</div></div><br><div class=3D"gmail_quote gmail_quote=
_container"><div dir=3D"ltr" class=3D"gmail_attr">---------- Forwarded mess=
age ---------<br>From: <strong class=3D"gmail_sendername" dir=3D"auto">Jo=
=C3=A3o T=C3=A1vora</strong> <span dir=3D"auto">&lt;<a href=3D"mailto:joaot=
avora@HIDDEN">joaotavora@HIDDEN</a>&gt;</span><br>Date: Wed, Feb 4, 2=
026, 00:39<br>Subject: Re: bug#80323: [PATCH] Rewrite flex completion scori=
ng with Gotoh algorithm<br>To: St=C3=A9phane Marks &lt;<a href=3D"mailto:sh=
ipmints@HIDDEN">shipmints@HIDDEN</a>&gt;<br>Cc: Sean Whitton &lt;<a h=
ref=3D"mailto:spwhitton@HIDDEN">spwhitton@HIDDEN</a>&gt;,  =
&lt;<a href=3D"mailto:axel@HIDDEN">axel@HIDDEN</a>&gt;,  &lt;<a href=3D=
"mailto:monnier@HIDDEN">monnier@HIDDEN</a>&gt;<br></div=
><br><br>St=C3=A9phane Marks &lt;<a href=3D"mailto:shipmints@HIDDEN" tar=
get=3D"_blank" rel=3D"noreferrer">shipmints@HIDDEN</a>&gt; writes:<br>
<br>
&gt; - list<br>
&gt;<br>
&gt; In my past doing some computational biology work, I&#39;d also done a =
little dabbling.=C2=A0 I found this guy&#39;s ideas useful<br>
&gt; especially with regard to using integer arithmetic vs. floats and that=
 might help the efficiency of this adaptation for<br>
&gt; Emacs <a href=3D"https://florianerhard.github.io/2016/gotoh3" rel=3D"n=
oreferrer noreferrer" target=3D"_blank">https://florianerhard.github.io/201=
6/gotoh3</a><br>
&gt; <a href=3D"https://github.com/florianerhard/florianerhard.github.io/tr=
ee/master/assets/gotoh" rel=3D"noreferrer noreferrer" target=3D"_blank">htt=
ps://github.com/florianerhard/florianerhard.github.io/tree/master/assets/go=
toh</a><br>
&gt;<br>
&gt; I have not read the code beyond eyeballing the double-precision float =
matrices which is what prompted my ancient memory<br>
&gt; cells to reactivate.<br>
<br>
I&#39;ve rewritten the patch to be cost-based, which is much cleaner.=C2=A0=
 I<br>
also cleaned up some C silliness along the way (like the indiscrimate<br>
use of ptrdiff_t for loop indexes)<br>
<br>
I&#39;ve tried also some optimizations, like simplifying the &quot;gap orig=
in&quot;<br>
memory, using just a two-row matrix for match and using ints instead of<br>
doubles.=C2=A0 Neither made any practical difference.=C2=A0 In a final vers=
ion we<br>
could consider removing them if we find they obfuscate the code<br>
needlessly.<br>
<br>
So The code is just as fast as before and only slightly faster than<br>
hotfuzz.=C2=A0 But now since it&#39;s cost-based too maybe it will be easie=
r to<br>
compare the implementations.=C2=A0 I think hotfuzz&#39;s uses a simpler<br>
backtracking method for highlighting somehow.<br>
<br>
Also, I read the article, perhaps that guy did his PHD a long time ago<br>
when CPU architectures were very different?<br>
<br>
Anyway, the latest patch to play around with is after my sig.<br>
<br>
Jo=C3=A3o<br>
<br>
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el<br>
index fc193fe54f0..47652d2bda4 100644<br>
--- a/lisp/minibuffer.el<br>
+++ b/lisp/minibuffer.el<br>
@@ -4450,18 +4450,12 @@ completion-pcm--all-completions<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (string-match-p regex c) (p=
ush c poss)))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (nreverse poss))))))<br>
<br>
-(defvar flex-score-match-tightness 3<br>
-=C2=A0 &quot;Controls how the `flex&#39; completion style scores its match=
es.<br>
-<br>
-Value is a positive number.=C2=A0 A number smaller than 1 makes the<br>
-scoring formula reward matches scattered along the string, while<br>
-a number greater than one make the formula reward matches that<br>
-are clumped together.=C2=A0 I.e \&quot;foo\&quot; matches both strings<br>
-\&quot;fbarbazoo\&quot; and \&quot;fabrobazo\&quot;, which are of equal le=
ngth, but<br>
-only a value greater than one will score the former (which has<br>
-one large \&quot;hole\&quot; and a clumped-together \&quot;oo\&quot; match=
) higher<br>
-than the latter (which has two \&quot;holes\&quot; and three<br>
-one-letter-long matches).&quot;)<br>
+(defvar flex-score-match-tightness nil)<br>
+<br>
+(make-obsolete-variable<br>
+ &#39;flex-score-match-tightness<br>
+ &quot;It never did anything very useful anyway.&quot;<br>
+ &quot;31.0&quot;)<br>
<br>
=C2=A0(defvar completion-lazy-hilit nil<br>
=C2=A0 =C2=A0&quot;If non-nil, request lazy highlighting of completion cand=
idates.<br>
@@ -4502,133 +4496,46 @@ completion-lazy-hilit<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall completion-lazy-hilit-fn (copy-sequence=
 str))<br>
=C2=A0 =C2=A0 =C2=A0str))<br>
<br>
-(defun completion--hilit-from-re (string regexp &amp;optional point-idx)<b=
r>
-=C2=A0 &quot;Fontify STRING using REGEXP POINT-IDX.<br>
-Uses `completions-common-part&#39; and `completions-first-difference&#39;<=
br>
-faces to fontify STRING.<br>
-POINT-IDX is the position of point in the presumed \&quot;PCM\&quot; patte=
rn<br>
-from which REGEXP was generated.&quot;<br>
-=C2=A0 (let* ((md (and regexp (string-match regexp string) (cddr (match-da=
ta t))))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(pos (if point-idx (match-beginning poin=
t-idx) (match-end 0)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(me (and md (match-end 0)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(from 0))<br>
-=C2=A0 =C2=A0 (while md<br>
-=C2=A0 =C2=A0 =C2=A0 (add-face-text-property from (pop md)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &#39;completions-common-part nil string)<br=
>
-=C2=A0 =C2=A0 =C2=A0 (setq from (pop md)))<br>
-=C2=A0 =C2=A0 (if (and (numberp pos) (&gt; (length string) pos))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (add-face-text-property<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0pos (1+ pos)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;completions-first-difference<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0nil string))<br>
-=C2=A0 =C2=A0 (unless (or (not me) (=3D from me))<br>
-=C2=A0 =C2=A0 =C2=A0 (add-face-text-property from me &#39;completions-comm=
on-part nil string))<br>
-=C2=A0 =C2=A0 string))<br>
-<br>
-(defun completion--flex-score-1 (md-groups match-end len)<br>
-=C2=A0 &quot;Compute matching score of completion.<br>
-The score lies in the range between 0 and 1, where 1 corresponds to<br>
-the full match.<br>
-MD-GROUPS is the \&quot;group\&quot;=C2=A0 part of the match data.<br>
-MATCH-END is the end of the match.<br>
-LEN is the length of the completion string.&quot;<br>
-=C2=A0 (let* ((from 0)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; To understand how this works, conside=
r these simple<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; ascii diagrams showing how the patter=
n &quot;foo&quot;<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; flex-matches &quot;fabrobazo&quot;, &=
quot;fbarbazoo&quot; and<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; &quot;barfoobaz&quot;:<br>
-<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 f abr o baz o<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 + --- + --- +<br>
-<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 f barbaz oo<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 + ------ ++<br>
-<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 bar foo baz<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 +++=
<br>
-<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; &quot;+&quot; indicates parts where t=
he pattern matched.=C2=A0 A<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; &quot;hole&quot; in the middle of the=
 string is indicated by<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; &quot;-&quot;.=C2=A0 Note that there =
are no &quot;holes&quot; near the edges<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; of the string.=C2=A0 The completion s=
core is a number<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; bound by (0..1] (i.e., larger than (b=
ut not equal<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; to) zero, and smaller or equal to one=
): the higher<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; the better and only a perfect match (=
pattern equals<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; string) will have score 1.=C2=A0 The =
formula takes the<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; form of a quotient.=C2=A0 For the num=
erator, we use the<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; number of +, i.e. the length of the p=
attern.=C2=A0 For<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; the denominator, it first computes<br=
>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 =C2=A0hole_i_contrib =3D=
 1 + (Li-1)^(1/tightness)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; , for each hole &quot;i&quot; of leng=
th &quot;Li&quot;, where tightness<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; is given by `flex-score-match-tightne=
ss&#39;.=C2=A0 The<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; final value for the denominator is th=
en given by:<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;=C2=A0 =C2=A0 (SUM_across_i(hole_i_con=
trib) + 1) * len<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;;<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; , where &quot;len&quot; is the string=
&#39;s length.<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(score-numerator 0)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(score-denominator 0)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(last-b 0))<br>
-=C2=A0 =C2=A0 (while (and md-groups (car md-groups))<br>
-=C2=A0 =C2=A0 =C2=A0 (let ((a from)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (b (pop md-groups)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0score-numerator=C2=A0 =C2=A0(+ score-num=
erator (- b a)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless (or (=3D a last-b)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (zer=
op last-b)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (=3D=
 a len))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0score-denominator (+ score-denomi=
nator<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 1<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (expt (- a last-b 1)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (/ 1.0<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fl=
ex-score-match-tightness)))))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0last-b=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 b))<br>
-=C2=A0 =C2=A0 =C2=A0 (setq from (pop md-groups)))<br>
-=C2=A0 =C2=A0 ;; If `pattern&#39; doesn&#39;t have an explicit trailing an=
y, the<br>
-=C2=A0 =C2=A0 ;; regex `re&#39; won&#39;t produce match data representing =
the<br>
-=C2=A0 =C2=A0 ;; region after the match.=C2=A0 We need to account to accou=
nt<br>
-=C2=A0 =C2=A0 ;; for that extra bit of match (bug#42149).<br>
-=C2=A0 =C2=A0 (unless (=3D from match-end)<br>
-=C2=A0 =C2=A0 =C2=A0 (let ((a from)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (b match-end))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0score-numerator=C2=A0 =C2=A0(+ score-num=
erator (- b a)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (unless (or (=3D a last-b)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (zer=
op last-b)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (=3D=
 a len))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0score-denominator (+ score-denomi=
nator<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 1<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (expt (- a last-b 1)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (/ 1.0<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fl=
ex-score-match-tightness)))))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0last-b=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 b)))<br>
-=C2=A0 =C2=A0 (/ score-numerator (* len (1+ score-denominator)) 1.0)))<br>
-<br>
-(defvar completion--flex-score-last-md nil<br>
-=C2=A0 &quot;Helper variable for `completion--flex-score&#39;.&quot;)<br>
-<br>
-(defun completion--flex-score (str re &amp;optional dont-error)<br>
-=C2=A0 &quot;Compute flex score of completion STR based on RE.<br>
-If DONT-ERROR, just return nil if RE doesn&#39;t match STR.&quot;<br>
-=C2=A0 (let ((case-fold-search completion-ignore-case))<br>
-=C2=A0 =C2=A0 (cond ((string-match re str)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(let* ((match-end (match-end 0))<=
br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (md (cddr<b=
r>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0(setq<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 completion--flex-score-last-md<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 (match-data t completion--flex-score-last-md)))))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--flex-score-1 =
md match-end (length str))))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ((not dont-error)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(error &quot;Internal error: %s d=
oes not match %s&quot; re str)))))<br>
-<br>
-(defvar completion-pcm--regexp nil<br>
-=C2=A0 &quot;Regexp from PCM pattern in `completion-pcm--hilit-commonality=
&#39;.&quot;)<br>
+(cl-defun completion--flex-score (pat str &amp;optional dont-error)<br>
+=C2=A0 &quot;Compute flex score of STR matching PAT using Gotoh algorithm.=
<br>
+If DONT-ERROR, return nil if PAT cannot match STR.<br>
+Returns (COST . MATCHES) where COST is a float (lower is better) and<br>
+MATCHES is a list of match positions in STR.&quot;<br>
+=C2=A0 (or (completion--flex-score-gotoh pat str)<br>
+=C2=A0 =C2=A0 =C2=A0 (unless dont-error<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (error &quot;Pattern %s does not match %s&quot=
; pat str))))<br>
+<br>
+(defun completion--flex-propertize (str matches point-idx segments)<br>
+=C2=A0 &quot;Add completion faces to STR based on MATCHES and POINT-IDX.<b=
r>
+MATCHES is a list of match positions.=C2=A0 POINT-IDX is a match group ind=
ex<br>
+from the PCM pattern.=C2=A0 SEGMENTS are extracted from the full PCM patte=
rn.<br>
+Adds `completions-common-part&#39; for matched positions and<br>
+`completions-first-difference&#39; for the position corresponding to point=
.&quot;<br>
+=C2=A0 (when point-idx<br>
+=C2=A0 =C2=A0 ;; Compute character position from segments<br>
+=C2=A0 =C2=A0 (let* ((pos (cl-loop for seg in segments<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0for i from 1<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0while (&lt;=3D i point-idx)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0sum (length (car seg)))))<br>
+=C2=A0 =C2=A0 =C2=A0 ;; Add first-difference after pos-th match, if in ran=
ge<br>
+=C2=A0 =C2=A0 =C2=A0 (let ((point-match (and (&gt; pos 0)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (&lt;=3D pos (length matches))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (nth (1- pos) matches))))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 (when (and point-match (&lt; (1+ point-match) =
(length str)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (add-face-text-property<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(1+ point-match) (+ 2 point-match=
)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;completions-first-difference=
 nil str)))))<br>
+=C2=A0 ;; Highlight matched positions<br>
+=C2=A0 (dolist (pos matches)<br>
+=C2=A0 =C2=A0 (add-face-text-property pos (1+ pos)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0&#39;completions-common-part<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0nil str))<br>
+=C2=A0 str)<br>
+<br>
+(defvar completion-flex--pattern-str nil<br>
+=C2=A0 &quot;Pattern string for flex completion scoring.<br>
+This is the concatenated string parts from the PCM pattern,<br>
+used by `completion--flex-score&#39; for Gotoh algorithm matching.&quot;)<=
br>
<br>
=C2=A0(defun completion-pcm--hilit-commonality (pattern completions)<br>
=C2=A0 =C2=A0&quot;Show where and how well PATTERN matches COMPLETIONS.<br>
@@ -4645,22 +4552,37 @@ completion-pcm--hilit-commonality<br>
=C2=A0Else, if `completion-lazy-hilit&#39; is t, return COMPLETIONS<br>
=C2=A0unchanged, but setup a suitable `completion-lazy-hilit-fn&#39; (which=
<br>
=C2=A0see) for later lazy highlighting.&quot;<br>
-=C2=A0 (setq completion-pcm--regexp nil<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 completion-lazy-hilit-fn nil)<br>
+=C2=A0 (setq completion-lazy-hilit-fn nil<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 completion-flex--pattern-str nil)<br>
=C2=A0 =C2=A0(cond<br>
=C2=A0 =C2=A0 ((and completions (cl-loop for e in pattern thereis (stringp =
e)))<br>
=C2=A0 =C2=A0 =C2=A0(let* ((segments (completion-pcm--pattern-&gt;segments =
pattern))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(re (completion-pcm--segments-&gt=
;regex segments &#39;group))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(point-idx (completion-pcm--segme=
nts-point-idx segments)))<br>
-=C2=A0 =C2=A0 =C2=A0 (setq completion-pcm--regexp re)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(point-idx (completion-pcm--segme=
nts-point-idx segments))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;; Extract pattern string (concat=
enate string elements)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(pat (mapconcat #&#39;identity<br=
>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0(delq nil (mapcar (lambda (x)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0(if (stringp x) x nil))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0pattern))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0&quot;&quot;)))<br>
+=C2=A0 =C2=A0 =C2=A0 (setq completion-flex--pattern-str pat)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0(cond (completion-lazy-hilit<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq completion-lazy-hili=
t-fn<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lamb=
da (str) (completion--hilit-from-re str re point-idx)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lamb=
da (str)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0(let ((result (completion--flex-score pat str t)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0(when result<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0(completion--flex-propertize<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 str (cdr result) point-idx segments)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0str))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 completions)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(t<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (mapcar<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda (str)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (completion--hilit=
-from-re (copy-sequence str) re point-idx))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (setq str (copy-se=
quence str))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (let ((result (com=
pletion--flex-score pat str t)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (when resul=
t<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (com=
pletion--flex-propertize<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0str (cdr result) point-idx segments)))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0completions)))))<br>
=C2=A0 =C2=A0 (t completions)))<br>
<br>
@@ -5009,7 +4931,7 @@ completion-flex-nospace<br>
<br>
=C2=A0(defun completion--flex-adjust-metadata (metadata)<br>
=C2=A0 =C2=A0&quot;If `flex&#39; is actually doing filtering, adjust sortin=
g.&quot;<br>
-=C2=A0 (let ((flex-is-filtering-p completion-pcm--regexp)<br>
+=C2=A0 (let ((flex-is-filtering-p completion-flex--pattern-str)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(existing-dsf<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (completion-metadata-get metadata &#39;d=
isplay-sort-function))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(existing-csf<br>
@@ -5021,11 +4943,11 @@ completion--flex-adjust-metadata<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (mapcar<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(lambda (str)<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(cons<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(- (completion--flex-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(or (get-text-pr=
operty<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 0=
 &#39;completion--unquoted str)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0st=
r)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0completion-pcm--=
regexp))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(car (completion--flex-score<b=
r>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0completio=
n-flex--pattern-str<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(or (get-=
text-property<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 0 &#39;completion--unquoted str)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0str)))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 str))<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(if existing-sort-fn<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(funcall existing-sort-=
fn completions)<br>
diff --git a/src/minibuf.c b/src/minibuf.c<br>
index 5dc2b230883..a3a93454383 100644<br>
--- a/src/minibuf.c<br>
+++ b/src/minibuf.c<br>
@@ -20,6 +20,7 @@ Copyright (C) 1985-1986, 1993-2026 Free Software Foundati=
on, Inc.<br>
<br>
=C2=A0#include &lt;config.h&gt;<br>
=C2=A0#include &lt;errno.h&gt;<br>
+#include &lt;math.h&gt;<br>
<br>
=C2=A0#include &lt;binary-io.h&gt;<br>
<br>
@@ -2279,6 +2280,147 @@ init_minibuf_once_for_pdumper (void)<br>
=C2=A0 =C2=A0last_minibuf_string =3D Qnil;<br>
=C2=A0}<br>
<br>
+DEFUN (&quot;completion--flex-score-gotoh&quot;, Fcompletion__flex_score_g=
otoh,<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0Scompletion__flex_score_gotoh, 2, 2, 0,<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0doc: /* Compute flex score of STR matching PAT =
using Gotoh algorithm.<br>
+Returns (COST . MATCHES) where COST is a float (lower is better) and<br>
+MATCHES is a list of match positions in STR, or nil if no match found.=C2=
=A0 */)<br>
+=C2=A0 (Lisp_Object pat, Lisp_Object str)<br>
+{<br>
+=C2=A0 /* Pre-allocated matrices for flex completion scoring.=C2=A0 */<br>
+#define FLEX_MAX_STR_SIZE 512<br>
+#define FLEX_MAX_PAT_SIZE 128<br>
+<br>
+=C2=A0 /* Only two rows actually needed for M and D */<br>
+=C2=A0 static int M[2 * FLEX_MAX_STR_SIZE];<br>
+=C2=A0 static int D[2 * FLEX_MAX_STR_SIZE];<br>
+=C2=A0 static size_t P[FLEX_MAX_STR_SIZE * FLEX_MAX_PAT_SIZE];<br>
+=C2=A0 /* Macro for 2D indexing.=C2=A0 MAT uses only 2 rows for M and D,<b=
r>
+=C2=A0 =C2=A0 =C2=A0alternating via bitmask.=C2=A0 MAT uses full indexing =
for P.=C2=A0 */<br>
+#define MAT2(matrix, i, j) ((matrix)[(((i) + 1) &amp; 1) * width + ((j) + =
1)])<br>
+#define MAT(matrix, i, j) ((matrix)[((i) + 1) * width + ((j) + 1)])<br>
+<br>
+=C2=A0 CHECK_STRING (pat);<br>
+=C2=A0 CHECK_STRING (str);<br>
+<br>
+=C2=A0 size_t m =3D SCHARS (pat);<br>
+=C2=A0 size_t n =3D SCHARS (str);<br>
+=C2=A0 size_t width =3D n + 1;<br>
+=C2=A0 size_t size =3D (m + 1) * width;<br>
+<br>
+=C2=A0 /* Bail if strings are empty or matrix too large.=C2=A0 */<br>
+=C2=A0 if (m =3D=3D 0 || n =3D=3D 0)<br>
+=C2=A0 =C2=A0 return Qnil;<br>
+<br>
+=C2=A0 if (size &gt; sizeof(P))<br>
+=C2=A0 =C2=A0 return Qnil;<br>
+<br>
+=C2=A0 /* Extract string data.=C2=A0 */<br>
+=C2=A0 unsigned char *pat_data =3D SDATA (pat);<br>
+=C2=A0 unsigned char *str_data =3D SDATA (str);<br>
+<br>
+=C2=A0 /* Cost constants (lower is better).=C2=A0 */<br>
+=C2=A0 const int gap_open_cost =3D 100;<br>
+=C2=A0 const int gap_extend_cost =3D 10;<br>
+=C2=A0 const int pos_inf =3D INT_MAX / 2;<br>
+<br>
+=C2=A0 /* Base case: can start matching at any position in str. Its a free=
<br>
+=C2=A0 =C2=A0 =C2=A0leading gap.=C2=A0 So set the first row of D (row -1) =
to 0.=C2=A0 */<br>
+=C2=A0 for (int j =3D 0; j &lt; width; j++)<br>
+=C2=A0 =C2=A0 D[j] =3D 0;<br>
+<br>
+=C2=A0 int prev_gap_origin =3D -1;<br>
+<br>
+=C2=A0 /* Forward pass - compute M and D matrices (minimize cost).=C2=A0 *=
/<br>
+=C2=A0 for (int i =3D 0; i &lt; m; i++)<br>
+=C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 unsigned char pat_char =3D pat_data[i];<br>
+=C2=A0 =C2=A0 =C2=A0 int gap_origin =3D -1; /* Index of last match before =
a gap started */<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 MAT2 (M, i, -1) =3D pos_inf;<br>
+=C2=A0 =C2=A0 =C2=A0 MAT2 (D, i, -1) =3D pos_inf;<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 for (int j =3D 0; j &lt; n; j++)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned char str_char =3D str_data[j];=
<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Compute gap cost D[i][j].=C2=A0 */<b=
r>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int from_match =3D MAT2 (M, i, j - 1) +=
 gap_open_cost;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int from_gap =3D MAT2 (D, i, j - 1) + g=
ap_extend_cost;<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (from_match &lt; from_gap)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MAT2 (D, i, j) =3D from_ma=
tch;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0gap_origin =3D j - 1;=C2=
=A0 /* New gap. */<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0else<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MAT2 (D, i, j) =3D from_gap;=C2=
=A0 /* Extend gap.=C2=A0 */<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Check if characters match (case-inse=
nsitive if needed).=C2=A0 */<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool chars_match;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (completion_ignore_case)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 chars_match =3D (downcase (pat_c=
har) =3D=3D downcase (str_char));<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 chars_match =3D (pat_char =3D=3D=
 str_char);<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Compute match cost M[i][j] (no cost =
for matching).=C2=A0 */<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAT2 (M, i, j) =3D pos_inf;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (chars_match)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int prev_match =3D MAT2 (=
M, i - 1, j - 1);<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int prev_gap =3D MAT2 (D,=
 i - 1, j - 1);<br>
+<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (prev_match &lt;=3D pr=
ev_gap)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAT2 (M, i,=
 j) =3D prev_match;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAT (P, i, =
j) =3D j - 1;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 else<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAT2 (M, i,=
 j) =3D prev_gap;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 MAT (P, i, =
j) =3D prev_gap_origin;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>
+=C2=A0 =C2=A0 =C2=A0 prev_gap_origin =3D gap_origin;<br>
+=C2=A0 =C2=A0 }<br>
+<br>
+=C2=A0 /* Find best (lowest) cost in last row.=C2=A0 */<br>
+=C2=A0 int best_cost =3D pos_inf;<br>
+=C2=A0 int lastcol =3D -1;<br>
+<br>
+=C2=A0 for (int j =3D 0; j &lt; n; j++)<br>
+=C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 int cost =3D MAT2 (M, m - 1, j);<br>
+=C2=A0 =C2=A0 =C2=A0 if (cost &lt; best_cost)<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 best_cost =3D cost;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 lastcol =3D j;<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 }<br>
+=C2=A0 =C2=A0 }<br>
+<br>
+=C2=A0 if (lastcol &lt; 0 || best_cost &gt;=3D pos_inf)<br>
+=C2=A0 =C2=A0 return Qnil;<br>
+<br>
+=C2=A0 /* Normalize cost to penalize longer strings.=C2=A0 Lower is better=
.=C2=A0 */<br>
+=C2=A0 double normalized_cost =3D best_cost + (double) (n - m) / (double) =
m;<br>
+<br>
+=C2=A0 /* Build match positions list by tracing back through P matrix.=C2=
=A0 */<br>
+=C2=A0 Lisp_Object matches =3D Qnil;<br>
+=C2=A0 int k =3D lastcol;<br>
+<br>
+=C2=A0 for (int i =3D m - 1; i &gt;=3D 0 &amp;&amp; k &gt;=3D 0; i--)<br>
+=C2=A0 =C2=A0 {<br>
+=C2=A0 =C2=A0 =C2=A0 matches =3D Fcons (make_fixnum (k), matches);<br>
+=C2=A0 =C2=A0 =C2=A0 k =3D MAT (P, i, k);<br>
+=C2=A0 =C2=A0 }<br>
+<br>
+#undef MAT2<br>
+#undef MAT<br>
+<br>
+=C2=A0 return Fcons (make_float (normalized_cost), matches);<br>
+}<br>
+<br>
=C2=A0void<br>
=C2=A0syms_of_minibuf (void)<br>
=C2=A0{<br>
@@ -2541,6 +2683,7 @@ syms_of_minibuf (void)<br>
=C2=A0 =C2=A0defsubr (&amp;Stest_completion);<br>
=C2=A0 =C2=A0defsubr (&amp;Sassoc_string);<br>
=C2=A0 =C2=A0defsubr (&amp;Scompleting_read);<br>
+=C2=A0 defsubr (&amp;Scompletion__flex_score_gotoh);<br>
=C2=A0 =C2=A0DEFSYM (Qminibuffer_quit_recursive_edit, &quot;minibuffer-quit=
-recursive-edit&quot;);<br>
=C2=A0 =C2=A0DEFSYM (Qinternal_complete_buffer, &quot;internal-complete-buf=
fer&quot;);<br>
=C2=A0 =C2=A0DEFSYM (Qcompleting_read_function, &quot;completing-read-funct=
ion&quot;);<br>
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el<=
br>
index 79ffb1d3fc7..005d7c500d4 100644<br>
--- a/test/lisp/minibuffer-tests.el<br>
+++ b/test/lisp/minibuffer-tests.el<br>
@@ -205,11 +205,6 @@ completion-all-sorted-completions<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&#39;(=
&quot;some/alpha&quot; &quot;base/epsilon&quot; &quot;base/delta&quot;))<br=
>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 `(&quot;epsi=
lon&quot; &quot;delta&quot; &quot;beta&quot; &quot;alpha&quot; &quot;gamma&=
quot;=C2=A0 . 5))))<br>
<br>
-(defun completion--pcm-score (comp)<br>
-=C2=A0 &quot;Get `completion-score&#39; from COMP.&quot;<br>
-=C2=A0 ;; FIXME, uses minibuffer.el implementation details<br>
-=C2=A0 (completion--flex-score comp completion-pcm--regexp))<br>
-<br>
=C2=A0(defun completion--pcm-first-difference-pos (comp)<br>
=C2=A0 =C2=A0&quot;Get `completions-first-difference&#39; from COMP.&quot;<=
br>
=C2=A0 =C2=A0(cl-loop for pos =3D (next-single-property-change 0 &#39;face =
comp)<br>
@@ -244,20 +239,11 @@ completion-pcm-test-2<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;barfoobar&quot;)))<br>
<br>
=C2=A0(ert-deftest completion-pcm-test-3 ()<br>
-=C2=A0 ;; Full match!<br>
-=C2=A0 (should (eql<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--pcm-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-pcm-all-complet=
ions<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quo=
t; &#39;(&quot;R&quot; &quot;hello&quot;) nil 1)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01.0)))<br>
+=C2=A0 (should (car (completion-pcm-all-completions<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quot; &#39=
;(&quot;R&quot; &quot;hello&quot;) nil 1))))<br>
<br>
=C2=A0(ert-deftest completion-pcm-test-4 ()<br>
-=C2=A0 ;; One fourth of a match and no match due to point being at the end=
<br>
-=C2=A0 (should (eql<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--pcm-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-pcm-all-complet=
ions<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;RO&qu=
ot; &#39;(&quot;RaOb&quot;) nil 1)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(/ 1.0 4.0)))<br>
+=C2=A0 ;; No match due to point being at the end<br>
=C2=A0 =C2=A0(should (null<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (completion-pcm-all-completions<b=
r>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;RO&quot; &#39;(&quot;=
RaOb&quot;) nil 2))))<br>
@@ -420,24 +406,14 @@ completion-pcm-bug4219<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;a&quot;)))<br>
<br>
=C2=A0(ert-deftest completion-substring-test-1 ()<br>
-=C2=A0 ;; One third of a match!<br>
=C2=A0 =C2=A0(should (equal<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-substring-all-co=
mpletions<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;foo&qu=
ot; &#39;(&quot;hello&quot; &quot;world&quot; &quot;barfoobar&quot;) nil 3)=
)<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;barfoobar&quot;))<br>
-=C2=A0 (should (eql<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--pcm-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-substring-all-c=
ompletions<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;foo&q=
uot; &#39;(&quot;hello&quot; &quot;world&quot; &quot;barfoobar&quot;) nil 3=
)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(/ 1.0 3.0))))<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0&quot;barfoobar&quot;)))<br>
<br>
=C2=A0(ert-deftest completion-substring-test-2 ()<br>
-=C2=A0 ;; Full match!<br>
-=C2=A0 (should (eql<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--pcm-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-substring-all-c=
ompletions<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quo=
t; &#39;(&quot;R&quot; &quot;hello&quot;) nil 1)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01.0)))<br>
+=C2=A0 (should (car (completion-substring-all-completions<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quot; &#39=
;(&quot;R&quot; &quot;hello&quot;) nil 1))))<br>
<br>
=C2=A0(ert-deftest completion-substring-test-3 ()<br>
=C2=A0 =C2=A0;; Substring match<br>
@@ -504,11 +480,8 @@ completion-flex-test-1<br>
<br>
=C2=A0(ert-deftest completion-flex-test-2 ()<br>
=C2=A0 =C2=A0;; Full match!<br>
-=C2=A0 (should (eql<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0(completion--pcm-score<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 (car (completion-flex-all-comple=
tions<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quo=
t; &#39;(&quot;R&quot; &quot;hello&quot;) nil 1)))<br>
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A01.0)))<br>
+=C2=A0 (should (car (completion-flex-all-completions<br>
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quot;R&quot; &#39=
;(&quot;R&quot; &quot;hello&quot;) nil 1))))<br>
<br>
=C2=A0(ert-deftest completion-flex-test-3 ()<br>
=C2=A0 =C2=A0;; Another fuzzy match, but more of a &quot;substring&quot; on=
e<br>
</div>

--00000000000061872d0649ff9353--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 13:24:23 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 08:24:23 2026
Received: from localhost ([127.0.0.1]:59762 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vncrn-0004HD-Cx
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:24:23 -0500
Received: from mail-vs1-xe2d.google.com ([2607:f8b0:4864:20::e2d]:52615)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <shipmints@HIDDEN>)
 id 1vncrk-0004H3-CV
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:24:21 -0500
Received: by mail-vs1-xe2d.google.com with SMTP id
 ada2fe7eead31-5f53ba9c548so2064583137.1
 for <80323 <at> debbugs.gnu.org>; Wed, 04 Feb 2026 05:24:20 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770211459; cv=none;
 d=google.com; s=arc-20240605;
 b=PgbGuB0SkykLSnfhGE8UJM48JCuio58xn6UB5xKqMO+EoO4ZVlmncwB0r5Lnc18Ahk
 BUfGgQT6z2RBQFn7lj/uekeGiq+HTw+YU8xVymRbXdgVE+vZngOLZo9hJ1ahYRPr2kUd
 ZEqRSGC4ir1CAaI1yVVTK4YRu2AFobhgJno47n0NDJoUT/AUy49vlRMzpBGK04uIrO9v
 0bf96qEtMEgmpS8wHwczARcvlcjxUQfc1+VsZGfDIiXaJnB3+PgBdEdoax8f3Lg2wZ+5
 lK7Iw5mzQY6yBHoZIVlxVV2uJGc0xBC4EqFtkbstjh48tsE+BQL6CCttfKa2McqyrOpb
 xUMA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:dkim-signature;
 bh=qLPc1Wbrm/D9IyBDyctlZpnSaz7heNVzIujDvGSVKlc=;
 fh=pk5mIRRl0g3d9nnxiaarSEKfjkGUGJG8rEbe455p4NM=;
 b=I/Ks0WKvBY9WM353N9jHZi78FCWX2N6zLGU4v3f3ib6o5Pe+QIPE/Og+5hitXyew15
 xUCBN4Iewzjnrrdt08Sm1lPRnBlI+gwkmm20W3jATKVQT5r2qxMCyEy3y54bErs7v7uV
 jzKzOS/kxicBA70T4hp89wMFzUFCevPxOCat1ed500p+2oqZtg73TnEypoOEwQh6qJO4
 csHbk7YpQiNwVfka+1sN9ubv51ifKzArKke5arlogs6eRQ7uGAv2Mp8HKpOMOK92NEk4
 OF3vSupVUTXS3KGwc5mwkraODpmZ4tNSgAxIR7ZK0mwtbuVFIv0NLtqtDsJO4JdUm13Q
 nDzA==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770211459; x=1770816259; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=qLPc1Wbrm/D9IyBDyctlZpnSaz7heNVzIujDvGSVKlc=;
 b=XC4r6+dFi4/TrNoWReY69S8qAWIhonyWdR7wAINBAJ/vgjvj9z06A0IlorpAI5KLuU
 oNHh1SzP0g4mFFTRQ+ynos4uliuc23/KR4Nd3c0nwCc3UvHIfBNiE7ph6IRc491ZKFqR
 Zh3qu81b5Z4lU6iDBiVoSOhDkoxqZ97maEAEOwn6kAC6fJ7BAdQJGQDo7VkFa97Ugbdp
 A8iXGwIighT+PImDqTDm3si/ZTmd3JDnKwSiIDdTu3tQcFSdLOW12XZIYgtO1CHb9L0N
 FB1a1jrepyxostEgF9FORfgnuGdUpCZJ3JuRSJQaSDBCd+iofvMjHgnFV8If6AaEz3YC
 yYmA==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770211459; x=1770816259;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=qLPc1Wbrm/D9IyBDyctlZpnSaz7heNVzIujDvGSVKlc=;
 b=LTryNUx+lHNSGXP+Pyah1lIpFWPz4eZKjVuD3KqXU+hJQ9p/ITR2hPbJ4zYySBxaeF
 y5+h3Hnu/5qrQ/6UPc4x9Z0odI+NqBEfhE9eV/gGkmc4grhGGANiAnnltQTGTwUA5tIp
 PBew1mvTfsUqC9szEPzPGKhD+ME1s73pSykLpvCUmpw/NJewBiOYk8Ltm8UKs7p6coUT
 +1zpINYhsB5Ebo2siL4R7NzJwG1W2YuuTr7YnCJYfXXXvln/8ZOgZl+ZGRri7zQIka0h
 Pea1hfiG7Rd3r5m2K9e+MxqGHxc6C2F0iSCmNGTBErKoCfFaJttwQ3Bic9XVh5xhQ0ZA
 1Y0g==
X-Forwarded-Encrypted: i=1;
 AJvYcCVD4Xf/EhotnbH21l6mZZNHNUSitMende5K5A84iICQcC4NVO2ApUySeeeBKGjkRueJTGGIXA==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YwRdZke+U+z59HaZKrn2n2vEUT5NOPO4mIizw5PCp/AFysdYAFL
 T2OMyBqIRZwPkcGxe7ESSkiFrau2+P1+jqjGT9CiQPQGYi2EHqrB7KcikFaPuiPBub5Q7Vy9cz1
 t4QTdopIXoJMWdQs2sacWiCy1jFqwkgw=
X-Gm-Gg: AZuq6aIqgV7v4RAjT7hQsEvfBvpj7XhrZHEorJHDO7J8hl+p/QTRg1svqJUvr12Xegj
 48RGxOdC0gh1vheQOGl6yJmPOZw+mp9AbpDceLfW2LTHofjKOhllgAuY/77rblw1yWI2zmjHyGj
 JchHjo2zEUn98BjuZCmd+ii74ExYLQmJB8cERwdLVhwBcp45W2GD9xTDHU+Zh/GGVUWGc0MFcly
 TCDQvXjjsU/Td8A4OaVuaIKk9BKKH5nU/S6YDUEdL2IwbaUXNWVAcSpCKIaogOeEPWFxMun79+N
 NrbU5wBAxPW3Nz7E6yqxWorKlxnN2l0P48qbgopyVCdcM6nBlBS0BuZU8Nk7ow==
X-Received: by 2002:a05:6102:3584:b0:5f5:2539:9b05 with SMTP id
 ada2fe7eead31-5f93961dbe9mr821437137.41.1770211459557; Wed, 04 Feb 2026
 05:24:19 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
 <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
In-Reply-To: <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
From: =?UTF-8?Q?St=C3=A9phane_Marks?= <shipmints@HIDDEN>
Date: Wed, 4 Feb 2026 08:24:08 -0500
X-Gm-Features: AZwV_Qi7o-OWxtvz3hNq9BjlNy7HvrmvJefkBQhJ8h_kIUoEHrH_zWdp2OR0vyc
Message-ID: <CAN+1Hbo7ce95DpN0BVjFxZ-69d7CTEUW7mY-JjD8OYv4amivZw@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Content-Type: multipart/alternative; boundary="000000000000396f330649ff79df"
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: 80323 <at> debbugs.gnu.org, Stefan Monnier <monnier@HIDDEN>,
 Sean Whitton <spwhitton@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

--000000000000396f330649ff79df
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

On Wed, Feb 4, 2026 at 8:09=E2=80=AFAM Jo=C3=A3o T=C3=A1vora <joaotavora@gm=
ail.com> wrote:

> Seems like my patch is too naive regarding wide chars. Gotta fix that.
> What's the recommended way to iterate such strings in C code?
>

IIRC, you can model something like in search.c look for references to
string_char_and_length.  I'm sure I'll be corrected if wrong.

--000000000000396f330649ff79df
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div class=3D"gmail_default" style=3D"fon=
t-family:monospace"><span style=3D"font-family:Arial,Helvetica,sans-serif">=
On Wed, Feb 4, 2026 at 8:09=E2=80=AFAM Jo=C3=A3o T=C3=A1vora &lt;<a href=3D=
"mailto:joaotavora@HIDDEN">joaotavora@HIDDEN</a>&gt; wrote:</span></d=
iv></div><div class=3D"gmail_quote gmail_quote_container"><blockquote class=
=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rg=
b(204,204,204);padding-left:1ex"><div dir=3D"auto"><div>Seems like my patch=
 is too naive regarding wide chars. Gotta fix that. What&#39;s the recommen=
ded way to iterate such strings in C code?</div></div></blockquote><div><br=
></div><div class=3D"gmail_default" style=3D"font-family:monospace">IIRC, y=
ou can model something like in search.c look for references to string_char_=
and_length.=C2=A0 I&#39;m sure I&#39;ll be corrected if wrong.</div></div><=
/div>

--000000000000396f330649ff79df--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 4 Feb 2026 13:08:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Feb 04 08:08:25 2026
Received: from localhost ([127.0.0.1]:59623 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnccK-0003W9-H9
	for submit <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:08:24 -0500
Received: from mail-oa1-x2e.google.com ([2001:4860:4864:20::2e]:58585)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vnccF-0003Vt-HW
 for 80323 <at> debbugs.gnu.org; Wed, 04 Feb 2026 08:08:22 -0500
Received: by mail-oa1-x2e.google.com with SMTP id
 586e51a60fabf-408778a8ec4so4433474fac.0
 for <80323 <at> debbugs.gnu.org>; Wed, 04 Feb 2026 05:08:19 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1770210498; cv=none;
 d=google.com; s=arc-20240605;
 b=XMsTpf1taFQubseR92GGDjq3QrNO5WidlGBQcDU+SXGOfx38yFmgNiE20Wx80y54V7
 4j0rNwFaRgjZ9NIfoXLRWv7xR2F9QAylqlXFF8vsT8cy1av9vwnELisCPHe2al164Mp2
 FszhWQqPjXYheYKvi2c1oDizZE9LWZI3WMyKzyXr9HB853cmYzqh2JYvNQ/C6ukYA7IV
 IWDWkAzwy2+98bAzFG58sF8zYczdvI4YgJRRAJwtObQM4fj7jJ8Pd8U2HiA2jWZbw4sT
 /IJ+20FqosV7h2Rp/r0cu2HBsSthU7bCH9hCJJrK5oDbmqWuZth98cjy3JZ7JLWRog3L
 WEDA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
 s=arc-20240605; 
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:dkim-signature;
 bh=eMEqcg0B0McpApmnmN+dMLY6U6+XczPWgFVFnxQoUws=;
 fh=b0B+DO3GdeQedSoRkdb4/yKupAjiRatcjSUdrQuQllM=;
 b=ZHvA8Hdf3LrQxqvFju3MFZmS2B8Gj7kMCe35w4hGdG6RfeVeLz5RAAHkU2Z7B1OqwF
 otq0tV89xTpImeaZMZ7ObvtgV814HQ1OK59AkrCEMCzldCMm6eX5VZ7qumevTIq3tfX1
 5O8wVnW4xaKVE3MP6FyJrtEsOqueNRo0mZka6hn6PMRYCkCQS4LPR5PwzOyulIrB8Ida
 4oUnIxXBwVbtpjIZ/UITI+h01QPM6u9lknAQf0ewCMxHGF5QvLkkwB0JX7jwRlgEqm3j
 TVaz/YPgzFO5r92k99V7e2AIIgH0qXyRgoH3CNUWA7+haiUrifuTege8qdJT+d0lWrin
 gIZg==; darn=debbugs.gnu.org
ARC-Authentication-Results: i=1; mx.google.com; arc=none
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770210498; x=1770815298; darn=debbugs.gnu.org;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:from:to:cc:subject:date:message-id:reply-to;
 bh=eMEqcg0B0McpApmnmN+dMLY6U6+XczPWgFVFnxQoUws=;
 b=gbvDwqxlh+f8eeaZf1oXcMmHymVuC1tRtSSz2NBJ26koH78XZWESFQrzUNJpIDBBta
 K4jxWBUTBza32AYy8bsQWEiZSYV8mItyo0Hc5wWOfHDst/sFezEwiJsZ+xR+jon+zMjv
 TpXce6yz3UipqvxqQ5th4Ijok5e7vYdjWjCdbiC+lmJsOuuzecxqj0VuO23vo4bnb3lw
 2sbYNmCD0kPrrnMHtiAdP4Yyqjkw12kSMgMVqELQW+XcxTVwpHE0cMiB2G5zXmPJeATs
 IOgFbw3sO91756llhT8SgjPZ7Lt/HwzG6oM8Av99z7s5cT28lcJ97310cHYKwXAvhho8
 iN5g==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770210498; x=1770815298;
 h=cc:to:subject:message-id:date:from:in-reply-to:references
 :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date
 :message-id:reply-to;
 bh=eMEqcg0B0McpApmnmN+dMLY6U6+XczPWgFVFnxQoUws=;
 b=JRvyBvTy+yZnjebzjI8DKiRvhWz0ZWwbbQlwN3w8JoKl5y54DrfzZh3lCeoASve2U5
 S6jASKBjLaV1c9SQ7e0buUnqi3cESUuyfSGsjg9VslRuQbzbQFB4LVCKP4zq/k30r8CD
 wNudkRAdl5GWK67wPEqoDwq7Ms38H3CojwD2tO57iHUQJy3GTJotF+W3or7aKdxsQ5FK
 3SKbyFKQMGRN9X5D97oC9ezF3UNJ1w43kbivTd50tZ17CiMfZ+0Hf1qc8OjBs+soOuPn
 x98MP3WveGRMwOaFXLH3OWnfGXz4Zw7Kwr1QeTN174a+9cTELesJWxxmPeW3FEU/zsrJ
 76+Q==
X-Forwarded-Encrypted: i=1;
 AJvYcCWy+aadoejBJTpRNCep+OVyOfxWwJO8IfIbCw85TqMpRo/HaXNdV/5hMA/19sp6UJvbNYDfqA==@debbugs.gnu.org
X-Gm-Message-State: AOJu0YwD+6qROa4RFRHE1TS9w05rLKeEUHTEGF6/D9pcDt998vmlzwn3
 5ypUZ1seUFuFV4ZudCBqvgcyqf2t5XiGeQYqSvek34tuLbUe+cA0dzTN7ptzf0XELaB1I8snXNW
 LrgRdxWoUh3IY7Ak7p7WXwOTeUa4QXEk=
X-Gm-Gg: AZuq6aIrXAIZRRx7/suBQhIv+b46WWBDK9Ij3WyRU1B12hwMtb227Fp4XVapG62vXv6
 6DFY37EpF6SoWVR9Ko9DCgoqsOC14HGWGLyN/HhoXCjug7/Yueuht9xCvdHKQ98ZBPqBQbbVaLH
 FYtbIXWN8ewDbzCUBbw+Qrd/zvUMm0OKVGRhEJ3bcWJJ+rVakkfBEZDtAeedjEYzDvVXZgaF8hX
 PM5Ul+9gpHkHS+gkxGxnmcFODY7oaToYG3isQTaINC+Vn1ecL3dujXN5cO5qPkbdwlduuA=
X-Received: by 2002:a05:6820:80e:b0:663:117c:fe05 with SMTP id
 006d021491bc7-66a2342dc7bmr1355398eaf.57.1770210498224; Wed, 04 Feb 2026
 05:08:18 -0800 (PST)
MIME-Version: 1.0
References: <87y0la2egy.fsf@HIDDEN> <87ms1q9bpq.fsf@HIDDEN>
 <CAN+1HbrAG_1YF4UzOyY_ARWzhKHsWCMaxgWb1qp8Rg1sq4SjVg@HIDDEN>
 <87zf5p7362.fsf@HIDDEN> <87qzr08yni.fsf@HIDDEN>
In-Reply-To: <87qzr08yni.fsf@HIDDEN>
From: =?UTF-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Date: Wed, 4 Feb 2026 13:07:44 +0000
X-Gm-Features: AZwV_QhJvNMm9XY6yn2ryjVCXVkngD6m5Yio-DcdW5je8tjjaclvY6KMUsIjGlk
Message-ID: <CALDnm50pn2rgD+K=gyr9Cj-iZy_rMFDmBRmHkT5P84hiVxaQnw@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
To: Sean Whitton <spwhitton@HIDDEN>
Content-Type: multipart/alternative; boundary="000000000000eca7890649ff3f4e"
X-Spam-Score: 1.0 (+)
X-Debbugs-Envelope-To: 80323
Cc: Stefan Monnier <monnier@HIDDEN>, 80323 <at> debbugs.gnu.org
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 0.0 (/)

--000000000000eca7890649ff3f4e
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Seems like my patch is too naive regarding wide chars. Gotta fix that.
What's the recommended way to iterate such strings in C code?

Jo=C3=A3o T=C3=A1vora

On Wed, Feb 4, 2026, 12:46 Sean Whitton <spwhitton@HIDDEN> wrote:

> Hello,
>
> I've identified a regression.
> When I use org-refile the candidates list can get stuck and
> icomplete-forward-completions and icomplete-backward-completions stop
> working.
>
> I try to type "Debiandevel" seeking to match "Debian.org/Development".
> I get an error in *Messages*.  I've pared down the CC list because it
> contains personal information; please take care when replying:
>
> Error in post-command-hook (icomplete-post-command-hook): (error "Pattern
> Deb does not match japanese.org/Development/Returning to Japanese/Ask
> =E7=9F=B3=E5=B7=9D=E5=85=88=E7=94=9F to send out advert a second time as =
semester begins/")
> completion--flex-score: Pattern Debian does not match
> RepeatedTasks.org/=E6=AF=8E=E6=97=A5=E3=81=AE=E3=82=A2=E3=82=B8=E3=82=A2=
=E8=AA=9E/Anki reviews (after back on basic kanji, I
> think)/ [12 times]
>
> --
> Sean Whitton
>

--000000000000eca7890649ff3f4e
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto"><div>Seems like my patch is too naive regarding wide char=
s. Gotta fix that. What&#39;s the recommended way to iterate such strings i=
n C code?</div><div><br></div><div data-smartmail=3D"gmail_signature">Jo=C3=
=A3o T=C3=A1vora</div></div><br><div class=3D"gmail_quote gmail_quote_conta=
iner"><div dir=3D"ltr" class=3D"gmail_attr">On Wed, Feb 4, 2026, 12:46 Sean=
 Whitton &lt;<a href=3D"mailto:spwhitton@HIDDEN">spwhitton@spwhitto=
n.name</a>&gt; wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"m=
argin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left=
:1ex">Hello,<br>
<br>
I&#39;ve identified a regression.<br>
When I use org-refile the candidates list can get stuck and<br>
icomplete-forward-completions and icomplete-backward-completions stop<br>
working.<br>
<br>
I try to type &quot;Debiandevel&quot; seeking to match &quot;Debian.org/Dev=
elopment&quot;.<br>
I get an error in *Messages*.=C2=A0 I&#39;ve pared down the CC list because=
 it<br>
contains personal information; please take care when replying:<br>
<br>
Error in post-command-hook (icomplete-post-command-hook): (error &quot;Patt=
ern Deb does not match <a href=3D"http://japanese.org/Development/Returning=
" rel=3D"noreferrer noreferrer" target=3D"_blank">japanese.org/Development/=
Returning</a> to Japanese/Ask =E7=9F=B3=E5=B7=9D=E5=85=88=E7=94=9F to send =
out advert a second time as semester begins/&quot;)<br>
completion--flex-score: Pattern Debian does not match RepeatedTasks.org/=E6=
=AF=8E=E6=97=A5=E3=81=AE=E3=82=A2=E3=82=B8=E3=82=A2=E8=AA=9E/Anki reviews (=
after back on basic kanji, I think)/ [12 times]<br>
<br>
-- <br>
Sean Whitton<br>
</blockquote></div>

--000000000000eca7890649ff3f4e--




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at 80323 <at> debbugs.gnu.org:


Received: (at 80323) by debbugs.gnu.org; 3 Feb 2026 13:51:57 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Feb 03 08:51:57 2026
Received: from localhost ([127.0.0.1]:45114 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnGov-0008Fs-8K
	for submit <at> debbugs.gnu.org; Tue, 03 Feb 2026 08:51:57 -0500
Received: from sendmail.purelymail.com ([34.202.193.197]:48284)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <spwhitton@HIDDEN>)
 id 1vnGot-0008FE-4s
 for 80323 <at> debbugs.gnu.org; Tue, 03 Feb 2026 08:51:56 -0500
DKIM-Signature: a=rsa-sha256;
 b=N00y2v7YqBCUmuJX+FgB1ZurQI25aYJLqaAfS2slTifGxYwPgVBbL/ecIIxf0nggddYL5qEf6Fm4ZfmUulaGsHbbQmDejO+PZOyts/ubH9ZY9MIu0NnSsN4z+R37/E8tqOgjMg3uS15RU5Y5WxJ50T8tgpTXA6F9wuD2QjNpwsh0P7oYD41sax4dxI/zEFAk1bBtP3qj1yn4OGRzq89yEABGeMTnaNVX7QutbQRA7GA0L8JICWyiEo+1pM2WjlbI80T4oiKSWplWXrw5oSdf0oDh/2Y2gKJ024PAcM7o5RC4Fb+Iam97MoQZsAZRPLVUrn07QpW7uVxei76+Wb3qnQ==;
 s=purelymail2; d=spwhitton.name; v=1;
 bh=17csVbrBLSxFgQf3CfqNcrOIk2n9M7Ec02yOVVflPm8=;
 h=Received:Received:From:To:Subject:Date; 
DKIM-Signature: a=rsa-sha256;
 b=qGVdCZtbGMJOUKFH6XsQTgji5SPPgqK5bFWgE2lB9c5xT2eNMXtSgnKaj8J9034eVhKMlj6ybzp6HUUpLcBqkJlUOicstA/GVC+UV7eUkmdDFgGwvqyI1G5iZgh2nLfePSEmgXuilxv44AWHLG5aOcxm9mpSqsOJiNPLbwSy5b5LQa8Ny7HZGMb3UB1Rl4x2YOdLSCzMqexShyGyDX8hsTWsn8OMcS60PiX6m4Jj5ytsG496B/duwnJUoGyyncu+TEw0slzN8/q5BHYGxmLXXg0OudAoTQJKB3Ow3Co5q79MWjROCeklyLrgu/08Sa7CT0C7dXQYQbgDV90Q3JVzBA==;
 s=purelymail2; d=purelymail.com; v=1;
 bh=17csVbrBLSxFgQf3CfqNcrOIk2n9M7Ec02yOVVflPm8=;
 h=Feedback-ID:Received:Received:From:To:Subject:Date; 
Feedback-ID: 20115:3760:null:purelymail
X-Pm-Original-To: 80323 <at> debbugs.gnu.org
Received: by smtp.purelymail.com (Purelymail SMTP) with ESMTPSA id 600957282; 
 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384);
 Tue, 03 Feb 2026 13:51:46 +0000 (UTC)
Received: by melete.silentflame.com (Postfix, from userid 1000)
 id 7A80C7E018C; Tue, 03 Feb 2026 13:51:45 +0000 (GMT)
From: Sean Whitton <spwhitton@HIDDEN>
To: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
Subject: Re: bug#80323: [PATCH] Rewrite flex completion scoring with Gotoh
 algorithm
In-Reply-To: <87y0la2egy.fsf@HIDDEN>
References: <87y0la2egy.fsf@HIDDEN>
Date: Tue, 03 Feb 2026 13:51:45 +0000
Message-ID: <87ms1q9bpq.fsf@HIDDEN>
User-Agent: Gnus/5.13 (Gnus v5.13)
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 80323
Cc: axel@HIDDEN, 80323 <at> debbugs.gnu.org, monnier@HIDDEN
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Hello,

Jo=C3=A3o T=C3=A1vora [03/Feb 12:34pm GMT] wrote:
> The greedy regexp matching, broken scoring and broken highlight were
> sources of frequent complaints about the 'flex' completion style.  The
> origin flex, created by me, was a naive half-decent algorithm to score
> so-called PCM pattern matches on completion candidates, to emulate the
> fuzzy searches found ubiqutously in the wild.  It served me and maybe
> others well for a number of years, but the annoyances are very real.
>
> The patch I'm attaching fixes them for good.

Thanks.  I use flex, so I'll install this locally right away, and see if
I notice any anomalies over the next few weeks.

Other people would be better qualified to comment on the implementation.

--=20
Sean Whitton




Information forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 3 Feb 2026 12:34:29 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Feb 03 07:34:29 2026
Received: from localhost ([127.0.0.1]:44122 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1vnFbw-0001Uy-1f
	for submit <at> debbugs.gnu.org; Tue, 03 Feb 2026 07:34:29 -0500
Received: from lists.gnu.org ([2001:470:142::17]:38226)
 by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.84_2) (envelope-from <joaotavora@HIDDEN>)
 id 1vnFbt-0001Ui-BQ
 for submit <at> debbugs.gnu.org; Tue, 03 Feb 2026 07:34:26 -0500
Received: from eggs.gnu.org ([2001:470:142:3::10])
 by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256)
 (Exim 4.90_1) (envelope-from <joaotavora@HIDDEN>)
 id 1vnFbm-0007QE-NU
 for bug-gnu-emacs@HIDDEN; Tue, 03 Feb 2026 07:34:18 -0500
Received: from mail-wm1-x32a.google.com ([2a00:1450:4864:20::32a])
 by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)
 (Exim 4.90_1) (envelope-from <joaotavora@HIDDEN>)
 id 1vnFbj-0001if-VM
 for bug-gnu-emacs@HIDDEN; Tue, 03 Feb 2026 07:34:18 -0500
Received: by mail-wm1-x32a.google.com with SMTP id
 5b1f17b1804b1-47ee07570deso46765355e9.1
 for <bug-gnu-emacs@HIDDEN>; Tue, 03 Feb 2026 04:34:15 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=gmail.com; s=20230601; t=1770122054; x=1770726854; darn=gnu.org;
 h=content-transfer-encoding:mime-version:message-id:date:subject:to
 :from:from:to:cc:subject:date:message-id:reply-to;
 bh=w6WT4OyJPCnljCKH1DlR7raevSQZRr7h99rfQ1Kw4lM=;
 b=dP4ZQgF6Jrp2fcUCo1KpQycI8h7ej+kHsI9Odqvll2tmjpYmElV2OixhZi0j1cp+6u
 URqj9saGCTX8CpKlHBnEjWkmPBFMIwbWDLS8DS8S7UkJI+rKW7368svx91rVnLVb/C0N
 +jzP8qzfTwvHwvJrbDDU+clDe34zGa7rpOIikyS3UfTk8zFDGC05yF4U+vh2Si+zJIZs
 qvm61Q8HKPNzu8L2rvW494J89sXxBd5qiEL+Mzd1WNm6+5ojRUTp9fBtzqRjFnJGgS5D
 x3JcHazzHjvjITougG7XhyqDvumdfUayWlJdyXAl4xdUqhX5mgunHv1YaJXCwZ27afX8
 3g5w==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20230601; t=1770122054; x=1770726854;
 h=content-transfer-encoding:mime-version:message-id:date:subject:to
 :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id
 :reply-to;
 bh=w6WT4OyJPCnljCKH1DlR7raevSQZRr7h99rfQ1Kw4lM=;
 b=BL7jMiFkRwwSr9p04XkFHoxX7SCqyUxfn20/KpQWJFDt88qBmkENoXIy5bUJipbWfh
 tUX8tbd6ZfPef5DYslVLs+RZBbg5Ml7FTRjYcUCTwnUYB1hiRysFp6nC4KEecgXVDVs/
 dV1E6ldoZICmmfK6V5pNZnOTW9rmTT1ber/cVcxCXyULAJYpGUr7yDtajf/wgOrCPQGX
 QnrT5SAeSpBER4IMle9vbuNvUsf0+NmUSJPIM+MoaxOoBhvbJbgLv7drqPyuaWqUrXvf
 OWK1+XxX8CpJGJo57gUzV3FNUBcSSbo2pbXEgCkbXHKNn2bvIon68WwIC9Y6SMgegTMD
 xLHA==
X-Gm-Message-State: AOJu0YzA/0UXT8llC16tTUKZXVTmuRrHmX9DvjTmfIAfBKFzVgNZLYSA
 JUulVqUjNncCBkDdHKAWAP3HWO7JBt729qC/lc2fEG6EU8vxnI4QehXu
X-Gm-Gg: AZuq6aKR+997W+GpJH79PDpwLmq0O6jtku5IvZGZqC6mwI7r2iLx4bnXpTQcJTYhIao
 JP4FsCx0ou0mi8I4DIudzFffqfOvM4jVM8fzyuhIGdBt3zXhMHRTImqyHtmn9SiR93YHHpORvp9
 DfDB2JvNh6AdV+Fvt4cY32m3X1/w2C/B2P3S6TWSzPsDOeiusGOu0pepSZtUDrSNVZ916Kfsnli
 Dkn190gafrDyfOJSD8hT8EiemR8KkTdoF4fHClMsDYptPiIeh7YB4DvVA1sQBkXolktRRtrRxQv
 xR+556GzCCUpZHYLuqQzUF+hUD2Il4Pu6agtDtUo5WtMizte6pRs0GbJ40wKrn5UlDFzPyZO2T2
 iLe3XQwjteL9bxYWRvjPfXOOMmAQfv5CdxEAl7EZT3+9AY4CAdhDct998ES0ZlhCdEtYYUE7JJj
 +z9pydDxl0I1qzCEdmKZlQkp48wA==
X-Received: by 2002:a05:600c:3155:b0:47e:e9bf:dd8a with SMTP id
 5b1f17b1804b1-482db4b5a1dmr186768915e9.37.1770122053393; 
 Tue, 03 Feb 2026 04:34:13 -0800 (PST)
Received: from krug (87-196-74-61.net.novis.pt. [87.196.74.61])
 by smtp.gmail.com with ESMTPSA id
 ffacd0b85a97d-436143d81desm3657235f8f.42.2026.02.03.04.34.11
 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
 Tue, 03 Feb 2026 04:34:12 -0800 (PST)
From: =?utf-8?B?Sm/Do28gVMOhdm9yYQ==?= <joaotavora@HIDDEN>
To: bug-gnu-emacs@HIDDEN, monnier@HIDDEN, axel@HIDDEN
Subject: [PATCH] Rewrite flex completion scoring with Gotoh algorithm
Date: Tue, 03 Feb 2026 12:34:05 +0000
Message-ID: <87y0la2egy.fsf@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass client-ip=2a00:1450:4864:20::32a;
 envelope-from=joaotavora@HIDDEN; helo=mail-wm1-x32a.google.com
X-Spam_score_int: -20
X-Spam_score: -2.1
X-Spam_bar: --
X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1,
 DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001,
 RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001,
 SPF_PASS=-0.001 autolearn=ham autolearn_force=no
X-Spam_action: no action
X-Spam-Score: 2.0 (++)
X-Spam-Report: Spam detection software, running on the system "debbugs.gnu.org",
 has NOT identified this incoming email as spam.  The original
 message has been attached to this so you can view it or label
 similar future email.  If you have any questions, see
 the administrator of that system for details.
 Content preview:  Hi, The greedy regexp matching, broken scoring and broken
 highlight were sources of frequent complaints about the 'flex' completion
 style. The origin flex, created by me, was a naive half-decent algorithm [...]
 Content analysis details:   (2.0 points, 10.0 required)
 pts rule name              description
 ---- ---------------------- --------------------------------------------------
 -0.0 SPF_HELO_PASS          SPF: HELO matches SPF record
 -0.0 RCVD_IN_DNSWL_NONE     RBL: Sender listed at https://www.dnswl.org/,
 no trust [2001:470:142:0:0:0:0:17 listed in] [list.dnswl.org]
 0.0 FREEMAIL_FROM          Sender email is commonly abused enduser mail
 provider (joaotavora[at]gmail.com)
 1.0 SPF_SOFTFAIL           SPF: sender does not match SPF record (softfail)
 1.0 FORGED_GMAIL_RCVD      'From' gmail.com does not match 'Received'
 headers
X-Debbugs-Envelope-To: submit
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: 1.0 (+)

Hi,

The greedy regexp matching, broken scoring and broken highlight were
sources of frequent complaints about the 'flex' completion style.  The
origin flex, created by me, was a naive half-decent algorithm to score
so-called PCM pattern matches on completion candidates, to emulate the
fuzzy searches found ubiqutously in the wild.  It served me and maybe
others well for a number of years, but the annoyances are very real.

The patch I'm attaching fixes them for good.

It was inspired by the 'hotfuzz' style available at
https://github.com/axelf4/hotfuzz which a modified version of Gotoh's
1982 dynamic programming algorithm (see: GOTOH, Osamu. An improved
algorithm for matching biological sequences. Journal of molecular
biology, 1982, 162.3: 705-708.).  That style is more sophisticated than
'flex' (has special rules for matching things at word boundaries, a C
module with multhreading support).  It's _almost_ void of hacks or
problems (see [1]) so its code would make a good candidate to replace
'flex' entirely, but no progress has been made in getting it into
Emacs's core in over 2 years...

The new 'flex' implementation also uses the Gotoh algorithm (apparently
a common choice for these kinds of task) and happens mostly in a new C
function.  The algorithm isn't easy to understand, and I'm not a
mathematician, so at a certain point I was coding it a bit on a
trial-and-error basis.  But it can be understood with some effort, and
at age 44 it's not exactly a revolutionary approach.  I can add source
code comments to clear up any doubts about how it works.

This is strictly better than the "old" flex in correctness.  For
example, when matching the pattern "goto" to, say, "eglot--goto" and
"eglot--bol", no longer is the latter returned first, which was a
substantial annoyance.  And of course the highlighting is also correctly
placed on the "goto" not scattered in the main string.

Regarding performance, it seems to be slightly slower than the naive
Elisp 'flex'.  It seems to be on-par with 'hotfuzz', if not slightly
faster.  The reason I write "seems" is that it isn't easy at all to
benchmark styles.  There's no single function to call that will show how
fast a given style matches, sorts and highlights when used via a
real-world frontend.  A possible way is to place a 'benchmark-progn'
inside a completion frontend, like in icomplete.el's call to
'completion-all-sorted-completions'.  But I can provide some naive
benchmark code too.

There may still be some speed improvements that can be made, like not
backtracking to understand the matching path when it isn't needed.  And
perhaps other clever ones.  In regards to memory usage it could also use
slightly smaller tables (currently three 64K float matrixes are used).
Although this uses statically allocated arrays already, so I thought
it's best to keep it relatively simple.

[1]: https://github.com/axelf4/hotfuzz/issues/16#issuecomment-2091181666

Jo=C3=A3o

And now the patch

* src/minibuf.c (completion--flex-score-gotoh): New function.
Implement Gotoh algorithm with dynamic programming to compute
optimal alignment score and match positions.
(syms_of_minibuf): Tweak.
(math.h): Include.

* lisp/minibuffer.el (completion--flex-score): Rework extensively.
Return (score . matches) without side effects.
(completion--flex-propertize): New function.  Handle face
propertization with proper segment-based position calculation.
(completion--highlight-from-re): Delete.
(flex-score-match-tightness): Obsolete.
(completion-pcm--hilit-commonality): Rework. No longer use regular
expressions at all.
(completion-flex--make-flex-pattern): Extract score from cons before
negating for sort.

* test/lisp/minibuffer-tests.el (completion--pcm-score): Update to
extract score from cons return value.  (completion-pcm-test-4): Remove
unreasonable scoring expectation from old flex

diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index fc193fe54f0..088297b3f45 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -4450,18 +4450,12 @@ completion-pcm--all-completions
 	    (when (string-match-p regex c) (push c poss)))
 	  (nreverse poss))))))
=20
-(defvar flex-score-match-tightness 3
-  "Controls how the `flex' completion style scores its matches.
-
-Value is a positive number.  A number smaller than 1 makes the
-scoring formula reward matches scattered along the string, while
-a number greater than one make the formula reward matches that
-are clumped together.  I.e \"foo\" matches both strings
-\"fbarbazoo\" and \"fabrobazo\", which are of equal length, but
-only a value greater than one will score the former (which has
-one large \"hole\" and a clumped-together \"oo\" match) higher
-than the latter (which has two \"holes\" and three
-one-letter-long matches).")
+(defvar flex-score-match-tightness nil)
+
+(make-obsolete-variable
+ 'flex-score-match-tightness
+ "It never did anything very useful anyway."
+ "31.0")
=20
 (defvar completion-lazy-hilit nil
   "If non-nil, request lazy highlighting of completion candidates.
@@ -4502,133 +4496,45 @@ completion-lazy-hilit
       (funcall completion-lazy-hilit-fn (copy-sequence str))
     str))
=20
-(defun completion--hilit-from-re (string regexp &optional point-idx)
-  "Fontify STRING using REGEXP POINT-IDX.
-Uses `completions-common-part' and `completions-first-difference'
-faces to fontify STRING.
-POINT-IDX is the position of point in the presumed \"PCM\" pattern
-from which REGEXP was generated."
-  (let* ((md (and regexp (string-match regexp string) (cddr (match-data t)=
)))
-         (pos (if point-idx (match-beginning point-idx) (match-end 0)))
-         (me (and md (match-end 0)))
-         (from 0))
-    (while md
-      (add-face-text-property from (pop md)
-                              'completions-common-part nil string)
-      (setq from (pop md)))
-    (if (and (numberp pos) (> (length string) pos))
-        (add-face-text-property
-         pos (1+ pos)
-         'completions-first-difference
-         nil string))
-    (unless (or (not me) (=3D from me))
-      (add-face-text-property from me 'completions-common-part nil string))
-    string))
-
-(defun completion--flex-score-1 (md-groups match-end len)
-  "Compute matching score of completion.
-The score lies in the range between 0 and 1, where 1 corresponds to
-the full match.
-MD-GROUPS is the \"group\"  part of the match data.
-MATCH-END is the end of the match.
-LEN is the length of the completion string."
-  (let* ((from 0)
-         ;; To understand how this works, consider these simple
-         ;; ascii diagrams showing how the pattern "foo"
-         ;; flex-matches "fabrobazo", "fbarbazoo" and
-         ;; "barfoobaz":
-
-         ;;      f abr o baz o
-         ;;      + --- + --- +
-
-         ;;      f barbaz oo
-         ;;      + ------ ++
-
-         ;;      bar foo baz
-         ;;          +++
-
-         ;; "+" indicates parts where the pattern matched.  A
-         ;; "hole" in the middle of the string is indicated by
-         ;; "-".  Note that there are no "holes" near the edges
-         ;; of the string.  The completion score is a number
-         ;; bound by (0..1] (i.e., larger than (but not equal
-         ;; to) zero, and smaller or equal to one): the higher
-         ;; the better and only a perfect match (pattern equals
-         ;; string) will have score 1.  The formula takes the
-         ;; form of a quotient.  For the numerator, we use the
-         ;; number of +, i.e. the length of the pattern.  For
-         ;; the denominator, it first computes
-         ;;
-         ;;     hole_i_contrib =3D 1 + (Li-1)^(1/tightness)
-         ;;
-         ;; , for each hole "i" of length "Li", where tightness
-         ;; is given by `flex-score-match-tightness'.  The
-         ;; final value for the denominator is then given by:
-         ;;
-         ;;    (SUM_across_i(hole_i_contrib) + 1) * len
-         ;;
-         ;; , where "len" is the string's length.
-         (score-numerator 0)
-         (score-denominator 0)
-         (last-b 0))
-    (while (and md-groups (car md-groups))
-      (let ((a from)
-            (b (pop md-groups)))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b))
-      (setq from (pop md-groups)))
-    ;; If `pattern' doesn't have an explicit trailing any, the
-    ;; regex `re' won't produce match data representing the
-    ;; region after the match.  We need to account to account
-    ;; for that extra bit of match (bug#42149).
-    (unless (=3D from match-end)
-      (let ((a from)
-            (b match-end))
-        (setq
-         score-numerator   (+ score-numerator (- b a)))
-        (unless (or (=3D a last-b)
-                    (zerop last-b)
-                    (=3D a len))
-          (setq
-           score-denominator (+ score-denominator
-                                1
-                                (expt (- a last-b 1)
-                                      (/ 1.0
-                                         flex-score-match-tightness)))))
-        (setq
-         last-b              b)))
-    (/ score-numerator (* len (1+ score-denominator)) 1.0)))
-
-(defvar completion--flex-score-last-md nil
-  "Helper variable for `completion--flex-score'.")
-
-(defun completion--flex-score (str re &optional dont-error)
-  "Compute flex score of completion STR based on RE.
-If DONT-ERROR, just return nil if RE doesn't match STR."
-  (let ((case-fold-search completion-ignore-case))
-    (cond ((string-match re str)
-           (let* ((match-end (match-end 0))
-                  (md (cddr
-                       (setq
-                        completion--flex-score-last-md
-                        (match-data t completion--flex-score-last-md)))))
-             (completion--flex-score-1 md match-end (length str))))
-          ((not dont-error)
-           (error "Internal error: %s does not match %s" re str)))))
-
-(defvar completion-pcm--regexp nil
-  "Regexp from PCM pattern in `completion-pcm--hilit-commonality'.")
+(cl-defun completion--flex-score (pat str &optional dont-error)
+  "Compute flex score of STR matching PAT.  If DONT-ERROR,
+return nil if PAT cannot match STR.  Returns (SCORE . MATCHES) where
+SCORE is a float and MATCHES is a list of match positions in STR."
+  (or (completion--flex-score-gotoh pat str)
+      (unless dont-error
+        (error "Pattern %s does not match %s" pat str))))
+
+(defun completion--flex-propertize (str matches point-idx segments)
+  "Add completion faces to STR based on MATCHES and POINT-IDX.
+MATCHES is a list of match positions.  POINT-IDX is a match group index
+from the PCM pattern.  SEGMENTS are extracted from the full PCM pattern.
+Adds `completions-common-part' for matched positions and
+`completions-first-difference' for the position corresponding to point."
+  (when point-idx
+    ;; Compute character position from segments
+    (let* ((pos (cl-loop for seg in segments
+                         for i from 1
+                         while (<=3D i point-idx)
+                         sum (length (car seg)))))
+      ;; Add first-difference after pos-th match, if in range
+      (let ((point-match (and (> pos 0)
+                              (<=3D pos (length matches))
+                              (nth (1- pos) matches))))
+        (when (and point-match (< (1+ point-match) (length str)))
+          (add-face-text-property
+           (1+ point-match) (+ 2 point-match)
+           'completions-first-difference nil str)))))
+  ;; Highlight matched positions
+  (dolist (pos matches)
+    (add-face-text-property pos (1+ pos)
+                           'completions-common-part
+                           nil str))
+  str)
+
+(defvar completion-flex--pattern-str nil
+  "Pattern string for flex completion scoring.
+This is the concatenated string parts from the PCM pattern,
+used by `completion--flex-score' for Gotoh algorithm matching.")
=20
 (defun completion-pcm--hilit-commonality (pattern completions)
   "Show where and how well PATTERN matches COMPLETIONS.
@@ -4645,22 +4551,37 @@ completion-pcm--hilit-commonality
 Else, if `completion-lazy-hilit' is t, return COMPLETIONS
 unchanged, but setup a suitable `completion-lazy-hilit-fn' (which
 see) for later lazy highlighting."
-  (setq completion-pcm--regexp nil
-        completion-lazy-hilit-fn nil)
+  (setq completion-lazy-hilit-fn nil
+        completion-flex--pattern-str nil)
   (cond
    ((and completions (cl-loop for e in pattern thereis (stringp e)))
     (let* ((segments (completion-pcm--pattern->segments pattern))
-           (re (completion-pcm--segments->regex segments 'group))
-           (point-idx (completion-pcm--segments-point-idx segments)))
-      (setq completion-pcm--regexp re)
+           (point-idx (completion-pcm--segments-point-idx segments))
+           ;; Extract pattern string (concatenate string elements)
+           (pat (mapconcat #'identity
+                           (delq nil (mapcar (lambda (x)
+                                               (if (stringp x) x nil))
+                                             pattern))
+                           "")))
+      (setq completion-flex--pattern-str pat)
       (cond (completion-lazy-hilit
              (setq completion-lazy-hilit-fn
-                   (lambda (str) (completion--hilit-from-re str re point-i=
dx)))
+                   (lambda (str)
+                     (let ((result (completion--flex-score pat str t)))
+                       (when result
+                         (completion--flex-propertize
+                          str (cdr result) point-idx segments)))
+                     str))
              completions)
             (t
              (mapcar
               (lambda (str)
-                (completion--hilit-from-re (copy-sequence str) re point-id=
x))
+                (setq str (copy-sequence str))
+                (let ((result (completion--flex-score pat str t)))
+                  (when result
+                    (completion--flex-propertize
+                     str (cdr result) point-idx segments)))
+                str)
               completions)))))
    (t completions)))
=20
@@ -5009,7 +4930,7 @@ completion-flex-nospace
=20
 (defun completion--flex-adjust-metadata (metadata)
   "If `flex' is actually doing filtering, adjust sorting."
-  (let ((flex-is-filtering-p completion-pcm--regexp)
+  (let ((flex-is-filtering-p completion-flex--pattern-str)
         (existing-dsf
          (completion-metadata-get metadata 'display-sort-function))
         (existing-csf
@@ -5021,11 +4942,11 @@ completion--flex-adjust-metadata
                              (mapcar
                               (lambda (str)
                                 (cons
-                                 (- (completion--flex-score
-                                     (or (get-text-property
-                                          0 'completion--unquoted str)
-                                         str)
-                                     completion-pcm--regexp))
+                                 (- (car (completion--flex-score
+                                          completion-flex--pattern-str
+                                          (or (get-text-property
+                                               0 'completion--unquoted str)
+                                              str))))
                                  str))
                               (if existing-sort-fn
                                   (funcall existing-sort-fn completions)
diff --git a/src/minibuf.c b/src/minibuf.c
index 5dc2b230883..16d30307ed4 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -20,6 +20,7 @@ Copyright (C) 1985-1986, 1993-2026 Free Software Foundati=
on, Inc.
=20
 #include <config.h>
 #include <errno.h>
+#include <math.h>
=20
 #include <binary-io.h>
=20
@@ -2279,6 +2280,143 @@ init_minibuf_once_for_pdumper (void)
   last_minibuf_string =3D Qnil;
 }
=20
+/* Pre-allocated matrices for flex completion scoring.  */
+#define FLEX_MAX_MATRIX_SIZE 65536
+
+static double flex_M[FLEX_MAX_MATRIX_SIZE];
+static double flex_D[FLEX_MAX_MATRIX_SIZE];
+static ptrdiff_t flex_P[FLEX_MAX_MATRIX_SIZE];
+
+DEFUN ("completion--flex-score-gotoh", Fcompletion__flex_score_gotoh,
+       Scompletion__flex_score_gotoh, 2, 2, 0,
+       doc: /* Compute flex score of STR matching PAT using Gotoh algorith=
m.
+Returns a list (SCORE MATCHES) where SCORE is a float and MATCHES
+is a list of match positions in STR, or nil if no valid score.  */)
+  (Lisp_Object pat, Lisp_Object str)
+{
+  CHECK_STRING (pat);
+  CHECK_STRING (str);
+
+  ptrdiff_t m =3D SCHARS (pat);
+  ptrdiff_t n =3D SCHARS (str);
+
+  /* Bail if strings are empty or matrix too large.  */
+  if (m =3D=3D 0 || n =3D=3D 0)
+    return Qnil;
+
+  ptrdiff_t width =3D n + 1;
+  ptrdiff_t size =3D (m + 1) * width;
+
+  if (size > FLEX_MAX_MATRIX_SIZE)
+    return Qnil;
+
+  /* Extract string data.  */
+  unsigned char *pat_data =3D SDATA (pat);
+  unsigned char *str_data =3D SDATA (str);
+
+  /* Scoring constants.  */
+  const double match_score =3D 1.0;
+  const double gap_extend =3D -0.05;
+  const double gap_open =3D -0.1;
+  const double neg_inf =3D -INFINITY;
+
+  /* Macro for 2D indexing into flat arrays.  */
+  #define MAT(matrix, i, j) ((matrix)[((i) + 1) * width + ((j) + 1)])
+
+  /* Initialize matrices with neg_inf and -1.  */
+  for (ptrdiff_t idx =3D 0; idx < size; idx++)
+    {
+      flex_M[idx] =3D neg_inf;
+      flex_D[idx] =3D neg_inf;
+      flex_P[idx] =3D -1;
+    }
+
+  /* Base case: can start matching at any position in str (free leading ga=
p).
+     Initialize first row of D (row -1) to 0.0.  */
+  for (ptrdiff_t j =3D 0; j < width; j++)
+    flex_D[j] =3D 0.0;
+
+  /* Forward pass - compute M and D matrices.  */
+  for (ptrdiff_t i =3D 0; i < m; i++)
+    {
+      unsigned char pat_char =3D pat_data[i];
+
+      for (ptrdiff_t j =3D 0; j < n; j++)
+        {
+          unsigned char str_char =3D str_data[j];
+
+          /* Compute gap score D[i][j].  */
+          double from_match =3D MAT (flex_M, i, j - 1) + gap_open;
+          double from_gap =3D MAT (flex_D, i, j - 1) + gap_extend;
+          MAT (flex_D, i, j) =3D fmax (from_match, from_gap);
+
+          /* Check if characters match (case-insensitive if needed).  */
+          bool chars_match;
+          if (completion_ignore_case)
+            chars_match =3D (downcase (pat_char) =3D=3D downcase (str_char=
));
+          else
+            chars_match =3D (pat_char =3D=3D str_char);
+
+          /* Compute match score M[i][j].  */
+          if (chars_match)
+            {
+              double prev_match =3D MAT (flex_M, i - 1, j - 1);
+              double prev_gap =3D MAT (flex_D, i - 1, j - 1);
+
+              if (prev_match >=3D prev_gap)
+                {
+                  MAT (flex_M, i, j) =3D prev_match + match_score;
+                  MAT (flex_P, i, j) =3D j - 1;
+                }
+              else
+                {
+                  MAT (flex_M, i, j) =3D prev_gap + match_score;
+                  /* Find gap origin.  */
+                  ptrdiff_t gap_origin =3D j - 1;
+                  while (gap_origin >=3D 0
+                         && MAT (flex_M, i - 1, gap_origin) < MAT (flex_D,=
 i - 1, gap_origin))
+                    gap_origin--;
+                  MAT (flex_P, i, j) =3D gap_origin;
+                }
+            }
+        }
+    }
+
+  /* Find best score in last row.  */
+  double best_score =3D neg_inf;
+  ptrdiff_t lastcol =3D -1;
+
+  for (ptrdiff_t j =3D 0; j < n; j++)
+    {
+      double score =3D MAT (flex_M, m - 1, j);
+      if (score > best_score)
+        {
+          best_score =3D score;
+          lastcol =3D j;
+        }
+    }
+
+  if (lastcol < 0 || isinf (best_score))
+    return Qnil;
+
+  /* Normalize score to penalize longer strings and gap penalties.  */
+  double normalized_score =3D (double) m / ((double) n * (1.0 + ((double) =
m - best_score)));
+
+  /* Build match positions list by tracing back through P matrix.  */
+  Lisp_Object matches =3D Qnil;
+  ptrdiff_t k =3D lastcol;
+
+  for (ptrdiff_t i =3D m - 1; i >=3D 0 && k >=3D 0; i--)
+    {
+      matches =3D Fcons (make_fixnum (k), matches);
+      k =3D MAT (flex_P, i, k);
+    }
+
+  #undef MAT
+
+  return Fcons (make_float (normalized_score), matches);
+}
+
 void
 syms_of_minibuf (void)
 {
@@ -2541,6 +2679,7 @@ syms_of_minibuf (void)
   defsubr (&Stest_completion);
   defsubr (&Sassoc_string);
   defsubr (&Scompleting_read);
+  defsubr (&Scompletion__flex_score_gotoh);
   DEFSYM (Qminibuffer_quit_recursive_edit, "minibuffer-quit-recursive-edit=
");
   DEFSYM (Qinternal_complete_buffer, "internal-complete-buffer");
   DEFSYM (Qcompleting_read_function, "completing-read-function");
diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el
index 79ffb1d3fc7..9f25ec1e78c 100644
--- a/test/lisp/minibuffer-tests.el
+++ b/test/lisp/minibuffer-tests.el
@@ -208,7 +208,7 @@ completion-all-sorted-completions
 (defun completion--pcm-score (comp)
   "Get `completion-score' from COMP."
   ;; FIXME, uses minibuffer.el implementation details
-  (completion--flex-score comp completion-pcm--regexp))
+  (car (completion--flex-score completion-flex--pattern-str comp)))
=20
 (defun completion--pcm-first-difference-pos (comp)
   "Get `completions-first-difference' from COMP."
@@ -252,12 +252,7 @@ completion-pcm-test-3
            1.0)))
=20
 (ert-deftest completion-pcm-test-4 ()
-  ;; One fourth of a match and no match due to point being at the end
-  (should (eql
-           (completion--pcm-score
-            (car (completion-pcm-all-completions
-                  "RO" '("RaOb") nil 1)))
-           (/ 1.0 4.0)))
+  ;; No match due to point being at the end
   (should (null
            (completion-pcm-all-completions
             "RO" '("RaOb") nil 2))))




Acknowledgement sent to João Távora <joaotavora@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs@HIDDEN. Full text available.
Report forwarded to bug-gnu-emacs@HIDDEN:
bug#80323; Package emacs. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Sun, 8 Feb 2026 17:00:03 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.