Refactor hunk viewer (and break it out from FileCard)

- necessary for aligning commit diff viewer and branch diff viewer
This commit is contained in:
Mattias Granlund 2024-01-31 13:22:28 +01:00
commit 4de440e444
4 changed files with 129 additions and 100 deletions

View File

@ -1,5 +1,5 @@
<script lang="ts">
import RenderedLine from './RenderedLine.svelte';
import HunkLine from './HunkLine.svelte';
import { invoke } from '$lib/backend/ipc';
import Button from '$lib/components/Button.svelte';
import Modal from '$lib/components/Modal.svelte';
@ -141,7 +141,7 @@
{#if 'hunk' in section}
{#each section.subSections as subsection}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<RenderedLine
<HunkLine
{line}
{minWidth}
sectionType={subsection.sectionType}

View File

@ -1,22 +1,19 @@
<script lang="ts">
import FileCardHeader from './FileCardHeader.svelte';
import HunkContextMenu from './HunkContextMenu.svelte';
import RenderedLine from './RenderedLine.svelte';
import HunkViewer from './HunkViewer.svelte';
import Icon from '$lib/components/Icon.svelte';
import Resizer from '$lib/components/Resizer.svelte';
import ScrollableContainer from '$lib/components/ScrollableContainer.svelte';
import { draggable } from '$lib/dragging/draggable';
import { draggableHunk } from '$lib/dragging/draggables';
import { persisted } from '$lib/persisted/persisted';
import { SETTINGS_CONTEXT, type SettingsStore } from '$lib/settings/userSettings';
import { ContentSection, HunkSection, parseFileSections } from '$lib/utils/fileSections';
import lscache from 'lscache';
import { onDestroy, getContext } from 'svelte';
import { getContext } from 'svelte';
import { quintOut } from 'svelte/easing';
import { slide } from 'svelte/transition';
import type { BranchController } from '$lib/vbranches/branchController';
import type { Ownership } from '$lib/vbranches/ownership';
import type { File, Hunk } from '$lib/vbranches/types';
import type { File } from '$lib/vbranches/types';
import type { Writable } from 'svelte/store';
export let projectId: string;
@ -37,16 +34,6 @@
const userSettings = getContext<SettingsStore>(SETTINGS_CONTEXT);
function updateContextMenu(file: File) {
if (popupMenu) popupMenu.$destroy();
return new HunkContextMenu({
target: document.body,
props: { projectPath, file, branchController }
});
}
$: popupMenu = updateContextMenu(file);
let sections: (HunkSection | ContentSection)[] = [];
function parseFile(file: File) {
@ -72,20 +59,6 @@
.filter((section): section is HunkSection => section instanceof HunkSection)
.some((section) => section.hunk.locked);
function onHunkSelected(hunk: Hunk, isSelected: boolean) {
if (isSelected) {
selectedOwnership.update((ownership) => ownership.addHunk(hunk.filePath, hunk.id));
} else {
selectedOwnership.update((ownership) => ownership.removeHunk(hunk.filePath, hunk.id));
}
}
onDestroy(() => {
if (popupMenu) {
popupMenu.$destroy();
}
});
function computedAddedRemoved(section: HunkSection | ContentSection): {
added: any;
removed: any;
@ -145,44 +118,18 @@
</div>
{/if}
</div>
<div
tabindex="0"
role="cell"
use:draggable={{
...draggableHunk(branchId, section.hunk),
disabled: isUnapplied || section.hunk.locked
}}
on:dblclick
class="hunk"
class:opacity-60={section.hunk.locked && !isFileLocked}
>
<div class="hunk__inner custom-scrollbar">
<div class="hunk__inner_inner">
{#each section.subSections as subsection}
{@const hunk = section.hunk}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<RenderedLine
{line}
{minWidth}
{selectable}
selected={$selectedOwnership.containsHunk(hunk.filePath, hunk.id)}
on:selected={(e) => onHunkSelected(hunk, e.detail)}
sectionType={subsection.sectionType}
filePath={file.path}
on:contextmenu={(e) =>
popupMenu.openByMouse(e, {
hunk,
section: subsection,
lineNumber: line.afterLineNumber
? line.afterLineNumber
: line.beforeLineNumber
})}
/>
{/each}
{/each}
</div>
</div>
</div>
<HunkViewer
{file}
{section}
{branchId}
{selectable}
{isUnapplied}
{projectPath}
{selectedOwnership}
{branchController}
{isFileLocked}
{minWidth}
/>
</div>
{/if}
{/each}
@ -259,35 +206,6 @@
flex-direction: column;
gap: var(--space-10);
}
.hunk {
display: flex;
flex-direction: column;
overflow-x: hidden;
&:focus-within {
& .hunk__inner {
overflow-x: auto;
border-color: var(--clr-theme-container-outline-pale);
}
}
}
.hunk__inner {
display: flex;
flex-direction: column;
overflow: hidden;
background: var(--clr-theme-container-light);
border-radius: var(--radius-s);
border: 1px solid var(--clr-theme-container-outline-light);
overflow-x: hidden;
transition: border-color var(--transition-fast);
user-select: text;
}
.hunk__inner_inner {
/* TODO: Rename this class */
width: 100%;
min-width: max-content;
user-select: text !important;
cursor: grab;
}
.indicators {
display: flex;
align-items: center;

View File

@ -58,7 +58,7 @@
</button>
</div>
<div
class="line flex-grow overflow-hidden whitespace-pre pl-0.5"
class="line"
class:diff-line-deletion={sectionType === SectionType.RemovedLines}
class:diff-line-addition={sectionType === SectionType.AddedLines}
>
@ -75,6 +75,12 @@
min-width: max-content;
font-family: monospace;
background-color: var(----clr-theme-container-light);
white-space: pre;
}
.line {
flex-grow: 1;
cursor: grab;
}
.code-line__numbers-line {
@ -86,5 +92,6 @@
.selectable-wrapper {
cursor: text;
display: inline-block;
padding-left: var(--space-4);
}
</style>

View File

@ -0,0 +1,104 @@
<script lang="ts">
import HunkContextMenu from './HunkContextMenu.svelte';
import HunkLine from './HunkLine.svelte';
import { draggable } from '$lib/dragging/draggable';
import { draggableHunk } from '$lib/dragging/draggables';
import { onDestroy } from 'svelte';
import type { HunkSection } from '$lib/utils/fileSections';
import type { BranchController } from '$lib/vbranches/branchController';
import type { Ownership } from '$lib/vbranches/ownership';
import type { File } from '$lib/vbranches/types';
import type { Hunk } from '$lib/vbranches/types';
import type { Writable } from 'svelte/store';
export let file: File;
export let section: HunkSection;
export let branchId: string;
export let projectPath: string | undefined;
export let minWidth: number;
export let selectable = false;
export let isUnapplied: boolean;
export let isFileLocked: boolean;
export let branchController: BranchController;
export let selectedOwnership: Writable<Ownership>;
function onHunkSelected(hunk: Hunk, isSelected: boolean) {
if (isSelected) {
selectedOwnership.update((ownership) => ownership.addHunk(hunk.filePath, hunk.id));
} else {
selectedOwnership.update((ownership) => ownership.removeHunk(hunk.filePath, hunk.id));
}
}
function updateContextMenu(file: File) {
if (popupMenu) popupMenu.$destroy();
return new HunkContextMenu({
target: document.body,
props: { projectPath, file, branchController }
});
}
$: popupMenu = updateContextMenu(file);
onDestroy(() => {
if (popupMenu) {
popupMenu.$destroy();
}
});
</script>
<div
tabindex="0"
role="cell"
use:draggable={{
...draggableHunk(branchId, section.hunk),
disabled: isUnapplied || section.hunk.locked
}}
on:contextmenu|preventDefault
class="hunk"
class:opacity-60={section.hunk.locked && !isFileLocked}
>
<div class="hunk__bg-stretch">
{#each section.subSections as subsection}
{@const hunk = section.hunk}
{#each subsection.lines.slice(0, subsection.expanded ? subsection.lines.length : 0) as line}
<HunkLine
{line}
{minWidth}
{selectable}
selected={$selectedOwnership.containsHunk(hunk.filePath, hunk.id)}
on:selected={(e) => onHunkSelected(hunk, e.detail)}
sectionType={subsection.sectionType}
filePath={file.path}
on:contextmenu={(e) =>
popupMenu.openByMouse(e, {
hunk,
section: subsection,
lineNumber: line.afterLineNumber ? line.afterLineNumber : line.beforeLineNumber
})}
/>
{/each}
{/each}
</div>
</div>
<style lang="postcss">
.hunk {
display: flex;
flex-direction: column;
overflow-x: auto;
cursor: grab;
background: var(--clr-theme-container-light);
border-radius: var(--radius-s);
border: 1px solid var(--clr-theme-container-outline-light);
transition: border-color var(--transition-fast);
}
.hunk__bg-stretch {
width: 100%;
min-width: max-content;
}
</style>