=> {
@@ -206,7 +211,6 @@ export function HighlightTab(): React.JSX.Element {
width: 76,
align: 'center',
sorter: (a, b) => a.priority - b.priority,
- defaultSortOrder: ORDERED_SORT,
render: (priority: number) => {priority}
},
{
@@ -217,8 +221,8 @@ export function HighlightTab(): React.JSX.Element {
render: (color: HighlightRule['color'], record) =>
record.bands && record.bands.length > 0 ? (
- {record.bands.map((band) => (
-
+ {record.bands.map((band, index) => (
+
≥{band.min}
@@ -423,7 +427,8 @@ function HighlightEditor({
bg: undefined,
caseInsensitive: false,
note: undefined,
- enabled: true
+ enabled: true,
+ basic: false
})
const [saving, setSaving] = useState(false)
const [showBg, setShowBg] = useState(false)
@@ -485,9 +490,10 @@ function HighlightEditor({
const note = editing ? editing.note : undefined
const enabled = editing ? editing.enabled : true
const caseInsensitive = editing ? editing.caseInsensitive === true : false
+ const basic = editing ? editing.basic === true : false
const bands = editing?.bands
const category = editing?.category
- setDraft({ pattern, priority, fg, bg, bands, category, caseInsensitive, note, enabled })
+ setDraft({ pattern, priority, fg, bg, bands, category, caseInsensitive, note, enabled, basic })
setShowBg(bg != null)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open])
@@ -507,7 +513,12 @@ function HighlightEditor({
const updateBand = (index: number, partial: Partial<{ min: number; fg: string }>): void => {
const bands = draft.bands
if (!bands) return
- patch({ bands: bands.map((band, i) => (i === index ? { ...band, ...partial } : band)) })
+ const next = bands.map((band, i) => (i === index ? { ...band, ...partial } : band))
+ // the engine applies bands in ascending min order (compileBands sorts), so
+ // keep the editor rows in that same order — a stable sort keeps equal mins
+ // in their entry order
+ next.sort((a, b) => a.min - b.min)
+ patch({ bands: next })
}
const removeBand = (index: number): void => {
@@ -535,6 +546,7 @@ function HighlightEditor({
bands,
category: draft.category,
caseInsensitive,
+ ...(draft.basic ? { basic: true as const } : {}),
note: draft.note?.trim() ? draft.note.trim() : undefined
}
await setHighlightRules([...highlightRules, rule])
@@ -548,6 +560,9 @@ function HighlightEditor({
bands,
category: draft.category,
caseInsensitive,
+ // explicit override (not a conditional spread): unchecking must clear
+ // a basic flag the edited rule may already carry
+ basic: draft.basic ? true : undefined,
note: draft.note?.trim() ? draft.note.trim() : undefined
}
await setHighlightRules(highlightRules.map((r) => (r.id === rule.id ? rule : r)))
@@ -646,7 +661,13 @@ function HighlightEditor({
value={draft.bg ?? PRESET_COLORS[0]}
onChange={(v) => patch({ bg: v })}
/>
-
+
+ {t('settings.highlight.basic')}
+ patch({ basic: c })} />
+ {t('settings.highlight.basicHint')}
+
+
{t('settings.highlight.enabled')}
patch({ enabled: c })} />
diff --git a/src/renderer/src/terminal/TerminalView.tsx b/src/renderer/src/terminal/TerminalView.tsx
index 2e45f9b..9aac79e 100644
--- a/src/renderer/src/terminal/TerminalView.tsx
+++ b/src/renderer/src/terminal/TerminalView.tsx
@@ -386,7 +386,11 @@ export const TerminalView: ForwardRefExoticComponent publishHighlightStats(new Map(sink)), 1000)
return () => window.clearInterval(timer)
}, [settings.terminal.highlightStats])
- streamRef.current?.setRules(compiledRules)
+ // Push the latest compiled rules into the stream from an effect — assigning
+ // during render would be a side effect in the render body.
+ useEffect(() => {
+ streamRef.current?.setRules(compiledRules)
+ }, [compiledRules])
// M5: load completion candidates once per session (history + library cached).
const ensureCompletionCache = useCallback((): void => {
diff --git a/src/shared/i18n/dicts/en/settings.ts b/src/shared/i18n/dicts/en/settings.ts
index aebf8fb..21bf5f3 100644
--- a/src/shared/i18n/dicts/en/settings.ts
+++ b/src/shared/i18n/dicts/en/settings.ts
@@ -200,6 +200,9 @@ const settings: Record = {
'settings.highlight.importMode': 'Mode',
'settings.highlight.importReplace': 'Replace current rules',
'settings.highlight.importAppend': 'Append to current rules',
+ 'settings.highlight.importReplaceTitle': 'Replace current rules?',
+ 'settings.highlight.importReplaceDesc':
+ 'Importing overwrites every current rule with this file. This cannot be undone.',
'settings.highlight.importOk': 'Import',
'settings.highlight.importEmpty': 'No usable rules found',
'settings.highlight.importBadJson': 'Not valid JSON',
@@ -214,6 +217,8 @@ const settings: Record = {
'settings.highlight.modeOff': 'Off',
'settings.highlight.modeDesc':
'Basic only: keeps just the key rules (errors, success, warnings, dangerous commands, secrets) — cheaper and quieter. Off: no colour injection at all (rules and colours are kept).',
+ 'settings.highlight.basic': 'Basic rule',
+ 'settings.highlight.basicHint': 'keep this rule active when the highlight mode is "Basic only"',
'settings.highlight.category': 'Category',
'settings.highlight.groupByCategory': 'Group by category',
'settings.highlight.category.safety': 'Safety',
@@ -245,6 +250,7 @@ const settings: Record = {
'settings.highlight.profileNamePlaceholder': 'e.g. production (errors only)',
'settings.highlight.profileRules': 'Included rules',
'settings.highlight.profileRulesHint': 'Unchecked rules stay off on that host',
+ 'settings.highlight.profileExcluded': 'Excluded {n}: {list}',
'settings.highlight.profileEmpty': 'No rule sets yet',
'settings.highlight.profileDeleteTitle': 'Delete rule set',
'settings.highlight.actions': 'Actions',
diff --git a/src/shared/i18n/dicts/ja/settings.ts b/src/shared/i18n/dicts/ja/settings.ts
index 22568d1..fa6d0e7 100644
--- a/src/shared/i18n/dicts/ja/settings.ts
+++ b/src/shared/i18n/dicts/ja/settings.ts
@@ -196,6 +196,9 @@ const settings: Record = {
'settings.highlight.importMode': '取り込み方法',
'settings.highlight.importReplace': '現在のルールを置き換える',
'settings.highlight.importAppend': '現在のルールに追加する',
+ 'settings.highlight.importReplaceTitle': '現在のルールを置き換えますか?',
+ 'settings.highlight.importReplaceDesc':
+ 'インポートすると現在のすべてのルールがこのファイルの内容で上書きされます。元に戻せません。',
'settings.highlight.importOk': 'インポート',
'settings.highlight.importEmpty': '有効なルールが見つかりません',
'settings.highlight.importBadJson': '有効な JSON ではありません',
@@ -210,6 +213,8 @@ const settings: Record = {
'settings.highlight.modeOff': 'オフ',
'settings.highlight.modeDesc':
'基本のみ:エラー/成功/警告/危険なコマンド/シークレットなど重要なルールだけを適用(軽量・低ノイズ)。オフ:色をまったく注入しません(ルールと色は保持)。',
+ 'settings.highlight.basic': '基本ルール',
+ 'settings.highlight.basicHint': 'オンにすると、ハイライトが「基本のみ」モードのときもこのルールが適用されます',
'settings.highlight.category': '分類',
'settings.highlight.groupByCategory': '分類でグループ化',
'settings.highlight.category.safety': '安全',
@@ -240,6 +245,7 @@ const settings: Record = {
'settings.highlight.profileNamePlaceholder': '例:本番機(エラーのみ)',
'settings.highlight.profileRules': '含めるルール',
'settings.highlight.profileRulesHint': 'チェックを外したルールはそのホストでは効きません',
+ 'settings.highlight.profileExcluded': '{n} 件を除外:{list}',
'settings.highlight.profileEmpty': 'ルールセットがまだありません',
'settings.highlight.profileDeleteTitle': 'ルールセットを削除',
'settings.highlight.actions': '操作',
diff --git a/src/shared/i18n/dicts/zh-CN/settings.ts b/src/shared/i18n/dicts/zh-CN/settings.ts
index 08b1044..167eec8 100644
--- a/src/shared/i18n/dicts/zh-CN/settings.ts
+++ b/src/shared/i18n/dicts/zh-CN/settings.ts
@@ -190,6 +190,8 @@ const settings: Record = {
'settings.highlight.importMode': '导入方式',
'settings.highlight.importReplace': '替换现有规则',
'settings.highlight.importAppend': '追加到现有规则',
+ 'settings.highlight.importReplaceTitle': '替换现有规则?',
+ 'settings.highlight.importReplaceDesc': '导入后当前全部规则将被这份文件覆盖,无法恢复。',
'settings.highlight.importOk': '导入',
'settings.highlight.importEmpty': '没有解析到可用规则',
'settings.highlight.importBadJson': '不是有效的 JSON',
@@ -203,6 +205,8 @@ const settings: Record = {
'settings.highlight.modeBasic': '仅基础',
'settings.highlight.modeOff': '关闭',
'settings.highlight.modeDesc': '仅基础:只保留错误/成功/警告/危险命令/密钥等关键规则,开销更小;关闭:完全不注入颜色(规则与颜色都保留)',
+ 'settings.highlight.basic': '基础规则',
+ 'settings.highlight.basicHint': '开启后,终端高亮为「仅基础」模式时该规则仍会生效',
'settings.highlight.category': '分类',
'settings.highlight.groupByCategory': '按分类分组',
'settings.highlight.category.safety': '安全',
@@ -230,6 +234,7 @@ const settings: Record = {
'settings.highlight.profileNamePlaceholder': '例如:生产机(只看错误)',
'settings.highlight.profileRules': '包含的规则',
'settings.highlight.profileRulesHint': '未勾选的规则在这台主机上不生效',
+ 'settings.highlight.profileExcluded': '未包含 {n} 条:{list}',
'settings.highlight.profileEmpty': '尚未创建规则集',
'settings.highlight.profileDeleteTitle': '删除规则集',
'settings.highlight.actions': '操作',
diff --git a/src/shared/i18n/dicts/zh-TW/settings.ts b/src/shared/i18n/dicts/zh-TW/settings.ts
index bc93d3a..d92bd5a 100644
--- a/src/shared/i18n/dicts/zh-TW/settings.ts
+++ b/src/shared/i18n/dicts/zh-TW/settings.ts
@@ -190,6 +190,8 @@ const settings: Record = {
'settings.highlight.importMode': '匯入方式',
'settings.highlight.importReplace': '取代現有規則',
'settings.highlight.importAppend': '附加到現有規則',
+ 'settings.highlight.importReplaceTitle': '取代現有規則?',
+ 'settings.highlight.importReplaceDesc': '匯入後目前全部規則將被這份檔案覆蓋,無法復原。',
'settings.highlight.importOk': '匯入',
'settings.highlight.importEmpty': '沒有解析到可用規則',
'settings.highlight.importBadJson': '不是有效的 JSON',
@@ -203,6 +205,8 @@ const settings: Record = {
'settings.highlight.modeBasic': '僅基礎',
'settings.highlight.modeOff': '關閉',
'settings.highlight.modeDesc': '僅基礎:只保留錯誤/成功/警告/危險命令/密鑰等關鍵規則,開銷更小;關閉:完全不注入顏色(規則與顏色都保留)',
+ 'settings.highlight.basic': '基礎規則',
+ 'settings.highlight.basicHint': '開啟後,終端機高亮為「僅基礎」模式時該規則仍會生效',
'settings.highlight.category': '分類',
'settings.highlight.groupByCategory': '依分類分組',
'settings.highlight.category.safety': '安全',
@@ -230,6 +234,7 @@ const settings: Record = {
'settings.highlight.profileNamePlaceholder': '例如:正式機(只看錯誤)',
'settings.highlight.profileRules': '包含的規則',
'settings.highlight.profileRulesHint': '未勾選的規則在這台主機上不生效',
+ 'settings.highlight.profileExcluded': '未包含 {n} 條:{list}',
'settings.highlight.profileEmpty': '尚未建立規則集',
'settings.highlight.profileDeleteTitle': '刪除規則集',
'settings.highlight.actions': '操作',