commented-lines.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import { type SelectedLineRange } from "@pierre/diffs"
  2. import { diffLineIndex, diffRowIndex } from "./diff-selection"
  3. export type CommentSide = "additions" | "deletions"
  4. function annotationIndex(node: HTMLElement) {
  5. const value = node.dataset.lineAnnotation?.split(",")[1]
  6. if (!value) return
  7. const line = parseInt(value, 10)
  8. if (Number.isNaN(line)) return
  9. return line
  10. }
  11. function clear(root: ShadowRoot) {
  12. const marked = Array.from(root.querySelectorAll("[data-comment-selected]"))
  13. for (const node of marked) {
  14. if (!(node instanceof HTMLElement)) continue
  15. node.removeAttribute("data-comment-selected")
  16. }
  17. }
  18. export function markCommentedDiffLines(root: ShadowRoot, ranges: SelectedLineRange[]) {
  19. clear(root)
  20. const diffs = root.querySelector("[data-diff]")
  21. if (!(diffs instanceof HTMLElement)) return
  22. const split = diffs.dataset.diffType === "split"
  23. const rows = Array.from(diffs.querySelectorAll("[data-line-index]")).filter(
  24. (node): node is HTMLElement => node instanceof HTMLElement,
  25. )
  26. if (rows.length === 0) return
  27. const annotations = Array.from(diffs.querySelectorAll("[data-line-annotation]")).filter(
  28. (node): node is HTMLElement => node instanceof HTMLElement,
  29. )
  30. for (const range of ranges) {
  31. const start = diffRowIndex(root, split, range.start, range.side as CommentSide | undefined)
  32. if (start === undefined) continue
  33. const end = (() => {
  34. const same = range.end === range.start && (range.endSide == null || range.endSide === range.side)
  35. if (same) return start
  36. return diffRowIndex(root, split, range.end, (range.endSide ?? range.side) as CommentSide | undefined)
  37. })()
  38. if (end === undefined) continue
  39. const first = Math.min(start, end)
  40. const last = Math.max(start, end)
  41. for (const row of rows) {
  42. const idx = diffLineIndex(split, row)
  43. if (idx === undefined || idx < first || idx > last) continue
  44. row.setAttribute("data-comment-selected", "")
  45. }
  46. for (const annotation of annotations) {
  47. const idx = annotationIndex(annotation)
  48. if (idx === undefined || idx < first || idx > last) continue
  49. annotation.setAttribute("data-comment-selected", "")
  50. }
  51. }
  52. }
  53. export function markCommentedFileLines(root: ShadowRoot, ranges: SelectedLineRange[]) {
  54. clear(root)
  55. const annotations = Array.from(root.querySelectorAll("[data-line-annotation]")).filter(
  56. (node): node is HTMLElement => node instanceof HTMLElement,
  57. )
  58. for (const range of ranges) {
  59. const start = Math.max(1, Math.min(range.start, range.end))
  60. const end = Math.max(range.start, range.end)
  61. for (let line = start; line <= end; line++) {
  62. const nodes = Array.from(root.querySelectorAll(`[data-line="${line}"], [data-column-number="${line}"]`))
  63. for (const node of nodes) {
  64. if (!(node instanceof HTMLElement)) continue
  65. node.setAttribute("data-comment-selected", "")
  66. }
  67. }
  68. for (const annotation of annotations) {
  69. const line = annotationIndex(annotation)
  70. if (line === undefined || line < start || line > end) continue
  71. annotation.setAttribute("data-comment-selected", "")
  72. }
  73. }
  74. }