diff.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import {
  2. type FileContents,
  3. FileDiff,
  4. type DiffLineAnnotation,
  5. type HunkData,
  6. DiffFileRendererOptions,
  7. // registerCustomTheme,
  8. } from "@pierre/precision-diffs"
  9. import { ComponentProps, createEffect, splitProps } from "solid-js"
  10. export type DiffProps<T = {}> = Omit<DiffFileRendererOptions<T>, "themes"> & {
  11. before: FileContents
  12. after: FileContents
  13. annotations?: DiffLineAnnotation<T>[]
  14. class?: string
  15. classList?: ComponentProps<"div">["classList"]
  16. }
  17. // registerCustomTheme("opencode", () => import("./theme.json"))
  18. // interface ThreadMetadata {
  19. // threadId: string
  20. // }
  21. export function Diff<T>(props: DiffProps<T>) {
  22. let container!: HTMLDivElement
  23. const [local, others] = splitProps(props, ["before", "after", "class", "classList", "annotations"])
  24. // const lineAnnotations: DiffLineAnnotation<ThreadMetadata>[] = [
  25. // {
  26. // side: "additions",
  27. // // The line number specified for an annotation is the visual line number
  28. // // you see in the number column of a diff
  29. // lineNumber: 16,
  30. // metadata: { threadId: "68b329da9893e34099c7d8ad5cb9c940" },
  31. // },
  32. // ]
  33. // If you ever want to update the options for an instance, simple call
  34. // 'setOptions' with the new options. Bear in mind, this does NOT merge
  35. // existing properties, it's a full replace
  36. // instance.setOptions({
  37. // ...instance.options,
  38. // theme: "pierre-dark",
  39. // themes: undefined,
  40. // })
  41. // When ready to render, simply call .render with old/new file, optional
  42. // annotations and a container element to hold the diff
  43. createEffect(() => {
  44. const instance = new FileDiff<T>({
  45. theme: "pierre-light",
  46. // Or can also provide a 'themes' prop, which allows the code to adapt
  47. // to your OS light or dark theme
  48. // themes: { dark: 'pierre-night', light: 'pierre-light' },
  49. // When using the 'themes' prop, 'themeType' allows you to force 'dark'
  50. // or 'light' theme, or inherit from the OS ('system') theme.
  51. themeType: "system",
  52. // Disable the line numbers for your diffs, generally not recommended
  53. disableLineNumbers: false,
  54. // Whether code should 'wrap' with long lines or 'scroll'.
  55. overflow: "scroll",
  56. // Normally you shouldn't need this prop, but if you don't provide a
  57. // valid filename or your file doesn't have an extension you may want to
  58. // override the automatic detection. You can specify that language here:
  59. // https://shiki.style/languages
  60. // lang?: SupportedLanguages;
  61. // 'diffStyle' controls whether the diff is presented side by side or
  62. // in a unified (single column) view
  63. diffStyle: "unified",
  64. // Line decorators to help highlight changes.
  65. // 'bars' (default):
  66. // Shows some red-ish or green-ish (theme dependent) bars on the left
  67. // edge of relevant lines
  68. //
  69. // 'classic':
  70. // shows '+' characters on additions and '-' characters on deletions
  71. //
  72. // 'none':
  73. // No special diff indicators are shown
  74. diffIndicators: "bars",
  75. // By default green-ish or red-ish background are shown on added and
  76. // deleted lines respectively. Disable that feature here
  77. disableBackground: false,
  78. // Diffs are split up into hunks, this setting customizes what to show
  79. // between each hunk.
  80. //
  81. // 'line-info' (default):
  82. // Shows a bar that tells you how many lines are collapsed. If you are
  83. // using the oldFile/newFile API then you can click those bars to
  84. // expand the content between them
  85. //
  86. // 'metadata':
  87. // Shows the content you'd see in a normal patch file, usually in some
  88. // format like '@@ -60,6 +60,22 @@'. You cannot use these to expand
  89. // hidden content
  90. //
  91. // 'simple':
  92. // Just a subtle bar separator between each hunk
  93. // hunkSeparators: "line-info",
  94. hunkSeparators(hunkData: HunkData) {
  95. const fragment = document.createDocumentFragment()
  96. const numCol = document.createElement("div")
  97. numCol.textContent = `${hunkData.lines}`
  98. numCol.style.position = "sticky"
  99. numCol.style.left = "0"
  100. numCol.style.backgroundColor = "var(--pjs-bg)"
  101. numCol.style.zIndex = "2"
  102. fragment.appendChild(numCol)
  103. const contentCol = document.createElement("div")
  104. contentCol.textContent = "unmodified lines"
  105. contentCol.style.position = "sticky"
  106. contentCol.style.width = "var(--pjs-column-content-width)"
  107. contentCol.style.left = "var(--pjs-column-number-width)"
  108. fragment.appendChild(contentCol)
  109. return fragment
  110. },
  111. // On lines that have both additions and deletions, we can run a
  112. // separate diff check to mark parts of the lines that change.
  113. // 'none':
  114. // Do not show these secondary highlights
  115. //
  116. // 'char':
  117. // Show changes at a per character granularity
  118. //
  119. // 'word':
  120. // Show changes but rounded up to word boundaries
  121. //
  122. // 'word-alt' (default):
  123. // Similar to 'word', however we attempt to minimize single character
  124. // gaps between highlighted changes
  125. lineDiffType: "word-alt",
  126. // If lines exceed these character lengths then we won't perform the
  127. // line lineDiffType check
  128. maxLineDiffLength: 1000,
  129. // If any line in the diff exceeds this value then we won't attempt to
  130. // syntax highlight the diff
  131. maxLineLengthForHighlighting: 1000,
  132. // Enabling this property will hide the file header with file name and
  133. // diff stats.
  134. disableFileHeader: true,
  135. // You can optionally pass a render function for rendering out line
  136. // annotations. Just return the dom node to render
  137. // renderAnnotation(annotation: DiffLineAnnotation<T>): HTMLElement {
  138. // // Despite the diff itself being rendered in the shadow dom,
  139. // // annotations are inserted via the web components 'slots' api and you
  140. // // can use all your normal normal css and styling for them
  141. // const element = document.createElement("div")
  142. // element.innerText = annotation.metadata.threadId
  143. // return element
  144. // },
  145. ...others,
  146. })
  147. instance.render({
  148. oldFile: local.before,
  149. newFile: local.after,
  150. lineAnnotations: local.annotations,
  151. containerWrapper: container,
  152. })
  153. })
  154. return (
  155. <div
  156. style={{
  157. "--pjs-font-family": "var(--font-family-mono)",
  158. "--pjs-font-size": "var(--font-size-small)",
  159. "--pjs-line-height": "24px",
  160. "--pjs-tab-size": 4,
  161. "--pjs-font-features": "var(--font-family-mono--font-feature-settings)",
  162. "--pjs-header-font-family": "var(--font-family-sans)",
  163. }}
  164. ref={container}
  165. />
  166. )
  167. }