mirror of
https://github.com/stablyai/orca.git
synced 2026-11-03 18:47:40 +00:00
fix(settings): show the default word separators as an editable value (#28336)
Double-click selected across spaces when a custom Word Separators value omitted the space. The field was empty with the default (which starts with an invisible space) only as a placeholder, so users rebuilt the list without it. Like xterm.js, VS Code and Ghostty, Orca keeps respecting the configured value exactly; the field now shows the default as its value, offers Reset when customized, and warns when no space is included. Fixes #28335 Co-authored-by: Neil <neil@stably.ai>
This commit is contained in:
@@ -3,14 +3,16 @@
|
||||
import { act } from 'react'
|
||||
import { createRoot, type Root } from 'react-dom/client'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { getDefaultSettings } from '../../../../shared/constants'
|
||||
import type { GlobalSettings } from '../../../../shared/global-settings-types'
|
||||
import { TERMINAL_DEFAULT_WORD_SEPARATOR } from '../../../../shared/terminal-word-separator'
|
||||
import { TerminalAdvancedSection } from './TerminalAdvancedSection'
|
||||
|
||||
vi.mock('@/i18n/i18n', () => ({
|
||||
translate: (_key: string, defaultValue: string) => defaultValue
|
||||
}))
|
||||
|
||||
describe('TerminalAdvancedSection scrollback rows', () => {
|
||||
describe('TerminalAdvancedSection', () => {
|
||||
let container: HTMLDivElement
|
||||
let root: Root
|
||||
|
||||
@@ -26,11 +28,11 @@ describe('TerminalAdvancedSection scrollback rows', () => {
|
||||
document.body.replaceChildren()
|
||||
})
|
||||
|
||||
function renderSection(updateSettings = vi.fn()): void {
|
||||
function renderSection(updateSettings = vi.fn(), overrides: Partial<GlobalSettings> = {}): void {
|
||||
act(() => {
|
||||
root.render(
|
||||
<TerminalAdvancedSection
|
||||
settings={{ terminalScrollbackRows: 5000 } as GlobalSettings}
|
||||
settings={{ ...getDefaultSettings('/tmp'), terminalScrollbackRows: 5000, ...overrides }}
|
||||
updateSettings={updateSettings}
|
||||
scrollbackMode="custom"
|
||||
setScrollbackMode={vi.fn()}
|
||||
@@ -103,4 +105,23 @@ describe('TerminalAdvancedSection scrollback rows', () => {
|
||||
expect(updateSettings).toHaveBeenCalledWith({ terminalScrollbackRows: 12345 })
|
||||
expect(input.value).toBe('12345')
|
||||
})
|
||||
|
||||
it('shows the no-space hint for a custom separator and resets to the default', () => {
|
||||
const updateSettings = vi.fn()
|
||||
renderSection(updateSettings, { terminalWordSeparator: '()[]' })
|
||||
|
||||
const input = container.querySelector<HTMLInputElement>('input:not([type])')
|
||||
expect(input?.value).toBe('()[]')
|
||||
expect(container.textContent).toContain('No space included')
|
||||
|
||||
const reset = [...container.querySelectorAll('button')].find((b) => b.textContent === 'Reset')
|
||||
act(() => reset?.click())
|
||||
|
||||
expect(updateSettings).toHaveBeenCalledWith({ terminalWordSeparator: undefined })
|
||||
expect(input?.value).toBe(TERMINAL_DEFAULT_WORD_SEPARATOR)
|
||||
expect(container.textContent).not.toContain('No space included')
|
||||
expect([...container.querySelectorAll('button')].some((b) => b.textContent === 'Reset')).toBe(
|
||||
false
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
DESKTOP_TERMINAL_SCROLLBACK_ROWS_MIN,
|
||||
normalizeDesktopTerminalScrollbackRows
|
||||
} from '../../../../shared/terminal-scrollback-policy'
|
||||
import { Button } from '../ui/button'
|
||||
import { Input } from '../ui/input'
|
||||
import { ToggleGroup, ToggleGroupItem } from '../ui/toggle-group'
|
||||
import {
|
||||
@@ -35,6 +36,10 @@ function formatScrollbackRowsLabel(rows: number): string {
|
||||
return rows % 1_000 === 0 ? `${rows / 1_000}k` : String(rows)
|
||||
}
|
||||
|
||||
function toWordSeparatorSetting(draft: string): string | undefined {
|
||||
return draft && draft !== TERMINAL_DEFAULT_WORD_SEPARATOR ? draft : undefined
|
||||
}
|
||||
|
||||
export function TerminalAdvancedSection({
|
||||
settings,
|
||||
updateSettings,
|
||||
@@ -58,6 +63,22 @@ export function TerminalAdvancedSection({
|
||||
)
|
||||
const scrollbackToggleValue =
|
||||
scrollbackMode === 'custom' ? 'custom' : isPreset ? `${scrollbackRows}` : 'custom'
|
||||
const wordSeparator = settings.terminalWordSeparator
|
||||
const [wordSeparatorDraft, setWordSeparatorDraft] = useState(
|
||||
wordSeparator ?? TERMINAL_DEFAULT_WORD_SEPARATOR
|
||||
)
|
||||
const [prevWordSeparator, setPrevWordSeparator] = useState(wordSeparator)
|
||||
if (wordSeparator !== prevWordSeparator) {
|
||||
setPrevWordSeparator(wordSeparator)
|
||||
// Why: an emptied field stays empty while editing instead of snapping back to the default.
|
||||
if (wordSeparator !== toWordSeparatorSetting(wordSeparatorDraft)) {
|
||||
setWordSeparatorDraft(wordSeparator ?? TERMINAL_DEFAULT_WORD_SEPARATOR)
|
||||
}
|
||||
}
|
||||
const commitWordSeparatorDraft = (draft: string): void => {
|
||||
setWordSeparatorDraft(draft)
|
||||
updateSettings({ terminalWordSeparator: toWordSeparatorSetting(draft) })
|
||||
}
|
||||
const powerShellImplementation = settings.terminalWindowsPowerShellImplementation ?? 'auto'
|
||||
const commitScrollbackRowsDraft = (): void => {
|
||||
const trimmed = scrollbackRowsDraft.trim()
|
||||
@@ -176,27 +197,47 @@ export function TerminalAdvancedSection({
|
||||
<SearchableSetting
|
||||
title={translate('auto.components.settings.TerminalPane.4bebcc2b2c', 'Word Separators')}
|
||||
description={translate(
|
||||
'auto.components.settings.TerminalPane.8a956cc91e',
|
||||
'Characters treated as word boundaries for double-click selection.'
|
||||
'settings.terminal.wordSeparators.description',
|
||||
'Characters treated as word boundaries for double-click selection, including space.'
|
||||
)}
|
||||
keywords={['word', 'separator', 'boundary', 'double-click', 'selection']}
|
||||
>
|
||||
<SettingsRow
|
||||
label={translate('auto.components.settings.TerminalPane.4bebcc2b2c', 'Word Separators')}
|
||||
description={translate(
|
||||
'auto.components.settings.TerminalPane.8a956cc91e',
|
||||
'Characters treated as word boundaries for double-click selection.'
|
||||
'settings.terminal.wordSeparators.description',
|
||||
'Characters treated as word boundaries for double-click selection, including space.'
|
||||
)}
|
||||
control={
|
||||
<Input
|
||||
value={settings.terminalWordSeparator ?? ''}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
updateSettings({ terminalWordSeparator: value || undefined })
|
||||
}}
|
||||
placeholder={TERMINAL_DEFAULT_WORD_SEPARATOR}
|
||||
className="w-56 font-mono text-xs"
|
||||
/>
|
||||
<div className="flex w-56 flex-col items-end gap-1">
|
||||
<div className="flex w-full items-center gap-1">
|
||||
<Input
|
||||
value={wordSeparatorDraft}
|
||||
onChange={(e) => commitWordSeparatorDraft(e.target.value)}
|
||||
variant="code"
|
||||
spellCheck={false}
|
||||
className="min-w-0 flex-1"
|
||||
/>
|
||||
{wordSeparatorDraft !== TERMINAL_DEFAULT_WORD_SEPARATOR ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
onClick={() => commitWordSeparatorDraft(TERMINAL_DEFAULT_WORD_SEPARATOR)}
|
||||
>
|
||||
{translate('auto.components.settings.AgentsPane.5200dac9da', 'Reset')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
{wordSeparatorDraft && !wordSeparatorDraft.includes(' ') ? (
|
||||
<p className="text-xs text-status-warning">
|
||||
{translate(
|
||||
'settings.terminal.wordSeparators.noSpaceHint',
|
||||
'No space included — double-click will select across spaces.'
|
||||
)}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</SearchableSetting>
|
||||
|
||||
@@ -363,6 +363,10 @@
|
||||
"openManageSessions": "Open Manage Sessions",
|
||||
"administratorSearchDescription": "See Orca’s Windows permissions or restart with administrator approval.",
|
||||
"administratorApproval": "Windows will ask for approval. Use your usual account."
|
||||
},
|
||||
"wordSeparators": {
|
||||
"description": "Characters treated as word boundaries for double-click selection, including space.",
|
||||
"noSpaceHint": "No space included — double-click will select across spaces."
|
||||
}
|
||||
},
|
||||
"appearance": {
|
||||
@@ -8592,7 +8596,6 @@
|
||||
"a016ffbeed": "Auto uses Windows PowerShell now and switches to PowerShell 7+ when installed.",
|
||||
"5ed5c95344": "Choose between Windows PowerShell and PowerShell 7+ for new terminal panes.",
|
||||
"3d88af864d": "Choose whether the PowerShell shell option launches Windows PowerShell or PowerShell 7+ for new terminal panes.",
|
||||
"8a956cc91e": "Characters treated as word boundaries for double-click selection.",
|
||||
"4bebcc2b2c": "Word Separators",
|
||||
"12e06178fa": "rows",
|
||||
"907b0b9d3e": "Custom",
|
||||
|
||||
@@ -8220,7 +8220,6 @@
|
||||
"a016ffbeed": "Auto usa Windows PowerShell ahora y cambia a PowerShell 7+ cuando está instalado.",
|
||||
"5ed5c95344": "Elige entre Windows PowerShell y PowerShell 7+ para nuevos paneles de terminal.",
|
||||
"3d88af864d": "Elige si la opción de shell PowerShell inicia Windows PowerShell o PowerShell 7+ para nuevos paneles de terminal.",
|
||||
"8a956cc91e": "Caracteres tratados como límites de palabras para la selección con doble clic.",
|
||||
"4bebcc2b2c": "Separadores de palabras",
|
||||
"12e06178fa": "filas",
|
||||
"907b0b9d3e": "Personalizado",
|
||||
|
||||
@@ -8439,7 +8439,6 @@
|
||||
"a016ffbeed": "Auto utilise Windows PowerShell pour le moment et bascule vers PowerShell 7+ une fois installé.",
|
||||
"5ed5c95344": "Choisissez entre Windows PowerShell et PowerShell 7+ pour les nouveaux volets de terminal.",
|
||||
"3d88af864d": "Choisissez si l'option de shell PowerShell lance Windows PowerShell ou PowerShell 7+ pour les nouveaux volets de terminal.",
|
||||
"8a956cc91e": "Caractères traités comme séparateurs de mots pour la sélection par double-clic.",
|
||||
"4bebcc2b2c": "Séparateurs de mots",
|
||||
"12e06178fa": "lignes",
|
||||
"907b0b9d3e": "Personnalisé",
|
||||
|
||||
@@ -8226,7 +8226,6 @@
|
||||
"a016ffbeed": "Auto は現在 Windows PowerShell を使用し、インストールされると PowerShell 7 以降に切り替わります。",
|
||||
"5ed5c95344": "新規ターミナルペインについては、Windows PowerShell と PowerShell 7+ のどちらかを選択します。",
|
||||
"3d88af864d": "PowerShell シェルオプションで、新規ターミナルペインに対して Windows PowerShell を起動するか PowerShell 7+ を起動するかを選択します。",
|
||||
"8a956cc91e": "文字はダブルクリック選択の単語境界として扱われます。",
|
||||
"4bebcc2b2c": "単語の区切り文字",
|
||||
"12e06178fa": "行",
|
||||
"907b0b9d3e": "カスタム",
|
||||
|
||||
@@ -8189,7 +8189,6 @@
|
||||
"a016ffbeed": "자동은 현재 Windows PowerShell을 사용하고, PowerShell 7+가 설치되면 전환합니다.",
|
||||
"5ed5c95344": "새 터미널 패널을 위해 Windows PowerShell과 PowerShell 7+ 중에서 선택하세요.",
|
||||
"3d88af864d": "PowerShell 셸 옵션이 새 터미널 패널에 대해 Windows PowerShell을 시작할지 아니면 PowerShell 7+를 시작할지 선택합니다.",
|
||||
"8a956cc91e": "두 번 클릭 선택 시 단어 경계로 처리되는 문자입니다.",
|
||||
"4bebcc2b2c": "단어 구분 기호",
|
||||
"12e06178fa": "행",
|
||||
"907b0b9d3e": "사용자 지정",
|
||||
|
||||
@@ -4023,7 +4023,6 @@
|
||||
"a016ffbeed": "Auto usa o Windows PowerShell agora e alterna para o PowerShell 7+ quando instalado.",
|
||||
"5ed5c95344": "Escolha entre Windows PowerShell e PowerShell 7+ para novos painéis de terminal.",
|
||||
"3d88af864d": "Escolha se a opção de shell PowerShell inicia o Windows PowerShell ou o PowerShell 7+ para novos painéis de terminal.",
|
||||
"8a956cc91e": "Caracteres tratados como limites de palavra para seleção por clique duplo.",
|
||||
"4bebcc2b2c": "Separadores de Palavra",
|
||||
"12e06178fa": "linhas",
|
||||
"907b0b9d3e": "Personalizado",
|
||||
|
||||
@@ -8616,7 +8616,6 @@
|
||||
"a016ffbeed": "Сейчас «Авто» использует Windows PowerShell и переключится на PowerShell 7+ после установки.",
|
||||
"5ed5c95344": "Выберите Windows PowerShell или PowerShell 7+ для новых панелей терминала.",
|
||||
"3d88af864d": "Выберите, какую оболочку запускает пункт PowerShell для новых панелей терминала: Windows PowerShell или PowerShell 7+.",
|
||||
"8a956cc91e": "Символы границ слов для выделения двойным щелчком.",
|
||||
"4bebcc2b2c": "Разделители слов",
|
||||
"12e06178fa": "строк",
|
||||
"907b0b9d3e": "Пользовательские",
|
||||
|
||||
@@ -8556,7 +8556,6 @@
|
||||
"a016ffbeed": "Otomatik, şu anda Windows PowerShell'i kullanır ve kurulduğunda PowerShell 7+'a geçer.",
|
||||
"5ed5c95344": "Yeni terminal bölmeleri için Windows PowerShell ve PowerShell 7+ arasında seçim yapın.",
|
||||
"3d88af864d": "PowerShell kabuk seçeneğinin yeni terminal bölmeleri için Windows PowerShell mi yoksa PowerShell 7+ mı başlatacağını seçin.",
|
||||
"8a956cc91e": "Çift tıklama seçiminde kelime sınırı olarak kabul edilen karakterler.",
|
||||
"4bebcc2b2c": "Kelime Ayırıcıları",
|
||||
"12e06178fa": "satır",
|
||||
"907b0b9d3e": "Özel",
|
||||
|
||||
@@ -8545,7 +8545,6 @@
|
||||
"a016ffbeed": "「自動」模式目前使用 Windows PowerShell,並在安裝後切換到 PowerShell 7+。",
|
||||
"5ed5c95344": "為新的終端機窗格選擇 Windows PowerShell 或 PowerShell 7+。",
|
||||
"3d88af864d": "使用 PowerShell shell 選項開啟新的終端機窗格時,選擇要啟動 Windows PowerShell 還是 PowerShell 7+。",
|
||||
"8a956cc91e": "按兩下選取時視為字詞邊界的字元。",
|
||||
"4bebcc2b2c": "字詞分隔字元",
|
||||
"12e06178fa": "列",
|
||||
"907b0b9d3e": "自訂",
|
||||
|
||||
@@ -8189,7 +8189,6 @@
|
||||
"a016ffbeed": "Auto 现在使用 Windows PowerShell,并在安装后切换到 PowerShell 7+。",
|
||||
"5ed5c95344": "为新的终端窗格选择 Windows PowerShell 和 PowerShell 7+。",
|
||||
"3d88af864d": "选择 PowerShell shell 选项是为新终端窗格启动 Windows PowerShell 还是 PowerShell 7+。",
|
||||
"8a956cc91e": "双击选择时将字符视为单词边界。",
|
||||
"4bebcc2b2c": "单词分隔符",
|
||||
"12e06178fa": "行",
|
||||
"907b0b9d3e": "自定义",
|
||||
|
||||
Reference in New Issue
Block a user