Perform subsequence fuzzy matching (UTF-8 aware, ASCII case-folding).
Performs byte-wise subsequence matching with ASCII-only case folding. UTF-8 multi-byte sequences are preserved but matched as raw bytes. Only ASCII A-Z characters are case-folded to a-z.
264{
266 return -1;
267
268 size_t plen = strlen(pattern);
269 if (plen == 0)
270 return -1;
271
275
276 if (plen > (size_t) max_pattern)
277 return -1;
278
280
282
283 int pi = 0;
284 int ci = 0;
285 int score = 0;
286
287 int first = -1;
288 int last = -1;
289
290
292 {
293 const unsigned char pbyte = (unsigned char) pattern[pi];
294 if (pbyte < 0x80)
295 {
296 int pc =
lower_if(pattern[pi], fold);
298
299 if (pc == cc)
300 {
301 matchpos[pi] = ci;
302
303 if (first < 0)
304 first = ci;
305
306 last = ci;
307 pi++;
308 }
309
310 ci++;
311 continue;
312 }
313
314
316 const int premaining = (int) plen - pi;
317 if ((pchar_len <= 0) || (pchar_len > premaining))
318 return -1;
319 bool matched = false;
320
322 {
323 const unsigned char cbyte = (
unsigned char)
candidate[ci];
325 {
326 ci++;
327 continue;
328 }
329
331 if ((pchar_len == cchar_len) && (memcmp(pattern + pi,
candidate + ci, pchar_len) == 0))
332 {
333 for (int k = 0; k < pchar_len; k++)
334 {
335 const int match_idx = pi + k;
337 return -1;
338 matchpos[match_idx] = ci + k;
339 }
340
341 if (first < 0)
342 first = ci;
343
344 last = ci + pchar_len - 1;
345 pi += pchar_len;
346 ci += cchar_len;
347 matched = true;
348 break;
349 }
350
351 ci += cchar_len;
352 }
353
354 if (!matched)
355 break;
356 }
357
358 if (pi != (int) plen)
359 return -1;
360
361
362
363
364 score += plen * 10;
365
366
367 for (int i = 1; i < pi; i++)
368 {
369 int gap = matchpos[i] - matchpos[i - 1] - 1;
370
371 if (gap == 0)
372 score += 15;
373 else
374 score -= gap * 2;
375 }
376
377
378 int span = last - first + 1;
379 score -= span;
380
381
383 score += 40;
384
385
386 for (int i = 0; i < pi; i++)
387 {
388 int pos = matchpos[i];
389
390 if (pos == 0)
391 score += 30;
392 else
393 {
394 unsigned char prev = (
unsigned char)
candidate[pos - 1];
395 unsigned char curr = (
unsigned char)
candidate[pos];
396
397
398 if ((prev == '/') || (prev == '.') || (prev == '-') || (prev == '_'))
399 score += 15;
400
401 else if (((prev >= 'a') && (prev <= 'z')) && ((curr >= 'A') && (curr <= 'Z')))
402 score += 10;
403 }
404 }
405
406
408
409
410 if (score < 0)
411 score = 0;
412
413 if (out)
414 {
419 }
420
421 return score;
422}
bool candidate(struct CompletionData *cd, char *user, const char *src, char *dest, size_t dlen)
Helper function for completion.
int max_pattern
Safety bound (<=0 = default 256, capped at 256).
bool prefer_prefix
Extra weight for prefix matches.
int score
Score (<0 = no match).
int start
First match position.
int end
Last match position.
static int utf8_char_len(const char *s)
Get length of a UTF-8 codepoint at a byte offset.
static int lower_if(int c, bool fold)
Convert character to lowercase conditionally.
static bool compute_case_mode(const char *pattern, const struct FuzzyOptions *opts)
Determine if case folding should be used.
#define DEFAULT_MAX_PATTERN
Default maximum pattern length.