johnandersen777.bsky.social/knotless
git that lives in your Atmosphere account
Forked from chadtmiller.com/knotless
0
0
// 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;
}