mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-01 15:30:22 +00:00
refactor: dedupe core lowercase helpers
This commit is contained in:
@@ -2,6 +2,7 @@ import type { SlashCommand } from "@mariozechner/pi-tui";
|
||||
import { listChatCommands, listChatCommandsForConfig } from "../auto-reply/commands-registry.js";
|
||||
import { formatThinkingLevels, listThinkingLevelLabels } from "../auto-reply/thinking.js";
|
||||
import type { OpenClawConfig } from "../config/types.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
const VERBOSE_LEVELS = ["on", "off"];
|
||||
const FAST_LEVELS = ["status", "on", "off"];
|
||||
@@ -31,7 +32,7 @@ function createLevelCompletion(
|
||||
): NonNullable<SlashCommand["getArgumentCompletions"]> {
|
||||
return (prefix) =>
|
||||
levels
|
||||
.filter((value) => value.startsWith(prefix.toLowerCase()))
|
||||
.filter((value) => value.startsWith(normalizeLowercaseStringOrEmpty(prefix)))
|
||||
.map((value) => ({
|
||||
value,
|
||||
label: value,
|
||||
@@ -44,7 +45,7 @@ export function parseCommand(input: string): ParsedCommand {
|
||||
return { name: "", args: "" };
|
||||
}
|
||||
const [name, ...rest] = trimmed.split(/\s+/);
|
||||
const normalized = name.toLowerCase();
|
||||
const normalized = normalizeLowercaseStringOrEmpty(name);
|
||||
return {
|
||||
name: COMMAND_ALIASES[normalized] ?? normalized,
|
||||
args: rest.join(" ").trim(),
|
||||
@@ -77,7 +78,7 @@ export function getSlashCommands(options: SlashCommandOptions = {}): SlashComman
|
||||
description: "Set thinking level",
|
||||
getArgumentCompletions: (prefix) =>
|
||||
thinkLevels
|
||||
.filter((v) => v.startsWith(prefix.toLowerCase()))
|
||||
.filter((v) => v.startsWith(normalizeLowercaseStringOrEmpty(prefix)))
|
||||
.map((value) => ({ value, label: value })),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type SelectListTheme,
|
||||
} from "@mariozechner/pi-tui";
|
||||
import chalk from "chalk";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { fuzzyFilterLower, prepareSearchItems } from "./fuzzy-filter.js";
|
||||
|
||||
export interface FilterableSelectItem extends SelectItem {
|
||||
@@ -44,7 +45,7 @@ export class FilterableSelectList implements Component {
|
||||
}
|
||||
|
||||
private applyFilter(): void {
|
||||
const queryLower = this.filterText.toLowerCase();
|
||||
const queryLower = normalizeLowercaseStringOrEmpty(this.filterText);
|
||||
if (!queryLower.trim()) {
|
||||
this.selectList = new SelectList(this.allItems, this.maxVisible, this.theme);
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
* Shared fuzzy filtering utilities for select list components.
|
||||
*/
|
||||
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
|
||||
/**
|
||||
* Word boundary characters for matching.
|
||||
*/
|
||||
@@ -22,8 +24,8 @@ export function findWordBoundaryIndex(text: string, query: string): number | nul
|
||||
if (!query) {
|
||||
return null;
|
||||
}
|
||||
const textLower = text.toLowerCase();
|
||||
const queryLower = query.toLowerCase();
|
||||
const textLower = normalizeLowercaseStringOrEmpty(text);
|
||||
const queryLower = normalizeLowercaseStringOrEmpty(query);
|
||||
const maxIndex = textLower.length - queryLower.length;
|
||||
if (maxIndex < 0) {
|
||||
return null;
|
||||
@@ -133,6 +135,6 @@ export function prepareSearchItems<
|
||||
if (item.searchText) {
|
||||
parts.push(item.searchText);
|
||||
}
|
||||
return { ...item, searchTextLower: parts.join(" ").toLowerCase() };
|
||||
return { ...item, searchTextLower: normalizeLowercaseStringOrEmpty(parts.join(" ")) };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type SelectListTheme,
|
||||
truncateToWidth,
|
||||
} from "@mariozechner/pi-tui";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import { stripAnsi, visibleWidth } from "../../terminal/ansi.js";
|
||||
import { findWordBoundaryIndex, fuzzyFilterLower } from "./fuzzy-filter.js";
|
||||
|
||||
@@ -80,7 +81,7 @@ export class SearchableSelectList implements Component {
|
||||
* 4. Fuzzy match (lowest priority)
|
||||
*/
|
||||
private smartFilter(query: string): SelectItem[] {
|
||||
const q = query.toLowerCase();
|
||||
const q = normalizeLowercaseStringOrEmpty(query);
|
||||
type ScoredItem = { item: SelectItem; tier: number; score: number };
|
||||
type FuzzyCandidate = { item: SelectItem; searchTextLower: string };
|
||||
const scoredItems: ScoredItem[] = [];
|
||||
@@ -89,8 +90,8 @@ export class SearchableSelectList implements Component {
|
||||
for (const item of this.items) {
|
||||
const rawLabel = this.getItemLabel(item);
|
||||
const rawDesc = item.description ?? "";
|
||||
const label = stripAnsi(rawLabel).toLowerCase();
|
||||
const desc = stripAnsi(rawDesc).toLowerCase();
|
||||
const label = normalizeLowercaseStringOrEmpty(stripAnsi(rawLabel));
|
||||
const desc = normalizeLowercaseStringOrEmpty(stripAnsi(rawDesc));
|
||||
|
||||
// Tier 1: Exact substring in label
|
||||
const labelIndex = label.indexOf(q);
|
||||
@@ -114,11 +115,12 @@ export class SearchableSelectList implements Component {
|
||||
const searchText = (item as { searchText?: string }).searchText ?? "";
|
||||
fuzzyCandidates.push({
|
||||
item,
|
||||
searchTextLower: [rawLabel, rawDesc, searchText]
|
||||
.map((value) => stripAnsi(value))
|
||||
.filter(Boolean)
|
||||
.join(" ")
|
||||
.toLowerCase(),
|
||||
searchTextLower: normalizeLowercaseStringOrEmpty(
|
||||
[rawLabel, rawDesc, searchText]
|
||||
.map((value) => stripAnsi(value))
|
||||
.filter(Boolean)
|
||||
.join(" "),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -171,7 +173,7 @@ export class SearchableSelectList implements Component {
|
||||
const tokens = query
|
||||
.trim()
|
||||
.split(/\s+/)
|
||||
.map((token) => token.toLowerCase())
|
||||
.map((token) => normalizeLowercaseStringOrEmpty(token))
|
||||
.filter((token) => token.length > 0);
|
||||
if (tokens.length === 0) {
|
||||
return text;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
|
||||
export function createEditorSubmitHandler(params: {
|
||||
editor: {
|
||||
setText: (value: string) => void;
|
||||
@@ -44,7 +46,7 @@ export function shouldEnableWindowsGitBashPasteFallback(params?: {
|
||||
}): boolean {
|
||||
const platform = params?.platform ?? process.platform;
|
||||
const env = params?.env ?? process.env;
|
||||
const termProgram = (env.TERM_PROGRAM ?? "").toLowerCase();
|
||||
const termProgram = normalizeLowercaseStringOrEmpty(env.TERM_PROGRAM);
|
||||
|
||||
// Some macOS terminals emit multiline paste as rapid single-line submits.
|
||||
// Enable burst coalescing so pasted blocks stay as one user message.
|
||||
@@ -64,7 +66,7 @@ export function shouldEnableWindowsGitBashPasteFallback(params?: {
|
||||
if (msystem.startsWith("MINGW") || msystem.startsWith("MSYS")) {
|
||||
return true;
|
||||
}
|
||||
if (shell.toLowerCase().includes("bash")) {
|
||||
if (normalizeLowercaseStringOrEmpty(shell).includes("bash")) {
|
||||
return true;
|
||||
}
|
||||
return termProgram.includes("mintty");
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
normalizeMainKey,
|
||||
parseAgentSessionKey,
|
||||
} from "../routing/session-key.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
|
||||
import { getSlashCommands } from "./commands.js";
|
||||
import { ChatLog } from "./components/chat-log.js";
|
||||
import { CustomEditor } from "./components/custom-editor.js";
|
||||
@@ -69,9 +70,9 @@ export function resolveTuiSessionKey(params: {
|
||||
return trimmed;
|
||||
}
|
||||
if (trimmed.startsWith("agent:")) {
|
||||
return trimmed.toLowerCase();
|
||||
return normalizeLowercaseStringOrEmpty(trimmed);
|
||||
}
|
||||
return `agent:${params.currentAgentId}:${trimmed.toLowerCase()}`;
|
||||
return `agent:${params.currentAgentId}:${normalizeLowercaseStringOrEmpty(trimmed)}`;
|
||||
}
|
||||
|
||||
export function resolveInitialTuiAgentId(params: {
|
||||
|
||||
Reference in New Issue
Block a user