history

tcmts.cli.main.history · #yz3ubicr · term · runs on the server

uses tcmts.cli.style.dim, which uses node:util

This branch's history, newest first: each entry, its message if it has one, the command that made it, and what it changed: by name, but for the definitions only re-hashed because a dependency changed, which are counted (a change to a definition much code uses re-hashes hundreds), unless all.

import type { Codebase } from "#codebase/tcmts/cli/codebase";
import { diffNamespaces } from "#codebase/tcmts/cli/diff";
import type { NameState } from "#codebase/tcmts/cli/diff";
import { nameChanges, stateAt } from "#codebase/tcmts/cli/main";
import { bold, dim, yellow } from "#codebase/tcmts/cli/style";
import { shortHash } from "#codebase/tcmts/core/hash";
import { entryTitle } from "#codebase/tcmts/store";

export function history(cb: Codebase, limit: number, all = false) {
  const irOf = (h: string) => cb.store.getDef(h)!.ir;
  const entries = cb.store.causalLog(limit + 1);
  for (const [i, c] of entries.slice(0, limit).entries()) {
    if (!c.parents.length) break;
    const when = new Date(c.ts).toISOString().replace("T", " ").slice(0, 19);
    const merge =
      c.parents.length > 1
        ? dim(
            `  merged ${c.parents
              .slice(1)
              .map((p) => shortHash(p))
              .join(", ")}`,
          )
        : "";
    console.log(
      `${yellow(shortHash(c.hash))} ${dim(String(i).padStart(3))}  ${dim(when)}  ${c.message ? bold(entryTitle(c)) : c.command}${merge}`,
    );
    // (a message: the rest of it, then the command that made the entry)
    if (c.message) {
      const body = c.message.split("\n").slice(1);
      if (body[0] === "") body.shift();
      for (const line of body) console.log(line ? `    ${line}` : "");
      console.log(dim(`    ${c.command}`));
    }
    const texts = {
      before: cb.store.textsAt(cb.store.causal(c.parents[0]!)!.namespace),
      after: cb.store.textsAt(c.namespace),
    };
    const [before, after] = [stateAt(cb, c.parents[0]!), stateAt(cb, c.hash)];
    const propagated = all
      ? new Set<string>()
      : new Set(diffNamespaces(before, after, irOf).propagated.map((p) => p.path));
    const without = (s: NameState): NameState =>
      new Map([...s].filter(([key]) => !propagated.has(key)));
    for (const line of nameChanges(without(before), without(after), texts)) console.log(line);
    if (propagated.size)
      console.log(
        dim(
          `    and ${propagated.size} updated because a dependency changed (\`tcm history --all\` lists them)`,
        ),
      );
  }
}

uses

used by