import React, { useEffect, useState } from "react"; import { ChevronRight, Pencil, Plus, RotateCcw, Trash2 } from "lucide-react"; import { DEFAULT_KEYWORD_HIGHLIGHT_RULES, type KeywordHighlightRule } from "../../../domain/models"; import { useI18n } from "../../../application/i18n/I18nProvider"; import { TERMINAL_THEMES } from "../../../infrastructure/config/terminalThemes"; import { cn } from "../../../lib/utils"; import { Toggle } from "../settings-ui"; import { Button } from "../../ui/button"; import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "../../ui/dialog"; import { Input } from "../../ui/input"; import { Label } from "../../ui/label"; import { Textarea } from "../../ui/textarea"; // Keyword highlight rules editor for global settings const DEFAULT_NEW_RULE_COLOR = '#F87171'; /** Temporarily disable/enable one rule without deleting it. */ export function toggleKeywordHighlightRuleEnabled( rules: KeywordHighlightRule[], ruleId: string, ): KeywordHighlightRule[] { return rules.map((rule) => ( rule.id === ruleId ? { ...rule, enabled: !rule.enabled } : rule )); } export const AddCustomRuleDialog: React.FC<{ open: boolean; onOpenChange: (open: boolean) => void; editRule?: KeywordHighlightRule | null; isBuiltIn?: boolean; onAdd: (rule: KeywordHighlightRule) => void; }> = ({ open, onOpenChange, editRule, isBuiltIn = false, onAdd }) => { const { t } = useI18n(); const [label, setLabel] = useState(''); // Multi-line text: one regex pattern per line. Built-in rules typically // ship multiple patterns (e.g. several spellings of "error"), and the user // is allowed to add as many as they like. const [patternsText, setPatternsText] = useState(''); const [color, setColor] = useState(DEFAULT_NEW_RULE_COLOR); const [patternError, setPatternError] = useState(null); const reset = () => { setLabel(''); setPatternsText(''); setColor(DEFAULT_NEW_RULE_COLOR); setPatternError(null); }; // Populate form when editing useEffect(() => { if (open && editRule) { setLabel(editRule.label); setPatternsText(editRule.patterns.join('\n')); setColor(editRule.color); setPatternError(null); } else if (!open) { reset(); } }, [open, editRule]); const handleSubmit = () => { if (!label.trim()) return; const patterns = patternsText .split('\n') .map((line) => line.trim()) .filter((line) => line.length > 0); if (patterns.length === 0) return; for (const p of patterns) { try { new RegExp(p, 'gi'); } catch { setPatternError(t('settings.terminal.keywordHighlight.invalidPattern')); return; } } onAdd({ id: editRule?.id ?? crypto.randomUUID(), label: label.trim(), patterns, color, enabled: editRule?.enabled ?? true, // Editing a built-in rule flips it into "user-customized" mode so the // normalizer keeps the user's patterns across restarts. customized: isBuiltIn ? true : editRule?.customized, }); reset(); onOpenChange(false); }; const dialogTitleKey = editRule ? (isBuiltIn ? 'settings.terminal.keywordHighlight.editBuiltIn' : 'settings.terminal.keywordHighlight.editCustom') : 'settings.terminal.keywordHighlight.addCustom'; return ( { if (!v) reset(); onOpenChange(v); }}> {t(dialogTitleKey)}
setLabel(e.target.value)} className="flex-1" />