From 00467ba31c4b70ef27d16737940ade1d48a059cc Mon Sep 17 00:00:00 2001 From: estib Date: Mon, 31 Mar 2025 11:13:22 +0200 Subject: [PATCH] Unified diff: File deletions can't be partially selected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t let the user partially select the hunk if they are file deletions --- .../src/components/v3/UnifiedDiffView.svelte | 12 ++++++--- apps/desktop/src/lib/hunks/hunk.ts | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/components/v3/UnifiedDiffView.svelte b/apps/desktop/src/components/v3/UnifiedDiffView.svelte index 7e0ecb0ebd..4986b32e12 100644 --- a/apps/desktop/src/components/v3/UnifiedDiffView.svelte +++ b/apps/desktop/src/components/v3/UnifiedDiffView.svelte @@ -3,6 +3,7 @@ import HunkContextMenu from '$components/v3/HunkContextMenu.svelte'; import LineSelection from '$components/v3/unifiedDiffLineSelection.svelte'; import { DiffService } from '$lib/hunks/diffService.svelte'; + import { canBePartiallySelected, type DiffHunk } from '$lib/hunks/hunk'; import { Project } from '$lib/project/project'; import { ChangeSelectionService, @@ -13,7 +14,6 @@ import { getContextStoreBySymbol, inject } from '@gitbutler/shared/context'; import HunkDiff from '@gitbutler/ui/HunkDiff.svelte'; import type { TreeChange } from '$lib/hunks/change'; - import type { DiffHunk } from '$lib/hunks/hunk'; import type { LineId } from '@gitbutler/ui/utils/diffParsing'; type Props = { @@ -173,8 +173,14 @@ diffFont={$userSettings.diffFont} diffContrast={$userSettings.diffContrast} inlineUnifiedDiffs={$userSettings.inlineUnifiedDiffs} - onLineClick={(p) => - lineSelection.toggleStageLines(selection, hunk, p, diff.subject.hunks)} + onLineClick={(p) => { + if (!canBePartiallySelected(diff.subject)) { + const select = selection === undefined; + updateStage(hunk, select, diff.subject.hunks); + return; + } + lineSelection.toggleStageLines(selection, hunk, p, diff.subject.hunks); + }} onChangeStage={(selected) => { updateStage(hunk, selected, diff.subject.hunks); }} diff --git a/apps/desktop/src/lib/hunks/hunk.ts b/apps/desktop/src/lib/hunks/hunk.ts index 30f2dba3ec..5ae6af2409 100644 --- a/apps/desktop/src/lib/hunks/hunk.ts +++ b/apps/desktop/src/lib/hunks/hunk.ts @@ -247,3 +247,28 @@ export type Patch = { /** All non-overlapping hunks, including their context lines. */ readonly hunks: DiffHunk[]; }; + +export function isFileDeletionHunk(hunk: DiffHunk): boolean { + return hunk.newStart === 1 && hunk.newLines === 0; +} + +export function isFileAdditionHunk(hunk: DiffHunk): boolean { + return hunk.oldStart === 1 && hunk.oldLines === 0; +} + +export function canBePartiallySelected(patch: Patch): boolean { + if (patch.hunks.length === 0) { + // Should never happen, but just in case + return false; + } + + if (patch.hunks.length === 1 && isFileDeletionHunk(patch.hunks[0]!)) { + // Only one hunk and it's a file deletion + return false; + } + + // TODO: Check if the hunks come from the diff filter + // See: https://github.com/gitbutlerapp/gitbutler/pull/7893 + + return true; +}