Skip to content

Latest commit

 

History

History
134 lines (103 loc) · 4.92 KB

File metadata and controls

134 lines (103 loc) · 4.92 KB

OpenTUI component

hunkdiff/opentui exports HunkDiffView, a reusable terminal diff component built from the same renderer as the Hunk CLI.

Use it when you want Hunk's split or stack diff view inside your own OpenTUI app.

Install

npm i hunkdiff @opentui/core @opentui/react react

hunkdiff declares OpenTUI and React as peer dependencies, so install them in your app.

Quick start

import { createCliRenderer } from "@opentui/core";
import { createRoot } from "@opentui/react";
import { HunkDiffView, parseDiffFromFile } from "hunkdiff/opentui";

const metadata = parseDiffFromFile(
  {
    cacheKey: "before",
    contents: "export const value = 1;\n",
    name: "example.ts",
  },
  {
    cacheKey: "after",
    contents: "export const value = 2;\nexport const added = true;\n",
    name: "example.ts",
  },
  { context: 3 },
  true,
);

const renderer = await createCliRenderer({
  useAlternateScreen: true,
  useMouse: true,
  exitOnCtrlC: true,
});
const root = createRoot(renderer);

root.render(
  <HunkDiffView
    diff={{
      id: "example",
      metadata,
      language: "typescript",
      path: "example.ts",
    }}
    layout="split"
    width={88}
    theme="midnight"
  />,
);

In a real app, derive width from your layout or useTerminalDimensions().

Building the diff input

HunkDiffView renders one file at a time. Pass a diff object shaped like this:

type HunkDiffFile = {
  id: string;
  metadata: FileDiffMetadata;
  language?: string;
  path?: string;
  patch?: string;
};

From before/after contents

Use parseDiffFromFile(...) when you already have the old and new file contents.

import { parseDiffFromFile } from "hunkdiff/opentui";

const metadata = parseDiffFromFile(beforeFile, afterFile, { context: 3 }, true);

From unified diff text

Use parsePatchFiles(...) when you already have a patch string.

import { parsePatchFiles } from "hunkdiff/opentui";

const parsed = parsePatchFiles(patchText, "example:patch", true);
const metadata = parsed.flatMap((entry) => entry.files)[0];

if (!metadata) {
  throw new Error("Expected at least one diff file.");
}

Props

Prop Type Default Notes
diff HunkDiffFile undefined File to render. When omitted, the component shows an empty-state message.
layout "split" | "stack" "split" Chooses side-by-side or stacked rendering.
width number Required content width in terminal columns.
theme "graphite" | "midnight" | "paper" | "ember" "graphite" Matches Hunk's built-in themes.
showLineNumbers boolean true Toggles line-number columns.
showHunkHeaders boolean true Toggles @@ ... @@ hunk header rows.
wrapLines boolean false Wraps long lines instead of clipping horizontally.
horizontalOffset number 0 Scroll offset for non-wrapped code rows.
highlight boolean true Enables syntax highlighting.
scrollable boolean true Set to false if your parent view owns scrolling.
selectedHunkIndex number 0 Highlights one hunk as the active target.

Other exports

  • parseDiffFromFile
  • parsePatchFiles
  • FileDiffMetadata
  • HUNK_DIFF_THEME_NAMES
  • HunkDiffThemeName
  • HunkDiffLayout
  • HunkDiffFile
  • HunkDiffViewProps

parseDiffFromFile, parsePatchFiles, and FileDiffMetadata are re-exported from @pierre/diffs so you can build metadata without adding a second diff dependency.

Examples

The in-repo demos import from ../../src/opentui so they run from source. Published consumers should import from hunkdiff/opentui.