surshar / claude-code
Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.
Built by Anthropic · github.com/anthropics
| 1 | /* @jsxRuntime classic */ |
| 2 | /* @jsx h */ |
| 3 | /* @jsxFrag Fragment */ |
| 4 | import type { RenderElement } from 'claude-code' |
| 5 | |
| 6 | import type Git from '../../git' |
| 7 | import Names from '../../names' |
| 8 | import PaneState from '../../pane-state' |
| 9 | import Detail from '../detail' |
| 10 | import type { Kit } from '../kit' |
| 11 | import Layout from '../layout' |
| 12 | import Sections from '../sections' |
| 13 | import { fileRowOf } from './file-row-of' |
| 14 | import { listBodyOf } from './list-body-of' |
| 15 | |
| 16 | /** |
| 17 | * The pane over the repository's diff now (ReplDiffSidebarBody, one file's |
| 18 | * body at a time): header, base line, todo bar, pickers, rows, detail. |
| 19 | * |
| 20 | * The tests-and-generated toggle sits above the rows; the elision count, the |
| 21 | * withheld-untracked note, the pre-session line and rows below them; the |
| 22 | * selected file last. |
| 23 | * |
| 24 | * @param kit the elements, the handlers, the width |
| 25 | * @param model the pane's state |
| 26 | * @returns the pane's tree |
| 27 | */ |
| 28 | export function currentPane( |
| 29 | kit: Kit, |
| 30 | model: PaneState.PaneModel, |
| 31 | ): RenderElement { |
| 32 | const { Box } = kit.ui |
| 33 | const { data } = model |
| 34 | |
| 35 | if (model.isOutsideRepository) { |
| 36 | return <Box>{Sections.dimNote(kit, Names.NOT_IN_REPOSITORY_TEXT)}</Box> |
| 37 | } |
| 38 | |
| 39 | if (!data && !model.hasSettled) { |
| 40 | return <Box>{Sections.dimNote(kit, 'Loading diff…')}</Box> |
| 41 | } |
| 42 | |
| 43 | const noise = model.isNoiseShown ? 'shown' : 'hidden' |
| 44 | const preSession = model.isPreSessionShown ? 'shown' : 'hidden' |
| 45 | const partition = PaneState.partitionOf(data?.files ?? [], noise) |
| 46 | const totals = data |
| 47 | ? PaneState.headerTotalsOf(data, partition) |
| 48 | : PaneState.ZERO_TOTALS |
| 49 | const empty = PaneState.emptyStateOf(data, totals.filesCount, model.words) |
| 50 | const baseLabel = PaneState.baseLabelOf( |
| 51 | model.requestedMode, |
| 52 | data, |
| 53 | totals.filesCount, |
| 54 | model.words, |
| 55 | ) |
| 56 | const selected = PaneState.selectionOf( |
| 57 | PaneState.listedOf(partition, preSession), |
| 58 | model.selectedPath, |
| 59 | ) |
| 60 | const rowOf = (file: Git.FileStat): RenderElement => |
| 61 | Sections.fileRow(kit, fileRowOf(file, selected?.path ?? null), () => |
| 62 | kit.actions.selectFile(file.path), |
| 63 | ) |
| 64 | const noteOf = (text: string | null): RenderElement | null => |
| 65 | text === null ? null : Sections.dimNote(kit, Layout.sanitizeName(text)) |
| 66 | const noiseFace = model.isNoiseShown ? 'hide' : 'show' |
| 67 | const noiseCount = Layout.plural(partition.noiseCount, 'test') |
| 68 | const hasNoise = partition.noiseCount > 0 |
| 69 | const noiseToggle = hasNoise |
| 70 | ? Sections.toggleRow(kit, 'noise', { |
| 71 | label: `${noiseCount}/generated (${noiseFace})`, |
| 72 | onPress: kit.actions.toggleNoise, |
| 73 | }) |
| 74 | : null |
| 75 | const earlierFace = model.isPreSessionShown ? 'hide' : 'show' |
| 76 | const earlierCount = Layout.plural(partition.preSession.length, 'file') |
| 77 | const hasEarlier = partition.preSession.length > 0 |
| 78 | const earlierToggle = hasEarlier |
| 79 | ? Sections.toggleRow(kit, 'presession', { |
| 80 | label: `+${earlierCount} edited before this session (${earlierFace})`, |
| 81 | onPress: kit.actions.togglePreSession, |
| 82 | }) |
| 83 | : null |
| 84 | const earlierRows = model.isPreSessionShown ? partition.preSession : [] |
| 85 | const isUntrackedNoted = data?.isUntrackedWithheld === true && !empty |
| 86 | const listed = listBodyOf(kit, { data, partition, totals, empty }) |
| 87 | const detail = selected |
| 88 | ? [ |
| 89 | Sections.divider(kit), |
| 90 | Detail.detailView( |
| 91 | kit, |
| 92 | { |
| 93 | words: model.words, |
| 94 | path: selected.path, |
| 95 | renamedFrom: selected.renamedFrom, |
| 96 | isUntracked: selected.isUntracked, |
| 97 | isBinary: selected.isBinary, |
| 98 | body: model.body, |
| 99 | bodyState: model.bodyState, |
| 100 | isArmed: model.armedPath === selected.path, |
| 101 | }, |
| 102 | () => kit.actions.toggleAsk(selected.path), |
| 103 | ), |
| 104 | ] |
| 105 | : [] |
| 106 | |
| 107 | return ( |
| 108 | <Box flexDirection="column"> |
| 109 | {Sections.present([ |
| 110 | Sections.headerView(kit, empty?.headline ?? null, totals), |
| 111 | noteOf(baseLabel), |
| 112 | Sections.todoBar(kit, model.todos), |
| 113 | Sections.controlsView(kit, model), |
| 114 | noiseToggle, |
| 115 | ...listed.map(line => |
| 116 | typeof line === 'string' ? noteOf(line) : rowOf(line), |
| 117 | ), |
| 118 | noteOf(totals.notShown > 0 ? `${totals.notShown} not shown` : null), |
| 119 | noteOf( |
| 120 | isUntrackedNoted |
| 121 | ? Names.untrackedWithheldTextOf(model.words.lister) |
| 122 | : null, |
| 123 | ), |
| 124 | earlierToggle, |
| 125 | ...earlierRows.map(rowOf), |
| 126 | ...detail, |
| 127 | ])} |
| 128 | </Box> |
| 129 | ) |
| 130 | } |