Files
CodeNomad/packages/ui/src/lib/i18n/messages/ru/toolCall.ts
VooDisss 4f236ce36f Implement shared compact split and unified tool-call diff layout (#270)
# PR Title

Implement shared compact split and unified tool-call diff layout

---
Fixes #268 
# PR Description

## Summary

This PR makes tool-call diffs more compact in both `Unified` and `Split`
views by reducing wasted horizontal space in line-number gutters and
content indentation.

## What changed

- introduced a shared compact-diff framework for tool-call diffs
- kept mobile-specific policy limited to:
  - forcing unified mode below the breakpoint
  - enabling wrap only in mobile unified mode
- added mode-specific compact applicators in the diff viewer:
  - unified applicator
  - split applicator
- reduced gutter width waste by measuring rendered line-number text and
tightening column width around it
- removed unnecessary right-side content padding
- aligned `+` / `-` markers closer to the left edge across both views
- simplified cleanup after gatekeeper review by removing extra plumbing
and residue

## Screenshots

### Before

<img width="581" height="341" alt="image"
src="https://github.com/user-attachments/assets/ec47b256-749a-4afc-8879-aaf33f0b46b6"
/>

### After

<img width="470" height="586" alt="image"
src="https://github.com/user-attachments/assets/7258a5a2-47c4-408d-84bc-1b497761c7ad"
/>

## Architectural approach

This change intentionally uses:

- shared policy in
`packages/ui/src/components/tool-call/diff-render.tsx`
- shared helper/measurement logic in
`packages/ui/src/components/diff-viewer.tsx`
- mode-specific applicators where unified and split DOM differ
- CSS for shared visual spacing and alignment cleanup

The goal was to keep the implementation architecturally clean and avoid
building separate duplicated compact-diff features for:

- mobile vs desktop
- unified vs split

Instead, the feature shares one compact-diff concept and only diverges
where the upstream diff DOM requires separate handling.

## Files changed

- `packages/ui/src/components/tool-call/diff-render.tsx`
- `packages/ui/src/components/diff-viewer.tsx`
- `packages/ui/src/styles/messaging/tool-call.css`
- `packages/ui/src/types/message.ts`

## Validation

Manual validation was performed in the running UI.

Verified manually:

- compact unified gutters on mobile
- compact unified gutters on desktop
- compact split gutters on desktop
- tighter operator alignment in both modes

Also verified:

- `npm run typecheck` passes

## Notes

- This PR is intended to address the compact diff layout problem
described in the related issue.
- Diff-specific CSS still lives in `tool-call.css`; future extraction
into a smaller dedicated stylesheet is possible but not required for
this change.

---------

Co-authored-by: Shantur Rathore <i@shantur.com>
2026-04-01 23:13:32 +01:00

138 lines
8.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export const toolCallMessages = {
"toolCall.pending.waitingToRun": "Ожидание запуска…",
"toolCall.error.label": "Ошибка:",
"toolCall.header.copyTitle": "Copy tool call title",
"toolCall.header.copyAriaLabel": "Copy tool call title",
"toolCall.header.showInputTitle": "Show Tool Arguments",
"toolCall.header.showInputAriaLabel": "Show Tool Arguments",
"toolCall.header.hideInputTitle": "Hide Tool Arguments",
"toolCall.header.hideInputAriaLabel": "Hide Tool Arguments",
"toolCall.io.input": "Tool Input",
"toolCall.io.output": "Tool Output",
"toolCall.diff.label": "Diff",
"toolCall.diff.label.withPath": "Diff · {path}",
"toolCall.diff.viewMode.ariaLabel": "Режим просмотра diff",
"toolCall.diff.viewMode.split": "Раздельный",
"toolCall.diff.viewMode.unified": "Единый",
"toolCall.diff.switchToSplit": "Переключить на раздельный вид",
"toolCall.diff.switchToUnified": "Переключить на единый вид",
"toolCall.diff.enableWordWrap": "Включить перенос слов",
"toolCall.diff.disableWordWrap": "Выключить перенос слов",
"toolCall.diff.copyPatch": "Скопировать patch",
"toolCall.diagnostics.title": "Диагностика",
"toolCall.diagnostics.ariaLabel": "Диагностика",
"toolCall.diagnostics.ariaLabel.withLabel": "Диагностика {label}",
"toolCall.diagnostics.severity.error.short": "ERR",
"toolCall.diagnostics.severity.warning.short": "WARN",
"toolCall.diagnostics.severity.info.short": "INFO",
"toolCall.renderer.toolName.shell": "Shell",
"toolCall.renderer.toolName.fetch": "Fetch",
"toolCall.renderer.toolName.invalid": "Неверный",
"toolCall.renderer.toolName.plan": "План",
"toolCall.renderer.toolName.applyPatch": "Применить патч",
"toolCall.renderer.action.working": "Выполняется…",
"toolCall.renderer.action.writingCommand": "Запись команды…",
"toolCall.renderer.action.preparingEdit": "Подготовка правки…",
"toolCall.renderer.action.readingFile": "Чтение файла…",
"toolCall.renderer.action.preparingWrite": "Подготовка записи…",
"toolCall.renderer.action.preparingPatch": "Подготовка патча…",
"toolCall.renderer.action.planning": "Планирование…",
"toolCall.renderer.action.fetchingFromWeb": "Получение из интернета…",
"toolCall.renderer.action.findingFiles": "Поиск файлов…",
"toolCall.renderer.action.searchingContent": "Поиск по содержимому…",
"toolCall.renderer.action.listingDirectory": "Просмотр каталога…",
"toolCall.renderer.bash.title.timeout": "Таймаут: {timeout}",
"toolCall.renderer.read.detail.offset": "Смещение: {offset}",
"toolCall.renderer.read.detail.limit": "Лимит: {limit}",
"toolCall.renderer.todo.empty": "Пока нет пунктов плана.",
"toolCall.renderer.todo.status.pending": "Ожидает",
"toolCall.renderer.todo.status.inProgress": "В процессе",
"toolCall.renderer.todo.status.completed": "Завершено",
"toolCall.renderer.todo.status.cancelled": "Отменено",
"toolCall.renderer.todo.title.plan": "План",
"toolCall.renderer.todo.title.creating": "Создание плана",
"toolCall.renderer.todo.title.completing": "Завершение плана",
"toolCall.renderer.todo.title.updating": "Обновление плана",
"toolCall.permission.status.required": "Требуется разрешение",
"toolCall.permission.status.queued": "Разрешение в очереди",
"toolCall.permission.requestedDiff.label": "Запрошенный diff",
"toolCall.permission.requestedDiff.withPath": "Запрошенный diff · {path}",
"toolCall.permission.queuedText": "Ожидание предыдущих ответов по разрешениям.",
"toolCall.permission.actions.allowOnce": "Разрешить один раз",
"toolCall.permission.actions.alwaysAllow": "Всегда разрешать",
"toolCall.permission.actions.deny": "Запретить",
"toolCall.permission.shortcuts.allowOnce": "Разрешить один раз",
"toolCall.permission.shortcuts.alwaysAllow": "Всегда разрешать",
"toolCall.permission.shortcuts.deny": "Запретить",
"toolCall.permission.errors.unableToUpdate": "Не удалось обновить разрешение",
"permissionApproval.title": "Запросы",
"permissionApproval.empty": "Нет ожидающих запросов.",
"permissionApproval.kind.permission": "Разрешение",
"permissionApproval.kind.question": "Вопрос",
"permissionApproval.questionCount.one": "{count} вопрос",
"permissionApproval.questionCount.other": "{count} вопросов",
"permissionApproval.status.active": "Активно",
"permissionApproval.actions.closeAriaLabel": "Закрыть",
"permissionApproval.actions.goToSession": "Перейти к сессии",
"permissionApproval.actions.loadingSession": "Загрузка…",
"permissionApproval.actions.loadSession": "Загрузить сессию",
"permissionApproval.actions.allowOnce": "Разрешить один раз",
"permissionApproval.actions.alwaysAllow": "Всегда разрешать",
"permissionApproval.actions.deny": "Запретить",
"permissionApproval.fallbackHint": "Загрузите сессию для получения подробностей.",
"permissionApproval.errors.unableToUpdatePermission": "Не удалось обновить разрешение",
"toolCall.question.status.required": "Требуется ответ",
"toolCall.question.status.queued": "Вопрос в очереди",
"toolCall.question.status.questions": "Вопросы",
"toolCall.question.action.awaitingAnswers": "Ожидание ответов…",
"toolCall.question.title.questions": "Вопросы",
"toolCall.question.title.askingQuestions": "Задаем вопросы",
"toolCall.question.type.one": "Вопрос",
"toolCall.question.type.other": "Вопросы",
"toolCall.question.number": "В{number}:",
"toolCall.question.multiple": "Несколько",
"toolCall.question.custom.title": "Введите свой ответ",
"toolCall.question.custom.label": "Свой ответ",
"toolCall.question.custom.placeholder": "Введите свой ответ",
"toolCall.question.actions.submit": "Отправить",
"toolCall.question.actions.dismiss": "Скрыть",
"toolCall.question.shortcuts.submit": "Отправить",
"toolCall.question.shortcuts.dismiss": "Скрыть",
"toolCall.question.queuedText": "Ожидание предыдущих ответов.",
"toolCall.question.validation.answerAll": "Ответьте на все вопросы перед отправкой.",
"toolCall.question.errors.unableToReply": "Не удалось ответить",
"toolCall.question.errors.unableToDismiss": "Не удалось скрыть",
"toolCall.task.action.delegating": "Делегирование…",
"toolCall.task.sections.prompt": "Prompt",
"toolCall.task.sections.steps": "Шаги",
"toolCall.task.sections.output": "Вывод",
"toolCall.task.steps.count": "{count} шагов",
"toolCall.task.meta.agentModel": "Агент: {agent} • Модель: {model}",
"toolCall.task.meta.agent": "Агент: {agent}",
"toolCall.task.meta.model": "Модель: {model}",
"toolCall.status.pending": "В ожидании",
"toolCall.status.running": "Выполняется",
"toolCall.status.completed": "Завершено",
"toolCall.status.error": "Ошибка",
"toolCall.status.unknown": "Неизвестно",
"toolCall.applyPatch.action.preparing": "Подготовка apply_patch…",
"toolCall.applyPatch.title.withFileCount.one": "{tool} ({count} файл)",
"toolCall.applyPatch.title.withFileCount.other": "{tool} ({count} файлов)",
"toolCall.applyPatch.fileFallback": "Файл {number}",
} as const