Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

A commit's hover hint is its subject, cut on a word past 160 characters (commitHint, lib/commit-message.ts): on flagon-io/g1t's Files list a commit whose subject runs to a paragraph filled the screen with its tooltip. The Files list, Branches, Compare and Tags each use it; Branches, Compare and Tags showed the whole message, body and trailers too. The commit's page has it all. Checked: apps/web tsc -b; npm test (988; new: a commit's hint).

G1t-Session:
ses_01m501jq3vetja2s4a904rs068
syntaqxcommitted Parentea32f46Browse files
6 files+37−50/6 viewed
+2−1
5959 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "./ui/table";
6060 import { PullIcon } from "./work-icons";
6161 import { isMerged } from "../lib/branches";
62+import { commitHint } from "../lib/commit-message";
6263
6364 /** What the page's action answers. */
6465 export type BranchActionData = { intent: string; branch?: string; hash?: string; error?: string };
149150 // browser, and the page then fails to hydrate.
150151 <span className="inline-flex items-center gap-1.5 whitespace-nowrap">
151152 <CommitAvatars commit={row.commit} size={18} max={2} />
152− <Hint label={row.commit.message}>
153+ <Hint label={commitHint(row.commit.message)}>
153154 <Link to={`${base}/commit/${row.commit.hash}`} className="text-muted hover:text-fg">
154155 <TimeAgo at={row.commit.at} />
155156 </Link>
+2−1
1515 import { CodeLines } from "./code-lines";
1616
1717 import { useAddresses } from "../lib/addresses";
18+import { commitHint } from "../lib/commit-message";
1819 import { type Failed, isFailed } from "../lib/partial";
1920 import { Boundary, Unavailable } from "./boundary";
2021 import { isImagePath } from "../lib/usercontent";
321322 </Link>
322323 <span className="hidden min-w-0 sm:block">
323324 {commit ? (
324− <Hint label={commit.message.split("\n")[0]}>
325+ <Hint label={commitHint(commit.message)}>
325326 <span className="block animate-fade-in truncate text-muted">
326327 <CommitText text={commit.message.split("\n")[0] ?? ""} base={base} to={`${base}/commit/${commit.hash}`} linkClassName="hover:text-fg hover:underline" />
327328 </span>
+13−1
11 import assert from "node:assert/strict";
22 import { test } from "node:test";
33
4−import { messageParts, parseCommitMessage } from "./commit-message.ts";
4+import { HINT_LIMIT, commitHint, messageParts, parseCommitMessage } from "./commit-message.ts";
55
66 test("co-authors leave the body and keep only their names", () => {
77 const parsed = parseCommitMessage(
6969 assert.deepEqual(messageParts(text), [{ kind: "text", text }], text);
7070 }
7171 });
72+
73+test("a commit's hint is its subject, cut on a word when it runs long", () => {
74+ assert.equal(commitHint("Fix the login\n\nBecause it broke."), "Fix the login");
75+ assert.equal(commitHint("\n\nOnly a body line"), "Only a body line");
76+ const long = `Sessions show by who is looking: ${"word ".repeat(80)}end`;
77+ const hint = commitHint(long);
78+ assert.ok(hint.length <= HINT_LIMIT, `${hint.length}`);
79+ assert.ok(hint.endsWith("…"));
80+ assert.ok(hint.startsWith("Sessions show by who is looking:"));
81+ assert.ok(!/\s…$/.test(hint));
82+ assert.equal(commitHint("x".repeat(400)).length, HINT_LIMIT);
83+});
+16−0
6969 if (at < text.length) parts.push({ kind: "text", text: text.slice(at) });
7070 return parts;
7171 }
72+
73+/** The most of a commit's subject a hover hint shows. */
74+export const HINT_LIMIT = 160;
75+
76+/**
77+ * A commit message as a hover hint: its subject, cut on a word with `…`
78+ * past [HINT_LIMIT] characters. Some subjects run to a paragraph, and a
79+ * hint is a glance, not the message: the commit's page has it all.
80+ */
81+export function commitHint(message: string, limit = HINT_LIMIT): string {
82+ const subject = (message.split("\n").find((line) => line.trim()) ?? "").trim();
83+ if (subject.length <= limit) return subject;
84+ const cut = subject.slice(0, limit - 1);
85+ const space = cut.lastIndexOf(" ");
86+ return `${(space > limit / 2 ? cut.slice(0, space) : cut).replace(/[\s,;:.–—-]+$/, "")}…`;
87+}
+2−1
1111 import { Hint } from "../../components/ui/hint";
1212 import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../components/ui/select";
1313 import { type HighlightedComparison, firstScreens } from "../../lib/diff";
14+import { commitHint } from "../../lib/commit-message";
1415 import { page } from "../../lib/meta";
1516 import { showCommits } from "../../lib/commit-people.server";
1617 import { repos } from "../../lib/services.server";
161162 <li key={commit.hash} className="flex items-center gap-3 px-4 py-2.5 text-sm">
162163 <GitCommitHorizontal size={15} className="shrink-0 text-faint" />
163164 <CommitAvatars commit={commit} size={16} max={2} />
164− <Hint label={commit.message}>
165+ <Hint label={commitHint(commit.message)}>
165166 <span className="min-w-0 grow truncate">
166167 <CommitText text={commit.message} base={repoBase} to={`${repoBase}/commit/${commit.hash}`} linkClassName="hover:text-accent" />
167168 </span>
+2−1
88 import { EmptyState, TimeAgo } from "../../components/ui";
99 import { Card } from "../../components/ui/card";
1010 import { Hint } from "../../components/ui/hint";
11+import { commitHint } from "../../lib/commit-message";
1112 import { page } from "../../lib/meta";
1213 import { commitChecksFor } from "../../lib/commit-checks.server";
1314 import { showCommits } from "../../lib/commit-people.server";
6667 <CommitNames commit={tag.commit} className="hover:text-fg" />
6768 </span>
6869 <span className="text-faint">·</span>
69− <Hint label={tag.commit.message}>
70+ <Hint label={commitHint(tag.commit.message)}>
7071 <span className="min-w-0 truncate">
7172 <CommitText text={tag.commit.message.split("\n")[0] ?? ""} base={base} to={`${base}/commit/${tag.commit.hash}`} linkClassName="hover:text-fg" />
7273 </span>

Comments

Sign in to comment.