auto-select-file.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import type { Nullable } from '../../../../../types/utils'
  2. import type { FileDiff } from '../services/types/file'
  3. import type { FileOperation } from '../services/types/file-operation'
  4. import type { LoadedUpdate, Version } from '../services/types/update'
  5. import type { Selection } from '../services/types/selection'
  6. import { fileFinalPathname, isFileEditable } from './file-diff'
  7. type FileWithOps = {
  8. pathname: FileDiff['pathname']
  9. editable: boolean
  10. operation: FileOperation
  11. }
  12. function getFilesWithOps(
  13. files: FileDiff[],
  14. toV: Version,
  15. comparing: boolean,
  16. updateForToV: LoadedUpdate | undefined
  17. ): FileWithOps[] {
  18. if (toV && !comparing) {
  19. const filesWithOps: FileWithOps[] = []
  20. if (updateForToV) {
  21. const filesByPathname = new Map<string, FileDiff>()
  22. for (const file of files) {
  23. const pathname = fileFinalPathname(file)
  24. filesByPathname.set(pathname, file)
  25. }
  26. const isEditable = (pathname: string) => {
  27. const fileDiff = filesByPathname.get(pathname)
  28. if (!fileDiff) {
  29. return false
  30. }
  31. return isFileEditable(fileDiff)
  32. }
  33. for (const pathname of updateForToV.pathnames) {
  34. filesWithOps.push({
  35. pathname,
  36. editable: isEditable(pathname),
  37. operation: 'edited',
  38. })
  39. }
  40. for (const op of updateForToV.project_ops) {
  41. let pathAndOp: Nullable<Pick<FileWithOps, 'pathname' | 'operation'>> =
  42. null
  43. if (op.add) {
  44. pathAndOp = {
  45. pathname: op.add.pathname,
  46. operation: 'added',
  47. }
  48. } else if (op.remove) {
  49. pathAndOp = {
  50. pathname: op.remove.pathname,
  51. operation: 'removed',
  52. }
  53. } else if (op.rename) {
  54. pathAndOp = {
  55. pathname: op.rename.newPathname,
  56. operation: 'renamed',
  57. }
  58. }
  59. if (pathAndOp !== null) {
  60. filesWithOps.push({
  61. editable: isEditable(pathAndOp.pathname),
  62. ...pathAndOp,
  63. })
  64. }
  65. }
  66. }
  67. return filesWithOps
  68. } else {
  69. const filesWithOps = files.reduce((curFilesWithOps, file) => {
  70. if ('operation' in file) {
  71. curFilesWithOps.push({
  72. pathname: file.pathname,
  73. editable: isFileEditable(file),
  74. operation: file.operation,
  75. })
  76. }
  77. return curFilesWithOps
  78. }, <FileWithOps[]>[])
  79. return filesWithOps
  80. }
  81. }
  82. const orderedOpTypes: FileOperation[] = [
  83. 'edited',
  84. 'added',
  85. 'renamed',
  86. 'removed',
  87. ]
  88. export function autoSelectFile(
  89. files: FileDiff[],
  90. toV: Version,
  91. comparing: boolean,
  92. updateForToV: LoadedUpdate | undefined,
  93. previouslySelectedPathname: Selection['previouslySelectedPathname']
  94. ): FileDiff {
  95. const filesWithOps = getFilesWithOps(files, toV, comparing, updateForToV)
  96. const previouslySelectedFile = files.find(file => {
  97. return file.pathname === previouslySelectedPathname
  98. })
  99. const previouslySelectedFileHasOp = filesWithOps.some(file => {
  100. return file.pathname === previouslySelectedPathname
  101. })
  102. if (previouslySelectedFile && previouslySelectedFileHasOp) {
  103. return previouslySelectedFile
  104. }
  105. for (const opType of orderedOpTypes) {
  106. const fileWithMatchingOpType = filesWithOps.find(
  107. file => file.operation === opType && file.editable
  108. )
  109. if (fileWithMatchingOpType) {
  110. const fileToSelect = files.find(
  111. file => fileFinalPathname(file) === fileWithMatchingOpType.pathname
  112. )
  113. if (fileToSelect) {
  114. return fileToSelect
  115. }
  116. }
  117. }
  118. return (
  119. previouslySelectedFile ||
  120. files.find(file => /main\.tex$/.test(file.pathname)) ||
  121. files.find(file => /\.tex$/.test(file.pathname)) ||
  122. files[0]
  123. )
  124. }