Files
breadcrumb-the-shire/lib/Support/Search/SearchSpecialResourceProvider.php

251 lines
7.6 KiB
PHP
Raw Normal View History

<?php
namespace MintyPHP\Support\Search;
use MintyPHP\Service\Docs\DocsCatalogService;
use MintyPHP\Service\Ui\HotkeyService;
class SearchSpecialResourceProvider
{
private static function hotkeyEntries(): array
{
$rows = [];
foreach (HotkeyService::list() as $row) {
$actionKey = trim($row['action_key']);
$mac = trim($row['mac']);
$win = trim($row['win']);
if ($actionKey === '' || $mac === '' || $win === '') {
continue;
}
$rows[] = [
'label' => t($actionKey),
'mac' => $mac,
'win' => $win,
];
}
return $rows;
}
private static function matchesHotkeyQueryWith(string $query, array $entries): bool
{
$query = trim(mb_strtolower($query));
if ($query === '') {
return false;
}
$tokens = preg_split('/[^a-z0-9]+/i', $query);
$tokens = is_array($tokens) ? array_values(array_filter($tokens, static fn ($part): bool => $part !== '')) : [];
foreach (HotkeyService::searchKeywords() as $keywordRaw) {
$keyword = trim(mb_strtolower((string) $keywordRaw));
if ($keyword === '') {
continue;
}
if (in_array($keyword, $tokens, true)) {
return true;
}
foreach ($tokens as $token) {
if (strlen($token) >= 3 && str_starts_with($keyword, $token)) {
return true;
}
}
if (strlen($query) >= 3 && str_starts_with($keyword, $query)) {
return true;
}
}
foreach ($entries as $entry) {
$label = mb_strtolower((string) ($entry['label'] ?? ''));
$mac = mb_strtolower((string) ($entry['mac'] ?? ''));
$win = mb_strtolower((string) ($entry['win'] ?? ''));
if (($label !== '' && str_contains($label, $query))
|| ($mac !== '' && str_contains($mac, $query))
|| ($win !== '' && str_contains($win, $query))) {
return true;
}
}
return false;
}
private static function filterHotkeyEntries(string $query): array
{
$needle = trim(mb_strtolower($query));
$entries = self::hotkeyEntries();
if (!self::matchesHotkeyQueryWith($query, $entries)) {
return [];
}
if ($needle === '') {
return $entries;
}
$filtered = [];
foreach ($entries as $entry) {
$label = mb_strtolower((string) ($entry['label'] ?? ''));
$mac = mb_strtolower((string) ($entry['mac'] ?? ''));
$win = mb_strtolower((string) ($entry['win'] ?? ''));
if (str_contains($label, $needle) || str_contains($mac, $needle) || str_contains($win, $needle)) {
$filtered[] = $entry;
}
}
return $filtered;
}
public static function hotkeyPreviewResource(string $query): ?array
{
$entries = self::filterHotkeyEntries($query);
if ($entries === []) {
return null;
}
$items = [];
foreach ($entries as $entry) {
$items[] = [
'label' => trim((string) ($entry['label'] ?? '') . ' - ' . (string) ($entry['mac'] ?? '') . ' / ' . (string) ($entry['win'] ?? '')),
'url' => lurl('help/hotkeys'),
];
}
return [
'key' => 'hotkeys',
'label' => t('Keyboard shortcuts'),
'count' => count($items),
'url' => lurl('help/hotkeys'),
'items' => array_slice($items, 0, 5),
];
}
public static function hotkeyResultItems(string $query): array
{
$entries = self::filterHotkeyEntries($query);
if ($entries === []) {
return [];
}
$result = [];
foreach ($entries as $entry) {
$result[] = [
'type' => t('Keyboard shortcuts'),
'title' => (string) ($entry['label'] ?? ''),
'description' => trim((string) ($entry['mac'] ?? '') . ' / ' . (string) ($entry['win'] ?? '')),
'url' => lurl('help/hotkeys'),
'image' => '',
'icon' => 'bi-keyboard',
];
}
return $result;
}
private static function docsResultUrl(string $slug, string $anchor = ''): string
{
$url = lurl('admin/docs/' . $slug);
if ($anchor !== '') {
$url .= '#' . $anchor;
}
return $url;
}
public static function docsPreviewResource(string $query): ?array
{
$matches = DocsCatalogService::search($query);
if ($matches === []) {
return null;
}
$seenDocs = [];
$previewItems = [];
foreach ($matches as $match) {
$slug = trim((string) $match['slug']);
if ($slug === '') {
continue;
}
$seenDocs[$slug] = true;
if (isset($previewItems[$slug])) {
continue;
}
$title = trim((string) $match['title']);
if ($title === '') {
$title = $slug;
}
$section = trim((string) $match['section']);
$label = $title;
if ($section !== '' && mb_strtolower($section) !== mb_strtolower($title)) {
$label .= ' - ' . $section;
}
$previewItems[$slug] = [
'label' => $label,
'url' => self::docsResultUrl($slug, (string) $match['anchor']),
];
}
return [
'key' => 'docs',
'label' => t('Documentation'),
'count' => count($seenDocs),
'url' => lurl('admin/docs/' . DocsCatalogService::defaultSlug()) . '?search=' . urlencode($query),
'items' => array_values(array_slice($previewItems, 0, 5)),
];
}
public static function docsResultItems(string $query): array
{
$matches = DocsCatalogService::search($query);
if ($matches === []) {
return [];
}
$items = [];
foreach ($matches as $match) {
$slug = trim((string) $match['slug']);
$title = trim((string) $match['title']);
if ($slug === '' || $title === '') {
continue;
}
$section = trim((string) $match['section']);
$snippet = trim((string) $match['snippet']);
$descriptionParts = [];
if ($section !== '' && mb_strtolower($section) !== mb_strtolower($title)) {
$descriptionParts[] = $section;
}
if ($snippet !== '') {
$descriptionParts[] = $snippet;
}
$rawScore = (int) $match['score'];
$searchScore = match (true) {
$rawScore >= 1000 => 400,
$rawScore >= 900 => 360,
$rawScore >= 800 => 330,
$rawScore >= 700 => 300,
$rawScore >= 650 => 260,
$rawScore >= 600 => 230,
$rawScore >= 500 => 200,
default => 150,
};
$items[] = [
'type' => t('Documentation'),
'title' => $title,
'description' => implode(' - ', $descriptionParts),
'url' => self::docsResultUrl($slug, (string) $match['anchor']),
'image' => '',
'icon' => 'bi-journal-text',
'search_score' => $searchScore,
];
}
return $items;
}
}