@gjermundgaraba-designs/pixel-paper 0.20.1 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/DESIGN.md +21 -15
  2. package/dist/src/bench/bench.d.ts +14 -0
  3. package/dist/src/bench/bench.d.ts.map +1 -0
  4. package/dist/src/bench/bench.js +9 -0
  5. package/dist/src/bench/index.d.ts +3 -0
  6. package/dist/src/bench/index.d.ts.map +1 -0
  7. package/dist/src/bench/index.js +1 -0
  8. package/dist/src/chip/chip.d.ts +10 -0
  9. package/dist/src/chip/chip.d.ts.map +1 -1
  10. package/dist/src/chip/chip.js +19 -0
  11. package/dist/src/chip/index.d.ts +2 -2
  12. package/dist/src/chip/index.d.ts.map +1 -1
  13. package/dist/src/chip/index.js +1 -1
  14. package/dist/src/drag/drag.d.ts +18 -0
  15. package/dist/src/drag/drag.d.ts.map +1 -1
  16. package/dist/src/drag/drag.js +35 -7
  17. package/dist/src/field/field.d.ts +3 -0
  18. package/dist/src/field/field.d.ts.map +1 -1
  19. package/dist/src/field/field.js +2 -2
  20. package/dist/src/index.d.ts +1 -0
  21. package/dist/src/index.d.ts.map +1 -1
  22. package/dist/src/index.js +1 -0
  23. package/dist/src/lineDiff/index.d.ts +2 -0
  24. package/dist/src/lineDiff/index.d.ts.map +1 -1
  25. package/dist/src/lineDiff/index.js +1 -0
  26. package/dist/src/lineDiff/lineDiff.d.ts +8 -4
  27. package/dist/src/lineDiff/lineDiff.d.ts.map +1 -1
  28. package/dist/src/lineDiff/lineDiff.js +19 -15
  29. package/dist/src/lineDiff/patch.d.ts +35 -0
  30. package/dist/src/lineDiff/patch.d.ts.map +1 -0
  31. package/dist/src/lineDiff/patch.js +146 -0
  32. package/dist/src/menu/menu.d.ts +6 -6
  33. package/dist/src/rail/index.d.ts +1 -1
  34. package/dist/src/rail/index.d.ts.map +1 -1
  35. package/dist/src/rail/index.js +1 -1
  36. package/dist/src/rail/rail.d.ts +217 -17
  37. package/dist/src/rail/rail.d.ts.map +1 -1
  38. package/dist/src/rail/rail.js +133 -15
  39. package/dist/src/reel/index.d.ts +1 -1
  40. package/dist/src/reel/index.d.ts.map +1 -1
  41. package/dist/src/reel/index.js +1 -1
  42. package/dist/src/reel/layout.d.ts +21 -26
  43. package/dist/src/reel/layout.d.ts.map +1 -1
  44. package/dist/src/reel/layout.js +84 -106
  45. package/dist/src/reel/reel.d.ts +30 -172
  46. package/dist/src/reel/reel.d.ts.map +1 -1
  47. package/dist/src/reel/reel.js +144 -195
  48. package/dist/src/rows/rows.d.ts +9 -1
  49. package/dist/src/rows/rows.d.ts.map +1 -1
  50. package/dist/src/rows/rows.js +1 -1
  51. package/dist/src/sortable/sortable.d.ts +30 -30
  52. package/dist/src/toast/toast.d.ts +12 -12
  53. package/dist/src/window/window.d.ts +3 -1
  54. package/dist/src/window/window.d.ts.map +1 -1
  55. package/package.json +1 -1
  56. package/src/bench/bench.ts +24 -0
  57. package/src/bench/index.ts +2 -0
  58. package/src/chip/chip.ts +31 -0
  59. package/src/chip/index.ts +2 -2
  60. package/src/drag/drag.ts +60 -1
  61. package/src/field/field.ts +5 -1
  62. package/src/index.ts +1 -0
  63. package/src/lineDiff/index.ts +2 -0
  64. package/src/lineDiff/lineDiff.ts +29 -24
  65. package/src/lineDiff/patch.ts +218 -0
  66. package/src/pixel-paper.css +202 -32
  67. package/src/rail/index.ts +2 -0
  68. package/src/rail/rail.ts +181 -16
  69. package/src/reel/index.ts +0 -1
  70. package/src/reel/layout.ts +78 -118
  71. package/src/reel/reel.ts +108 -216
  72. package/src/rows/rows.ts +14 -2
  73. package/src/tokens.css +2 -1
  74. package/src/window/window.ts +3 -1
@@ -11,7 +11,8 @@ export type ViewConfig = Readonly<{
11
11
  }>;
12
12
  /** Configuration for rendering a unified diff with `patchView`. */
13
13
  export type PatchViewConfig = Readonly<{
14
- /** One file's unified diff, as `diff -u` or `git diff -- <path>` writes it. */
14
+ /** One file's unified diff, as `diff -u` or `git diff -- <path>` writes it, its git header
15
+ * included. */
15
16
  patch: string;
16
17
  /** Names the two sides for screen readers: `"Version 3 against version 4"`. */
17
18
  label: string;
@@ -23,8 +24,11 @@ export declare const view: <Message>(config: ViewConfig, h: HtmlBuilder<Message>
23
24
  /** A unified diff the caller already has (from a server, or `git diff -- <path>`) as `view`'s
24
25
  * table: its hunks' lines, numbered from their headers, and the unchanged lines between hunks
25
26
  * folded into a counted row. Lines past the last hunk are not in the patch, so nothing counts
26
- * them. An empty patch says there is no difference, as `view` does; anything but one file
27
- * with a hunk (text that is not a diff, a binary change, several files) says it cannot be
28
- * shown as lines. */
27
+ * them. What git's header says beyond the lines prints as a note line above the table, or in
28
+ * its place: a rename, a mode change, an empty or binary file (`describePatch` has the
29
+ * sentences). A file whose type changed (a file that became a symlink) is two sections, each
30
+ * its own table under one note, named for its side (`"<label>, as it was"`). An empty patch
31
+ * says there is no difference, as `view` does; text that is not a diff, or holds several
32
+ * files, says it cannot be shown as lines. */
29
33
  export declare const patchView: <Message>(config: PatchViewConfig, h: HtmlBuilder<Message>) => Html;
30
34
  //# sourceMappingURL=lineDiff.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lineDiff.d.ts","sourceRoot":"","sources":["../../../src/lineDiff/lineDiff.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiBtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd;mBACe;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AA2EH;;kFAEkF;AAClF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAO3E,CAAC;AAEF;;;;;sBAKsB;AACtB,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,eAAe,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAWrF,CAAC"}
1
+ {"version":3,"file":"lineDiff.d.ts","sourceRoot":"","sources":["../../../src/lineDiff/lineDiff.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAWtD,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;IACd;mBACe;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC;oBACgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAyEH;;kFAEkF;AAClF,eAAO,MAAM,IAAI,GAAI,OAAO,UAAU,UAAU,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAO3E,CAAC;AAEF;;;;;;;;+CAQ+C;AAC/C,eAAO,MAAM,SAAS,GAAI,OAAO,UAAU,eAAe,KAAK,WAAW,CAAC,OAAO,CAAC,KAAG,IAoBrF,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
- import { Array, Option, String } from "effect";
2
+ import { Array, Option } from "effect";
3
3
  import { LOCALE } from "../locale/locale.js";
4
- import { DiffRow, diffRowsOf, diffRowsOfPatch, foldUnchanged, hasChanges, } from "./diff.js";
4
+ import { DiffRow, diffRowsOf, foldUnchanged, hasChanges } from "./diff.js";
5
+ import { SAME_NOTE, readPatch } from "./patch.js";
5
6
  // VIEW
6
7
  const DEFAULT_CONTEXT = 2;
7
8
  const COLUMN_COUNT = 4;
@@ -29,7 +30,6 @@ const rowView = (row, h) => __foldkitBrandViewResult((DiffRow.match(row, {
29
30
  Fold: ({ count, firstOldNumber }) => __foldkitBrandViewResult((foldView(count, firstOldNumber, h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#Fold"),
30
31
  })), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#rowView");
31
32
  const noteView = (note, h) => __foldkitBrandViewResult((h.p([h.Class("note-line")], [note])), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#noteView");
32
- const SAME_NOTE = "No difference: both sides hold the same text.";
33
33
  const tableView = (rows, label, h) => __foldkitBrandViewResult((h.div([h.Class("diff-wrap")], [
34
34
  h.table([h.AriaLabel(label), h.Class("diff")], [
35
35
  h.tbody([], Array.map(rows, (row) => __foldkitBrandViewResult((rowView(row, h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#anonymous"))),
@@ -48,18 +48,22 @@ export const view = (config, h) => {
48
48
  /** A unified diff the caller already has (from a server, or `git diff -- <path>`) as `view`'s
49
49
  * table: its hunks' lines, numbered from their headers, and the unchanged lines between hunks
50
50
  * folded into a counted row. Lines past the last hunk are not in the patch, so nothing counts
51
- * them. An empty patch says there is no difference, as `view` does; anything but one file
52
- * with a hunk (text that is not a diff, a binary change, several files) says it cannot be
53
- * shown as lines. */
51
+ * them. What git's header says beyond the lines prints as a note line above the table, or in
52
+ * its place: a rename, a mode change, an empty or binary file (`describePatch` has the
53
+ * sentences). A file whose type changed (a file that became a symlink) is two sections, each
54
+ * its own table under one note, named for its side (`"<label>, as it was"`). An empty patch
55
+ * says there is no difference, as `view` does; text that is not a diff, or holds several
56
+ * files, says it cannot be shown as lines. */
54
57
  export const patchView = (config, h) => {
55
58
  const { patch, label } = config;
56
- if (String.isEmpty(String.trim(patch))) {
57
- return __foldkitBrandViewResult((noteView(SAME_NOTE, h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#patchView");
58
- }
59
- else {
60
- return __foldkitBrandViewResult((Option.match(diffRowsOfPatch(patch), {
61
- onNone: () => __foldkitBrandViewResult((noteView("This diff cannot be shown as lines.", h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onNone"),
62
- onSome: (rows) => __foldkitBrandViewResult((tableView(rows, label, h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onSome"),
63
- })), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#patchView");
64
- }
59
+ const { notes, tables } = readPatch(patch);
60
+ const parts = [
61
+ ...(Array.isReadonlyArrayNonEmpty(notes) ? [noteView(Array.join(notes, " "), h)] : []),
62
+ ...Array.map(tables, ({ rows, maybeSide }) => __foldkitBrandViewResult((tableView(rows, Option.match(maybeSide, { onNone: () => __foldkitBrandViewResult((label), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onNone"), onSome: (side) => __foldkitBrandViewResult((`${label}, ${side}`), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onSome") }), h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#anonymous~2")),
63
+ ];
64
+ // a lone table or note is drawn bare, so a flush window's body still meets its table
65
+ return __foldkitBrandViewResult((Array.match(parts, {
66
+ onEmpty: () => __foldkitBrandViewResult((noteView(SAME_NOTE, h)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onEmpty"),
67
+ onNonEmpty: ([part, ...others]) => __foldkitBrandViewResult((Array.isArrayEmpty(others) ? part : h.div([h.Class("stack gap-s")], parts)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#onNonEmpty"),
68
+ })), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/lineDiff.js#patchView");
65
69
  };
@@ -0,0 +1,35 @@
1
+ import { Option } from "effect";
2
+ import { type DiffRow } from "./diff.ts";
3
+ /** The name a path in git's header stands for: git C-quotes a name with unusual bytes
4
+ * (`"caf\303\251.txt"`), and leaves any other as it is. */
5
+ export declare const unquoted: (path: string) => string;
6
+ /** What a diff of two same texts says. */
7
+ export declare const SAME_NOTE = "No difference: both sides hold the same text.";
8
+ /** A table of the patch's lines; `maybeSide` says which side of a type change it is. */
9
+ type Table = Readonly<{
10
+ rows: ReadonlyArray<DiffRow>;
11
+ maybeSide: Option.Option<string>;
12
+ }>;
13
+ /** What `patchView` draws: its notes as a line, then its tables. */
14
+ export type PatchReading = Readonly<{
15
+ maybeRenamedFrom: Option.Option<string>;
16
+ notes: ReadonlyArray<string>;
17
+ tables: ReadonlyArray<Table>;
18
+ }>;
19
+ /** What `patchView` makes of a patch: the notes it prints and the tables it draws. */
20
+ export declare const readPatch: (patch: string) => PatchReading;
21
+ /** What a patch says beyond its lines, as `patchView` prints it. */
22
+ export type PatchDescription = Readonly<{
23
+ /** The path a rename left, unquoted: for a heading such as `old.txt → new.txt`. */
24
+ maybeRenamedFrom: Option.Option<string>;
25
+ /** The sentences `patchView` prints above the patch's lines, or in their place: a rename,
26
+ * a mode change, a type change, an empty or binary file, no difference, or a patch it
27
+ * cannot show as lines. */
28
+ notes: ReadonlyArray<string>;
29
+ }>;
30
+ /** What `patchView` says about a patch from `git diff`, read from its header: the notes it
31
+ * prints (`["Renamed from old.txt."]`), for a caller that prints them itself, and the path a
32
+ * rename left. */
33
+ export declare const describePatch: (patch: string) => PatchDescription;
34
+ export {};
35
+ //# sourceMappingURL=patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch.d.ts","sourceRoot":"","sources":["../../../src/lineDiff/patch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAgB,MAAM,QAAQ,CAAC;AAErD,OAAO,EAAE,KAAK,OAAO,EAAmB,MAAM,WAAW,CAAC;AAgC1D;4DAC4D;AAC5D,eAAO,MAAM,QAAQ,SAAU,MAAM,KAAG,MAO9B,CAAC;AAsCX,0CAA0C;AAC1C,eAAO,MAAM,SAAS,kDAAkD,CAAC;AAIzE,wFAAwF;AACxF,KAAK,KAAK,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,CAAC;AAE1F,oEAAoE;AACpE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;CAC9B,CAAC,CAAC;AAoFH,sFAAsF;AACtF,eAAO,MAAM,SAAS,UAAW,MAAM,KAAG,YAiBzC,CAAC;AAIF,oEAAoE;AACpE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,mFAAmF;IACnF,gBAAgB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxC;;gCAE4B;IAC5B,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9B,CAAC,CAAC;AAEH;;mBAEmB;AACnB,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,gBAI7C,CAAC"}
@@ -0,0 +1,146 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { Array, Option, String, pipe } from "effect";
3
+ import { diffRowsOfPatch } from "./diff.js";
4
+ // QUOTED PATHS
5
+ const ESCAPED_BYTES = {
6
+ a: 7,
7
+ b: 8,
8
+ t: 9,
9
+ n: 10,
10
+ v: 11,
11
+ f: 12,
12
+ r: 13,
13
+ };
14
+ // an octal escape is one byte of the name's UTF-8, so the bytes are gathered before decoding
15
+ const QUOTED_PART = /\\([0-7]{3})|\\(.)|[^\\]+/gu;
16
+ const bytesOf = (text) => __foldkitBrandViewResult(([...new TextEncoder().encode(text)]), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#bytesOf");
17
+ const bytesOfPart = ([part, octal, escaped]) => {
18
+ if (octal !== undefined) {
19
+ return __foldkitBrandViewResult(([Number.parseInt(octal, 8)]), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#bytesOfPart");
20
+ }
21
+ else if (escaped !== undefined) {
22
+ return __foldkitBrandViewResult((Option.match(Option.fromUndefinedOr(ESCAPED_BYTES[escaped]), {
23
+ onNone: () => __foldkitBrandViewResult((bytesOf(escaped)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#onNone"),
24
+ onSome: (byte) => __foldkitBrandViewResult(([byte]), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#onSome"),
25
+ })), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#bytesOfPart");
26
+ }
27
+ else {
28
+ return __foldkitBrandViewResult((bytesOf(part)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#bytesOfPart");
29
+ }
30
+ };
31
+ /** The name a path in git's header stands for: git C-quotes a name with unusual bytes
32
+ * (`"caf\303\251.txt"`), and leaves any other as it is. */
33
+ export const unquoted = (path) => __foldkitBrandViewResult((path.length >= 2 && path.startsWith('"') && path.endsWith('"')
34
+ ? new TextDecoder().decode(Uint8Array.from(Array.flatMap(Array.fromIterable(path.slice(1, -1).matchAll(QUOTED_PART)), bytesOfPart)))
35
+ : path), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#unquoted");
36
+ // HEADER
37
+ const GIT_SECTION = "diff --git ";
38
+ // the header is what comes before the first hunk, so a changed line that reads like a header
39
+ // line ("+rename from x") is never taken for one
40
+ const headOf = (section) => __foldkitBrandViewResult((Array.takeWhile(section.split("\n"), (line) => __foldkitBrandViewResult((!line.startsWith("@@") && !line.startsWith("--- ")), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous"))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#headOf");
41
+ const valueAfter = (head, prefix) => __foldkitBrandViewResult((pipe(Array.findFirst(head, String.startsWith(prefix)), Option.map((line) => __foldkitBrandViewResult((line.slice(prefix.length)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~2")))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#valueAfter");
42
+ const hasLine = (head, prefix) => __foldkitBrandViewResult((Option.isSome(valueAfter(head, prefix))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#hasLine");
43
+ const hasHunk = (section) => __foldkitBrandViewResult((Array.some(section.split("\n"), String.startsWith("@@ "))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#hasHunk");
44
+ // git writes one section per file, after whatever precedes the first (a commit's message, a
45
+ // mail's head); a patch without a git header is one section
46
+ const sectionsOf = (patch) => {
47
+ const [first = "", ...others] = patch.split(/(?=^diff --git )/mu);
48
+ return __foldkitBrandViewResult((Array.isArrayNonEmpty(others) && !first.startsWith(GIT_SECTION)
49
+ ? others
50
+ : [first, ...others]), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#sectionsOf");
51
+ };
52
+ // READING
53
+ /** What a diff of two same texts says. */
54
+ export const SAME_NOTE = "No difference: both sides hold the same text.";
55
+ const UNREADABLE_NOTE = "This diff cannot be shown as lines.";
56
+ const BINARY_NOTE = "A binary file: its change has no lines.";
57
+ const unreadable = {
58
+ maybeRenamedFrom: Option.none(),
59
+ notes: [UNREADABLE_NOTE],
60
+ tables: [],
61
+ };
62
+ const lineNote = (head, hasRows) => {
63
+ if (hasLine(head, "Binary files ") || hasLine(head, "GIT binary patch")) {
64
+ return __foldkitBrandViewResult((Option.some(BINARY_NOTE)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#lineNote");
65
+ }
66
+ else if (hasRows) {
67
+ return __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#lineNote");
68
+ }
69
+ else if (hasLine(head, "new file mode ")) {
70
+ return __foldkitBrandViewResult((Option.some("New empty file.")), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#lineNote");
71
+ }
72
+ else if (hasLine(head, "deleted file mode ")) {
73
+ return __foldkitBrandViewResult((Option.some("Deleted empty file.")), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#lineNote");
74
+ }
75
+ else {
76
+ return __foldkitBrandViewResult((Option.none()), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#lineNote");
77
+ }
78
+ };
79
+ const readSection = (section) => {
80
+ const head = headOf(section);
81
+ const maybeRows = diffRowsOfPatch(section);
82
+ const maybeRenamedFrom = Option.map(valueAfter(head, "rename from "), unquoted);
83
+ const notes = [
84
+ ...Option.toArray(Option.map(maybeRenamedFrom, (from) => __foldkitBrandViewResult((`Renamed from ${from}.`), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~3"))),
85
+ ...Option.toArray(Option.map(Option.all({ before: valueAfter(head, "old mode "), after: valueAfter(head, "new mode ") }), ({ before, after }) => __foldkitBrandViewResult((`Mode ${before} → ${after}.`), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~4"))),
86
+ ...Option.toArray(lineNote(head, Option.isSome(maybeRows))),
87
+ ];
88
+ const isUnread = Option.isNone(maybeRows) && (hasHunk(section) || Array.isArrayEmpty(notes));
89
+ return __foldkitBrandViewResult((isUnread
90
+ ? unreadable
91
+ : {
92
+ maybeRenamedFrom,
93
+ notes,
94
+ tables: Option.toArray(Option.map(maybeRows, (rows) => (__foldkitBrandViewResult(({ rows, maybeSide: Option.none() }), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~5")))),
95
+ }), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readSection");
96
+ };
97
+ const KINDS = {
98
+ "100644": "a file",
99
+ "100755": "an executable file",
100
+ "120000": "a symlink",
101
+ "160000": "a submodule",
102
+ };
103
+ const kindOf = (mode) => __foldkitBrandViewResult((KINDS[mode] ?? `mode ${mode}`), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#kindOf");
104
+ const sideTable = (section, side) => __foldkitBrandViewResult((Option.toArray(Option.map(diffRowsOfPatch(section), (rows) => (__foldkitBrandViewResult(({ rows, maybeSide: Option.some(side) }), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~6"))))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#sideTable");
105
+ // a file that became a symlink (or any other kind) is two sections for one path: the old
106
+ // kind deleted, then the new one added
107
+ const readTypeChange = (gone, added) => {
108
+ const [goneHead, addedHead] = [headOf(gone), headOf(added)];
109
+ return __foldkitBrandViewResult((Option.flatMap(Option.all({
110
+ before: valueAfter(goneHead, "deleted file mode "),
111
+ after: valueAfter(addedHead, "new file mode "),
112
+ }), ({ before, after }) => __foldkitBrandViewResult((goneHead[0] === addedHead[0]
113
+ ? Option.some({
114
+ maybeRenamedFrom: Option.none(),
115
+ notes: [`It was ${kindOf(before)} and is now ${kindOf(after)}.`],
116
+ tables: [...sideTable(gone, "as it was"), ...sideTable(added, "as it is")],
117
+ })
118
+ : Option.none()), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~7"))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readTypeChange");
119
+ };
120
+ /** What `patchView` makes of a patch: the notes it prints and the tables it draws. */
121
+ export const readPatch = (patch) => {
122
+ const text = patch.replaceAll("\r\n", "\n");
123
+ if (String.isEmpty(String.trim(text))) {
124
+ return __foldkitBrandViewResult(({ maybeRenamedFrom: Option.none(), notes: [SAME_NOTE], tables: [] }), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readPatch");
125
+ }
126
+ else {
127
+ const sections = sectionsOf(text);
128
+ const [first, second, ...rest] = sections;
129
+ if (first !== undefined && second === undefined) {
130
+ return __foldkitBrandViewResult((readSection(first)), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readPatch");
131
+ }
132
+ else if (first !== undefined && second !== undefined && Array.isArrayEmpty(rest)) {
133
+ return __foldkitBrandViewResult((Option.getOrElse(readTypeChange(first, second), () => __foldkitBrandViewResult((unreadable), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#anonymous~8"))), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readPatch");
134
+ }
135
+ else {
136
+ return __foldkitBrandViewResult((unreadable), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#readPatch");
137
+ }
138
+ }
139
+ };
140
+ /** What `patchView` says about a patch from `git diff`, read from its header: the notes it
141
+ * prints (`["Renamed from old.txt."]`), for a caller that prints them itself, and the path a
142
+ * rename left. */
143
+ export const describePatch = (patch) => {
144
+ const { maybeRenamedFrom, notes } = readPatch(patch);
145
+ return __foldkitBrandViewResult(({ maybeRenamedFrom, notes }), "@gjermundgaraba-designs/pixel-paper/src/lineDiff/patch.js#describePatch");
146
+ };
@@ -76,6 +76,8 @@ export declare const update: (model: Model, message: Message) => Readonly<{
76
76
  };
77
77
  commands?: Update.Commands<{
78
78
  readonly _tag: "CompletedFocus";
79
+ } | {
80
+ readonly _tag: "PressedEscape";
79
81
  } | {
80
82
  readonly _tag: "ClickedToggle";
81
83
  } | {
@@ -84,8 +86,6 @@ export declare const update: (model: Model, message: Message) => Readonly<{
84
86
  readonly _tag: "CompletedPlaceSlip";
85
87
  } | {
86
88
  readonly _tag: "LeftSlip";
87
- } | {
88
- readonly _tag: "PressedEscape";
89
89
  } | {
90
90
  readonly _tag: "PressedTab";
91
91
  } | {
@@ -125,11 +125,11 @@ export declare const BindSlip: Mount.MountDefinitionWithArgs<"BindSlip", {
125
125
  isEnd: Schema.Boolean;
126
126
  edge: Schema.Literals<readonly ["First", "Last"]>;
127
127
  }, {
128
+ readonly _tag: "PressedEscape";
129
+ } | {
128
130
  readonly _tag: "CompletedPlaceSlip";
129
131
  } | {
130
132
  readonly _tag: "LeftSlip";
131
- } | {
132
- readonly _tag: "PressedEscape";
133
133
  } | {
134
134
  readonly _tag: "PressedTab";
135
135
  }>;
@@ -175,6 +175,8 @@ export declare const view: import("foldkit/submodel").View<{
175
175
  readonly edge: "First" | "Last";
176
176
  }, {
177
177
  readonly _tag: "CompletedFocus";
178
+ } | {
179
+ readonly _tag: "PressedEscape";
178
180
  } | {
179
181
  readonly _tag: "ClickedToggle";
180
182
  } | {
@@ -183,8 +185,6 @@ export declare const view: import("foldkit/submodel").View<{
183
185
  readonly _tag: "CompletedPlaceSlip";
184
186
  } | {
185
187
  readonly _tag: "LeftSlip";
186
- } | {
187
- readonly _tag: "PressedEscape";
188
188
  } | {
189
189
  readonly _tag: "PressedTab";
190
190
  } | {
@@ -1,3 +1,3 @@
1
- export { FollowRailDrawer, HideRailDrawer, Message, Model, ShowRailDrawer, close, id, init, isOpen, update, view, } from "./rail.ts";
1
+ export { FollowRailDrawer, HideRailDrawer, Message, Model, OutMessage, ShowRailDrawer, close, id, init, isOpen, subscriptions, update, view, } from "./rail.ts";
2
2
  export type { InitConfig, ViewInputs } from "./rail.ts";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rail/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,KAAK,EACL,cAAc,EACd,KAAK,EACL,EAAE,EACF,IAAI,EACJ,MAAM,EACN,MAAM,EACN,IAAI,GACL,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/rail/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,OAAO,EACP,KAAK,EACL,UAAU,EACV,cAAc,EACd,KAAK,EACL,EAAE,EACF,IAAI,EACJ,MAAM,EACN,aAAa,EACb,MAAM,EACN,IAAI,GACL,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
@@ -1 +1 @@
1
- export { FollowRailDrawer, HideRailDrawer, Message, Model, ShowRailDrawer, close, id, init, isOpen, update, view, } from "./rail.js";
1
+ export { FollowRailDrawer, HideRailDrawer, Message, Model, OutMessage, ShowRailDrawer, close, id, init, isOpen, subscriptions, update, view, } from "./rail.js";