~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
63 lines · 2.7 KB Raw History
// A pull's files, listed without their rows but for the first few, and
// the rows of the rest fetched as a reader comes to them:
// dev.knotless.getThread with `filesOnly` and `firstRows`, then
// dev.knotless.getPullDiff a few files at a time. A commit's the same way,
// by dev.knotless.getCommit's `firstRows` and then its `paths`
// (later.svelte.ts).

import type { FileDiffView, RepoViewBasic } from '#lib/lexicons/dev/knotless/defs.ts';
import type { AtUriString } from '@atproto/lex';
import { repoHref, urlPath } from '#lib/format.ts';

/** The most lines a file changes before its rows wait to be asked for. */
export const HELD = 400;

/** How many files one getPullDiff asks for. */
export const BATCH = 10;

/** The cookie that keeps whether the viewer last showed a pull's file tree. */
export const TREE = 'tree';

/**
 * Where a diff's files are after the change: in the repository `repo` at
 * the commit `rev`, which the lines a diff leaves out are read from, and
 * on the page `view` gives for a file's path.
 */
export type Source = { repo: AtUriString; rev: string; view: (path: string) => string };

/** The files of `on` at the commit `rev`, each shown on its page at `ref`: a branch, or the commit itself. */
export const sourceAt = (on: RepoViewBasic, rev: string, ref = rev): Source => ({
	repo: `at://${on.did}/dev.knotless.repo/${on.name}`,
	rev,
	view: (path) => repoHref(on.handle, on.name, `/blob/${urlPath(ref)}/${urlPath(path)}`)
});

/** Whether the cookie `TREE` says to show the tree, or null where it says nothing and the screen's width decides. */
export const treeShown = (said: string | undefined): boolean | null =>
	said === 'shown' ? true : said === 'hidden' ? false : null;

/** The path a file goes by: where it is after the change, or was, if deleted. */
export const pathOf = (f: FileDiffView) => (f.status === 'deleted' ? f.old : f.new);

/** The paths getPullDiff finds `f` by: both of a renamed file's. */
export const pathsOf = (f: FileDiffView) => (f.status === 'renamed' ? [f.old, f.new] : [pathOf(f)]);

/** Whether `f`'s rows are still to fetch: listed without them, and with no note saying why none show. */
export const unfetched = (f: FileDiffView) => f.note === undefined && f.rows.length === 0;

/** Whether `f` changes so much that its rows wait to be asked for. */
export const held = (f: FileDiffView) => f.added + f.removed > HELD;

/** Which of `asked`, by index into `files`, each of `got` is. */
export function matched(
	files: FileDiffView[],
	asked: number[],
	got: FileDiffView[]
): Map<number, FileDiffView> {
	const out = new Map<number, FileDiffView>();
	for (const g of got) {
		const i = asked.find((i) => files[i].old === g.old && files[i].new === g.new);
		if (i !== undefined) out.set(i, g);
	}
	return out;
}