ediff-diff.el 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483
  1. ;;; ediff-diff.el --- diff-related utilities
  2. ;; Copyright (C) 1994-2015 Free Software Foundation, Inc.
  3. ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
  4. ;; Package: ediff
  5. ;; This file is part of GNU Emacs.
  6. ;; GNU Emacs is free software: you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation, either version 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;; Code:
  18. (provide 'ediff-diff)
  19. (require 'ediff-init)
  20. (require 'ediff-util)
  21. (defgroup ediff-diff nil
  22. "Diff related utilities."
  23. :prefix "ediff-"
  24. :group 'ediff)
  25. (defcustom ediff-diff-program "diff"
  26. "Program to use for generating the differential of the two files."
  27. :type 'string
  28. :group 'ediff-diff)
  29. (defcustom ediff-diff3-program "diff3"
  30. "Program to be used for three-way comparison.
  31. Must produce output compatible with Unix's diff3 program."
  32. :type 'string
  33. :group 'ediff-diff)
  34. ;; The following functions must precede all defcustom-defined variables.
  35. (fset 'ediff-set-actual-diff-options (lambda () nil))
  36. (defcustom ediff-shell
  37. (cond ((memq system-type '(ms-dos windows-nt))
  38. shell-file-name) ; no standard name on MS-DOS
  39. (t "sh")) ; UNIX
  40. "The shell used to run diff and patch.
  41. If user's .profile or .cshrc files are set up correctly, any shell
  42. will do. However, some people set $prompt or other things
  43. incorrectly, which leads to undesirable output messages. These may
  44. cause Ediff to fail. In such a case, set `ediff-shell' to a shell that
  45. you are not using or, better, fix your shell's startup file."
  46. :type 'string
  47. :group 'ediff-diff)
  48. (defcustom ediff-cmp-program "cmp"
  49. "Utility to use to determine if two files are identical.
  50. It must return code 0, if its arguments are identical files."
  51. :type 'string
  52. :group 'ediff-diff)
  53. (defcustom ediff-cmp-options nil
  54. "Options to pass to `ediff-cmp-program'.
  55. If GNU diff is used as `ediff-cmp-program', then the most useful options
  56. are `-I REGEXP', to ignore changes whose lines match the REGEXP."
  57. :type '(repeat string)
  58. :group 'ediff-diff)
  59. (defun ediff-set-diff-options (symbol value)
  60. (set symbol value)
  61. (ediff-set-actual-diff-options))
  62. (defcustom ediff-diff-options
  63. (if (memq system-type '(ms-dos windows-nt)) "--binary" "")
  64. "Options to pass to `ediff-diff-program'.
  65. If Unix diff is used as `ediff-diff-program',
  66. then a useful option is `-w', to ignore space.
  67. Options `-c', `-u', and `-i' are not allowed. Case sensitivity can be
  68. toggled interactively using \\[ediff-toggle-ignore-case].
  69. Do not remove the default options. If you need to change this variable, add new
  70. options after the default ones.
  71. This variable is not for customizing the look of the differences produced by
  72. the command \\[ediff-show-diff-output]. Use the variable
  73. `ediff-custom-diff-options' for that."
  74. :set 'ediff-set-diff-options
  75. :type 'string
  76. :group 'ediff-diff)
  77. (ediff-defvar-local ediff-ignore-case nil
  78. "If t, skip over difference regions that differ only in letter case.
  79. This variable can be set either in .emacs or toggled interactively.
  80. Use `setq-default' if setting it in .emacs")
  81. (defcustom ediff-ignore-case-option "-i"
  82. "Option that causes the diff program to ignore case of letters."
  83. :type 'string
  84. :group 'ediff-diff)
  85. (defcustom ediff-ignore-case-option3 ""
  86. "Option that causes the diff3 program to ignore case of letters.
  87. GNU diff3 doesn't have such an option."
  88. :type 'string
  89. :group 'ediff-diff)
  90. ;; the actual options used in comparison
  91. (ediff-defvar-local ediff-actual-diff-options ediff-diff-options "")
  92. (defcustom ediff-custom-diff-program ediff-diff-program
  93. "Program to use for generating custom diff output for saving it in a file.
  94. This output is not used by Ediff internally."
  95. :type 'string
  96. :group 'ediff-diff)
  97. (defcustom ediff-custom-diff-options "-c"
  98. "Options to pass to `ediff-custom-diff-program'."
  99. :type 'string
  100. :group 'ediff-diff)
  101. ;;; Support for diff3
  102. (defvar ediff-match-diff3-line "^====\\(.?\\)\C-m?$"
  103. "Pattern to match lines produced by diff3 that describe differences.")
  104. (defcustom ediff-diff3-options ""
  105. "Options to pass to `ediff-diff3-program'."
  106. :set 'ediff-set-diff-options
  107. :type 'string
  108. :group 'ediff-diff)
  109. ;; the actual options used in comparison
  110. (ediff-defvar-local ediff-actual-diff3-options ediff-diff3-options "")
  111. (defcustom ediff-diff3-ok-lines-regexp
  112. "^\\([1-3]:\\|====\\| \\|.*Warning *:\\|.*No newline\\|.*missing newline\\|^\C-m$\\)"
  113. "Regexp that matches normal output lines from `ediff-diff3-program'.
  114. Lines that do not match are assumed to be error messages."
  115. :type 'regexp
  116. :group 'ediff-diff)
  117. ;; keeps the status of the current diff in 3-way jobs.
  118. ;; the status can be =diff(A), =diff(B), or =diff(A+B)
  119. (ediff-defvar-local ediff-diff-status "" "")
  120. ;;; Fine differences
  121. (ediff-defvar-local ediff-auto-refine (if (ediff-has-face-support-p) 'on 'nix)
  122. "If `on', Ediff auto-highlights fine diffs for the current diff region.
  123. If `off', auto-highlighting is not used. If `nix', no fine diffs are shown
  124. at all, unless the user force-refines the region by hitting `*'.
  125. This variable can be set either in .emacs or toggled interactively.
  126. Use `setq-default' if setting it in .emacs")
  127. (ediff-defvar-local ediff-ignore-similar-regions nil
  128. "If t, skip over difference regions that differ only in the white space and line breaks.
  129. This variable can be set either in .emacs or toggled interactively.
  130. Use `setq-default' if setting it in .emacs")
  131. (ediff-defvar-local ediff-auto-refine-limit 14000
  132. "Auto-refine only the regions of this size (in bytes) or less.")
  133. ;;; General
  134. (defvar ediff-diff-ok-lines-regexp
  135. (concat
  136. "^\\("
  137. "[0-9,]+[acd][0-9,]+\C-m?$"
  138. "\\|[<>] "
  139. "\\|---"
  140. "\\|.*Warning *:"
  141. "\\|.*No +newline"
  142. "\\|.*missing +newline"
  143. "\\|^\C-m?$"
  144. "\\)")
  145. "Regexp that matches normal output lines from `ediff-diff-program'.
  146. This is mostly lifted from Emerge, except that Ediff also considers
  147. warnings and `Missing newline'-type messages to be normal output.
  148. Lines that do not match are assumed to be error messages.")
  149. (defvar ediff-match-diff-line
  150. (let ((x "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
  151. (concat "^" x "\\([acd]\\)" x "\C-m?$"))
  152. "Pattern to match lines produced by diff that describe differences.")
  153. (ediff-defvar-local ediff-setup-diff-regions-function nil
  154. "value is a function symbol depending on the kind of job is to be done.
  155. For 2-way jobs and for ediff-merge, it should be `ediff-setup-diff-regions'.
  156. For jobs requiring diff3, it should be `ediff-setup-diff-regions3'.
  157. The function should take three mandatory arguments, file-A, file-B, and
  158. file-C. It may ignore file C for diff2 jobs. It should also take
  159. one optional arguments, diff-number to refine.")
  160. ;;; Functions
  161. ;; Generate the difference vector and overlays for the two files
  162. ;; With optional arg REG-TO-REFINE, refine this region.
  163. ;; File-C argument is not used here. It is there just because
  164. ;; ediff-setup-diff-regions is called via a funcall to
  165. ;; ediff-setup-diff-regions-function, which can also have the value
  166. ;; ediff-setup-diff-regions3, which takes 4 arguments.
  167. (defun ediff-setup-diff-regions (file-A file-B _file-C)
  168. ;; looking for '-c', '-i', '-u', or 'c', 'i', 'u' among clustered non-long options
  169. (if (string-match "^-[ciu]\\| -[ciu]\\|\\(^\\| \\)-[^- ]+[ciu]"
  170. ediff-diff-options)
  171. (error "Options `-c', `-u', and `-i' are not allowed in `ediff-diff-options'"))
  172. ;; create, if it doesn't exist
  173. (or (ediff-buffer-live-p ediff-diff-buffer)
  174. (setq ediff-diff-buffer
  175. (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*"))))
  176. (ediff-make-diff2-buffer ediff-diff-buffer file-A file-B)
  177. (ediff-prepare-error-list ediff-diff-ok-lines-regexp ediff-diff-buffer)
  178. (ediff-convert-diffs-to-overlays
  179. (ediff-extract-diffs
  180. ediff-diff-buffer ediff-word-mode ediff-narrow-bounds)))
  181. ;; Run the diff program on FILE1 and FILE2 and put the output in DIFF-BUFFER
  182. ;; Return the size of DIFF-BUFFER
  183. ;; The return code isn't used in the program at present.
  184. (defun ediff-make-diff2-buffer (diff-buffer file1 file2)
  185. (let ((file1-size (ediff-file-size file1))
  186. (file2-size (ediff-file-size file2)))
  187. (cond ((not (numberp file1-size))
  188. (message "Can't find file: %s"
  189. (ediff-abbreviate-file-name file1))
  190. (sit-for 2)
  191. ;; 1 is an error exit code
  192. 1)
  193. ((not (numberp file2-size))
  194. (message "Can't find file: %s"
  195. (ediff-abbreviate-file-name file2))
  196. (sit-for 2)
  197. ;; 1 is an error exit code
  198. 1)
  199. (t (message "Computing differences between %s and %s ..."
  200. (file-name-nondirectory file1)
  201. (file-name-nondirectory file2))
  202. ;; this erases the diff buffer automatically
  203. (ediff-exec-process ediff-diff-program
  204. diff-buffer
  205. 'synchronize
  206. ediff-actual-diff-options file1 file2)
  207. (message "")
  208. (ediff-with-current-buffer diff-buffer
  209. (buffer-size))))))
  210. ;; If file-A/B/C is nil, do 2-way comparison with the non-nil buffers
  211. ;; This function works for diff3 and diff2 jobs
  212. (defun ediff-setup-fine-diff-regions (file-A file-B file-C reg-num)
  213. (or (ediff-buffer-live-p ediff-fine-diff-buffer)
  214. (setq ediff-fine-diff-buffer
  215. (get-buffer-create
  216. (ediff-unique-buffer-name "*ediff-fine-diff" "*"))))
  217. (let (diff3-job diff-program diff-options ok-regexp diff-list)
  218. (setq diff3-job ediff-3way-job
  219. diff-program (if diff3-job ediff-diff3-program ediff-diff-program)
  220. diff-options (if diff3-job
  221. ediff-actual-diff3-options
  222. ediff-actual-diff-options)
  223. ok-regexp (if diff3-job
  224. ediff-diff3-ok-lines-regexp
  225. ediff-diff-ok-lines-regexp))
  226. (ediff-message-if-verbose "Refining difference region %d ..." (1+ reg-num))
  227. (ediff-exec-process diff-program ediff-fine-diff-buffer 'synchronize
  228. diff-options
  229. ;; The shuffle below is because we can compare 3-way
  230. ;; or in several 2-way fashions, like fA fC, fA fB,
  231. ;; or fB fC.
  232. (if file-A file-A file-B)
  233. (if file-B file-B file-A)
  234. (if diff3-job
  235. (if file-C file-C file-B))
  236. ) ; exec process
  237. (ediff-prepare-error-list ok-regexp ediff-fine-diff-buffer)
  238. (ediff-message-if-verbose
  239. "")
  240. ;; "Refining difference region %d ... done" (1+ reg-num))
  241. (setq diff-list
  242. (if diff3-job
  243. (ediff-extract-diffs3
  244. ediff-fine-diff-buffer '3way-comparison 'word-mode)
  245. (ediff-extract-diffs ediff-fine-diff-buffer 'word-mode)))
  246. ;; fixup diff-list
  247. (if diff3-job
  248. (cond ((not file-A)
  249. (mapc (lambda (elt)
  250. (aset elt 0 nil)
  251. (aset elt 1 nil))
  252. (cdr diff-list)))
  253. ((not file-B)
  254. (mapc (lambda (elt)
  255. (aset elt 2 nil)
  256. (aset elt 3 nil))
  257. (cdr diff-list)))
  258. ((not file-C)
  259. (mapc (lambda (elt)
  260. (aset elt 4 nil)
  261. (aset elt 5 nil))
  262. (cdr diff-list)))
  263. ))
  264. (ediff-convert-fine-diffs-to-overlays diff-list reg-num)
  265. ))
  266. (defun ediff-prepare-error-list (ok-regexp diff-buff)
  267. (or (ediff-buffer-live-p ediff-error-buffer)
  268. (setq ediff-error-buffer
  269. (get-buffer-create (ediff-unique-buffer-name
  270. "*ediff-errors" "*"))))
  271. (ediff-with-current-buffer ediff-error-buffer
  272. (setq buffer-undo-list t)
  273. (erase-buffer)
  274. (insert (ediff-with-current-buffer diff-buff (buffer-string)))
  275. (goto-char (point-min))
  276. (delete-matching-lines ok-regexp))
  277. ;; If diff reports errors, show them then quit.
  278. (if (/= 0 (ediff-with-current-buffer ediff-error-buffer (buffer-size)))
  279. (let ((ctl-buf ediff-control-buffer)
  280. (error-buf ediff-error-buffer))
  281. (ediff-skip-unsuitable-frames)
  282. (switch-to-buffer error-buf)
  283. (ediff-kill-buffer-carefully ctl-buf)
  284. (error "Errors in diff output. Diff output is in %S" diff-buff))))
  285. ;; BOUNDS specifies visibility bounds to use.
  286. ;; WORD-MODE tells whether we are in the word-mode or not.
  287. ;; If WORD-MODE, also construct vector of diffs using word numbers.
  288. ;; Else, use point values.
  289. ;; This function handles diff-2 jobs including the case of
  290. ;; merging buffers and files without ancestor.
  291. (defun ediff-extract-diffs (diff-buffer word-mode &optional bounds)
  292. (let ((A-buffer ediff-buffer-A)
  293. (B-buffer ediff-buffer-B)
  294. (C-buffer ediff-buffer-C)
  295. (a-prev 1) ; this is needed to set the first diff line correctly
  296. (a-prev-pt nil)
  297. (b-prev 1)
  298. (b-prev-pt nil)
  299. (c-prev 1)
  300. (c-prev-pt nil)
  301. diff-list shift-A shift-B
  302. )
  303. ;; diff list contains word numbers, unless changed later
  304. (setq diff-list (cons (if word-mode 'words 'points)
  305. diff-list))
  306. ;; we don't use visibility bounds for buffer C when merging
  307. (if bounds
  308. (setq shift-A
  309. (ediff-overlay-start
  310. (ediff-get-value-according-to-buffer-type 'A bounds))
  311. shift-B
  312. (ediff-overlay-start
  313. (ediff-get-value-according-to-buffer-type 'B bounds))))
  314. ;; reset point in buffers A/B/C
  315. (ediff-with-current-buffer A-buffer
  316. (goto-char (if shift-A shift-A (point-min))))
  317. (ediff-with-current-buffer B-buffer
  318. (goto-char (if shift-B shift-B (point-min))))
  319. (if (ediff-buffer-live-p C-buffer)
  320. (ediff-with-current-buffer C-buffer
  321. (goto-char (point-min))))
  322. (ediff-with-current-buffer diff-buffer
  323. (goto-char (point-min))
  324. (while (re-search-forward ediff-match-diff-line nil t)
  325. (let* ((a-begin (string-to-number (buffer-substring (match-beginning 1)
  326. (match-end 1))))
  327. (a-end (let ((b (match-beginning 3))
  328. (e (match-end 3)))
  329. (if b
  330. (string-to-number (buffer-substring b e))
  331. a-begin)))
  332. (diff-type (buffer-substring (match-beginning 4) (match-end 4)))
  333. (b-begin (string-to-number (buffer-substring (match-beginning 5)
  334. (match-end 5))))
  335. (b-end (let ((b (match-beginning 7))
  336. (e (match-end 7)))
  337. (if b
  338. (string-to-number (buffer-substring b e))
  339. b-begin)))
  340. a-begin-pt a-end-pt b-begin-pt b-end-pt
  341. c-begin c-end c-begin-pt c-end-pt)
  342. ;; fix the beginning and end numbers, because diff is somewhat
  343. ;; strange about how it numbers lines
  344. (if (string-equal diff-type "a")
  345. (setq b-end (1+ b-end)
  346. a-begin (1+ a-begin)
  347. a-end a-begin)
  348. (if (string-equal diff-type "d")
  349. (setq a-end (1+ a-end)
  350. b-begin (1+ b-begin)
  351. b-end b-begin)
  352. ;; (string-equal diff-type "c")
  353. (setq a-end (1+ a-end)
  354. b-end (1+ b-end))))
  355. (if (eq ediff-default-variant 'default-B)
  356. (setq c-begin b-begin
  357. c-end b-end)
  358. (setq c-begin a-begin
  359. c-end a-end))
  360. ;; compute main diff vector
  361. (if word-mode
  362. ;; make diff-list contain word numbers
  363. (setq diff-list
  364. (nconc diff-list
  365. (list
  366. (if (ediff-buffer-live-p C-buffer)
  367. (vector (- a-begin a-prev) (- a-end a-begin)
  368. (- b-begin b-prev) (- b-end b-begin)
  369. (- c-begin c-prev) (- c-end c-begin)
  370. nil nil ; dummy ancestor
  371. nil ; state of diff
  372. nil ; state of merge
  373. nil ; state of ancestor
  374. )
  375. (vector (- a-begin a-prev) (- a-end a-begin)
  376. (- b-begin b-prev) (- b-end b-begin)
  377. nil nil ; dummy buf C
  378. nil nil ; dummy ancestor
  379. nil ; state of diff
  380. nil ; state of merge
  381. nil ; state of ancestor
  382. ))
  383. ))
  384. a-prev a-end
  385. b-prev b-end
  386. c-prev c-end)
  387. ;; else convert lines to points
  388. (ediff-with-current-buffer A-buffer
  389. (goto-char (or a-prev-pt shift-A (point-min)))
  390. (forward-line (- a-begin a-prev))
  391. (setq a-begin-pt (point))
  392. (forward-line (- a-end a-begin))
  393. (setq a-end-pt (point)
  394. a-prev a-end
  395. a-prev-pt a-end-pt))
  396. (ediff-with-current-buffer B-buffer
  397. (goto-char (or b-prev-pt shift-B (point-min)))
  398. (forward-line (- b-begin b-prev))
  399. (setq b-begin-pt (point))
  400. (forward-line (- b-end b-begin))
  401. (setq b-end-pt (point)
  402. b-prev b-end
  403. b-prev-pt b-end-pt))
  404. (if (ediff-buffer-live-p C-buffer)
  405. (ediff-with-current-buffer C-buffer
  406. (goto-char (or c-prev-pt (point-min)))
  407. (forward-line (- c-begin c-prev))
  408. (setq c-begin-pt (point))
  409. (forward-line (- c-end c-begin))
  410. (setq c-end-pt (point)
  411. c-prev c-end
  412. c-prev-pt c-end-pt)))
  413. (setq diff-list
  414. (nconc
  415. diff-list
  416. (list
  417. (if (ediff-buffer-live-p C-buffer)
  418. (vector
  419. a-begin-pt a-end-pt b-begin-pt b-end-pt
  420. c-begin-pt c-end-pt
  421. nil nil ; dummy ancestor
  422. ;; state of diff
  423. ;; shows which buff is different from the other two
  424. (if (eq ediff-default-variant 'default-B) 'A 'B)
  425. ediff-default-variant ; state of merge
  426. nil ; state of ancestor
  427. )
  428. (vector a-begin-pt a-end-pt
  429. b-begin-pt b-end-pt
  430. nil nil ; dummy buf C
  431. nil nil ; dummy ancestor
  432. nil nil ; dummy state of diff & merge
  433. nil ; dummy state of ancestor
  434. )))
  435. )))
  436. ))) ; end ediff-with-current-buffer
  437. diff-list
  438. ))
  439. (defun ediff-convert-diffs-to-overlays (diff-list)
  440. (ediff-set-diff-overlays-in-one-buffer 'A diff-list)
  441. (ediff-set-diff-overlays-in-one-buffer 'B diff-list)
  442. (if ediff-3way-job
  443. (ediff-set-diff-overlays-in-one-buffer 'C diff-list))
  444. (if ediff-merge-with-ancestor-job
  445. (ediff-set-diff-overlays-in-one-buffer 'Ancestor diff-list))
  446. ;; set up vector showing the status of merge regions
  447. (if ediff-merge-job
  448. (setq ediff-state-of-merge
  449. (vconcat
  450. (mapcar (lambda (elt)
  451. (let ((state-of-merge (aref elt 9))
  452. (state-of-ancestor (aref elt 10)))
  453. (vector
  454. ;; state of merge: prefers/default-A/B or combined
  455. (if state-of-merge (format "%S" state-of-merge))
  456. ;; whether the ancestor region is empty
  457. state-of-ancestor)))
  458. ;; the first elt designates type of list
  459. (cdr diff-list))
  460. )))
  461. (message "Processing difference regions ... done"))
  462. (defun ediff-set-diff-overlays-in-one-buffer (buf-type diff-list)
  463. (let* ((current-diff -1)
  464. (buff (ediff-get-buffer buf-type))
  465. (ctl-buf ediff-control-buffer)
  466. ;; ediff-extract-diffs puts the type of diff-list as the first elt
  467. ;; of this list. The type is either 'points or 'words
  468. (diff-list-type (car diff-list))
  469. (shift (ediff-overlay-start
  470. (ediff-get-value-according-to-buffer-type
  471. buf-type ediff-narrow-bounds)))
  472. (limit (ediff-overlay-end
  473. (ediff-get-value-according-to-buffer-type
  474. buf-type ediff-narrow-bounds)))
  475. diff-overlay-list list-element total-diffs
  476. begin end pt-saved overlay state-of-diff)
  477. (setq diff-list (cdr diff-list)) ; discard diff list type
  478. (setq total-diffs (length diff-list))
  479. ;; shift, if necessary
  480. (ediff-with-current-buffer buff (setq pt-saved shift))
  481. (while diff-list
  482. (setq current-diff (1+ current-diff)
  483. list-element (car diff-list)
  484. begin (aref list-element (cond ((eq buf-type 'A) 0)
  485. ((eq buf-type 'B) 2)
  486. ((eq buf-type 'C) 4)
  487. (t 6))) ; Ancestor
  488. end (aref list-element (cond ((eq buf-type 'A) 1)
  489. ((eq buf-type 'B) 3)
  490. ((eq buf-type 'C) 5)
  491. (t 7))) ; Ancestor
  492. state-of-diff (aref list-element 8)
  493. )
  494. (cond ((and (not (eq buf-type state-of-diff))
  495. (not (eq buf-type 'Ancestor))
  496. (memq state-of-diff '(A B C)))
  497. (setq state-of-diff
  498. (car (delq buf-type (delq state-of-diff (list 'A 'B 'C)))))
  499. (setq state-of-diff (format "=diff(%S)" state-of-diff))
  500. )
  501. (t (setq state-of-diff nil)))
  502. ;; Put overlays at appropriate places in buffer
  503. ;; convert word numbers to points, if necessary
  504. (if (eq diff-list-type 'words)
  505. (progn
  506. (ediff-with-current-buffer buff (goto-char pt-saved))
  507. (ediff-with-current-buffer ctl-buf
  508. (setq begin (ediff-goto-word (1+ begin) buff)
  509. end (ediff-goto-word end buff 'end)))
  510. (if (> end limit) (setq end limit))
  511. (if (> begin end) (setq begin end))
  512. (setq pt-saved (ediff-with-current-buffer buff (point)))))
  513. (setq overlay (ediff-make-bullet-proof-overlay begin end buff))
  514. (ediff-overlay-put overlay 'ediff-diff-num current-diff)
  515. (if (and (ediff-has-face-support-p)
  516. ediff-use-faces ediff-highlight-all-diffs)
  517. (ediff-set-overlay-face
  518. overlay (ediff-background-face buf-type current-diff)))
  519. (if (= 0 (mod current-diff 10))
  520. (message "Buffer %S: Processing difference region %d of %d"
  521. buf-type current-diff total-diffs))
  522. ;; Record all overlays for this difference.
  523. ;; The 2-d elt, nil, is a place holder for the fine diff vector.
  524. ;; The 3-d elt, nil, is a place holder for no-fine-diffs flag.
  525. ;; The 4-th elt says which diff region is different from the other two
  526. ;; (3-way jobs only).
  527. (setq diff-overlay-list
  528. (nconc
  529. diff-overlay-list
  530. (list (vector overlay nil nil state-of-diff)))
  531. diff-list
  532. (cdr diff-list))
  533. ) ; while
  534. (set (ediff-get-symbol-from-alist buf-type ediff-difference-vector-alist)
  535. (vconcat diff-overlay-list))
  536. ))
  537. ;; `n' is the diff region to work on. Default is ediff-current-difference.
  538. ;; if `flag' is 'noforce then make fine-diffs only if this region's fine
  539. ;; diffs have not been computed before.
  540. ;; if `flag' is 'skip then don't compute fine diffs for this region.
  541. (defun ediff-make-fine-diffs (&optional n flag)
  542. (or n (setq n ediff-current-difference))
  543. (if (< ediff-number-of-differences 1)
  544. (error ediff-NO-DIFFERENCES))
  545. (if ediff-word-mode
  546. (setq flag 'skip
  547. ediff-auto-refine 'nix))
  548. (or (< n 0)
  549. (>= n ediff-number-of-differences)
  550. ;; n is within the range
  551. (let ((tmp-buffer (get-buffer-create ediff-tmp-buffer))
  552. (file-A ediff-temp-file-A)
  553. (file-B ediff-temp-file-B)
  554. (file-C ediff-temp-file-C)
  555. (empty-A (ediff-empty-diff-region-p n 'A))
  556. (empty-B (ediff-empty-diff-region-p n 'B))
  557. (empty-C (ediff-empty-diff-region-p n 'C))
  558. (whitespace-A (ediff-whitespace-diff-region-p n 'A))
  559. (whitespace-B (ediff-whitespace-diff-region-p n 'B))
  560. (whitespace-C (ediff-whitespace-diff-region-p n 'C))
  561. cumulative-fine-diff-length)
  562. (cond ;; If one of the regions is empty (or 2 in 3way comparison)
  563. ;; then don't refine.
  564. ;; If the region happens to be entirely whitespace or empty then
  565. ;; mark as such.
  566. ((> (length (delq nil (list empty-A empty-B empty-C))) 1)
  567. (if (and (ediff-looks-like-combined-merge n)
  568. ediff-merge-job)
  569. (ediff-set-fine-overlays-in-one-buffer 'C nil n))
  570. (if ediff-3way-comparison-job
  571. (ediff-message-if-verbose
  572. "Region %d is empty in all buffers but %S"
  573. (1+ n)
  574. (cond ((not empty-A) 'A)
  575. ((not empty-B) 'B)
  576. ((not empty-C) 'C)))
  577. (ediff-message-if-verbose
  578. "Region %d in buffer %S is empty"
  579. (1+ n)
  580. (cond (empty-A 'A)
  581. (empty-B 'B)
  582. (empty-C 'C)))
  583. )
  584. ;; if all regions happen to be whitespace
  585. (if (and whitespace-A whitespace-B whitespace-C)
  586. ;; mark as space only
  587. (ediff-mark-diff-as-space-only n t)
  588. ;; if some regions are white and others don't, then mark as
  589. ;; non-white-space-only
  590. (ediff-mark-diff-as-space-only n nil)))
  591. ;; don't compute fine diffs if diff vector exists
  592. ((and (eq flag 'noforce) (ediff-get-fine-diff-vector n 'A))
  593. (if (ediff-no-fine-diffs-p n)
  594. (message
  595. "Only white-space differences in region %d %s"
  596. (1+ n)
  597. (cond ((eq (ediff-no-fine-diffs-p n) 'A)
  598. "in buffers B & C")
  599. ((eq (ediff-no-fine-diffs-p n) 'B)
  600. "in buffers A & C")
  601. ((eq (ediff-no-fine-diffs-p n) 'C)
  602. "in buffers A & B")
  603. (t "")))))
  604. ;; don't compute fine diffs for this region
  605. ((eq flag 'skip)
  606. (or (ediff-get-fine-diff-vector n 'A)
  607. (memq ediff-auto-refine '(off nix))
  608. (ediff-message-if-verbose
  609. "Region %d exceeds the auto-refinement limit. Type `%s' to refine"
  610. (1+ n)
  611. (substitute-command-keys
  612. "\\[ediff-make-or-kill-fine-diffs]")
  613. )))
  614. (t
  615. ;; recompute fine diffs
  616. (ediff-wordify
  617. (ediff-get-diff-posn 'A 'beg n)
  618. (ediff-get-diff-posn 'A 'end n)
  619. ediff-buffer-A
  620. tmp-buffer
  621. ediff-control-buffer)
  622. (setq file-A
  623. (ediff-make-temp-file tmp-buffer "fineDiffA" file-A))
  624. (ediff-wordify
  625. (ediff-get-diff-posn 'B 'beg n)
  626. (ediff-get-diff-posn 'B 'end n)
  627. ediff-buffer-B
  628. tmp-buffer
  629. ediff-control-buffer)
  630. (setq file-B
  631. (ediff-make-temp-file tmp-buffer "fineDiffB" file-B))
  632. (if ediff-3way-job
  633. (progn
  634. (ediff-wordify
  635. (ediff-get-diff-posn 'C 'beg n)
  636. (ediff-get-diff-posn 'C 'end n)
  637. ediff-buffer-C
  638. tmp-buffer
  639. ediff-control-buffer)
  640. (setq file-C
  641. (ediff-make-temp-file
  642. tmp-buffer "fineDiffC" file-C))))
  643. ;; save temp file names.
  644. (setq ediff-temp-file-A file-A
  645. ediff-temp-file-B file-B
  646. ediff-temp-file-C file-C)
  647. ;; set the new vector of fine diffs, if none exists
  648. (cond ((and ediff-3way-job whitespace-A)
  649. (ediff-setup-fine-diff-regions nil file-B file-C n))
  650. ((and ediff-3way-job whitespace-B)
  651. (ediff-setup-fine-diff-regions file-A nil file-C n))
  652. ((and ediff-3way-job
  653. ;; In merge-jobs, whitespace-C is t, since
  654. ;; ediff-empty-diff-region-p returns t in this case
  655. whitespace-C)
  656. (ediff-setup-fine-diff-regions file-A file-B nil n))
  657. (t
  658. (ediff-setup-fine-diff-regions file-A file-B file-C n)))
  659. (setq cumulative-fine-diff-length
  660. (+ (length (ediff-get-fine-diff-vector n 'A))
  661. (length (ediff-get-fine-diff-vector n 'B))
  662. ;; in merge jobs, the merge buffer is never refined
  663. (if (and file-C (not ediff-merge-job))
  664. (length (ediff-get-fine-diff-vector n 'C))
  665. 0)))
  666. (cond ((or
  667. ;; all regions are white space
  668. (and whitespace-A whitespace-B whitespace-C)
  669. ;; none is white space and no fine diffs detected
  670. (and (not whitespace-A)
  671. (not whitespace-B)
  672. (not (and ediff-3way-job whitespace-C))
  673. (eq cumulative-fine-diff-length 0)))
  674. (ediff-mark-diff-as-space-only n t)
  675. (ediff-message-if-verbose
  676. "Only white-space differences in region %d" (1+ n)))
  677. ((eq cumulative-fine-diff-length 0)
  678. (ediff-message-if-verbose
  679. "Only white-space differences in region %d %s"
  680. (1+ n)
  681. (cond (whitespace-A (ediff-mark-diff-as-space-only n 'A)
  682. "in buffers B & C")
  683. (whitespace-B (ediff-mark-diff-as-space-only n 'B)
  684. "in buffers A & C")
  685. (whitespace-C (ediff-mark-diff-as-space-only n 'C)
  686. "in buffers A & B"))))
  687. (t
  688. (ediff-mark-diff-as-space-only n nil)))
  689. )
  690. ) ; end cond
  691. (ediff-set-fine-diff-properties n)
  692. )))
  693. ;; Interface to ediff-make-fine-diffs. Checks for auto-refine limit, etc.
  694. (defun ediff-install-fine-diff-if-necessary (n)
  695. (cond ((and (eq ediff-auto-refine 'on)
  696. ediff-use-faces
  697. (not (eq ediff-highlighting-style 'off))
  698. (not (eq ediff-highlighting-style 'ascii)))
  699. (if (and
  700. (> ediff-auto-refine-limit
  701. (- (ediff-get-diff-posn 'A 'end n)
  702. (ediff-get-diff-posn 'A 'beg n)))
  703. (> ediff-auto-refine-limit
  704. (- (ediff-get-diff-posn 'B 'end n)
  705. (ediff-get-diff-posn 'B 'beg n))))
  706. (ediff-make-fine-diffs n 'noforce)
  707. (ediff-make-fine-diffs n 'skip)))
  708. ;; highlight if fine diffs already exist
  709. ((eq ediff-auto-refine 'off)
  710. (ediff-make-fine-diffs n 'skip))))
  711. ;; if fine diff vector is not set for diff N, then do nothing
  712. (defun ediff-set-fine-diff-properties (n &optional default)
  713. (or (not (ediff-has-face-support-p))
  714. (< n 0)
  715. (>= n ediff-number-of-differences)
  716. ;; when faces are supported, set faces and priorities of fine overlays
  717. (progn
  718. (ediff-set-fine-diff-properties-in-one-buffer 'A n default)
  719. (ediff-set-fine-diff-properties-in-one-buffer 'B n default)
  720. (if ediff-3way-job
  721. (ediff-set-fine-diff-properties-in-one-buffer 'C n default)))))
  722. (defun ediff-set-fine-diff-properties-in-one-buffer (buf-type
  723. n &optional default)
  724. (let ((fine-diff-vector (ediff-get-fine-diff-vector n buf-type))
  725. (face (if default
  726. nil
  727. (ediff-get-symbol-from-alist
  728. buf-type ediff-fine-diff-face-alist))))
  729. (mapc (lambda (overl)
  730. (ediff-set-overlay-face overl face))
  731. fine-diff-vector)))
  732. ;; Set overlays over the regions that denote delimiters
  733. (defun ediff-set-fine-overlays-for-combined-merge (diff-list reg-num)
  734. (let (overlay overlay-list)
  735. (while diff-list
  736. (condition-case nil
  737. (setq overlay
  738. (ediff-make-bullet-proof-overlay
  739. (nth 0 diff-list) (nth 1 diff-list) ediff-buffer-C))
  740. (error ""))
  741. (setq overlay-list (cons overlay overlay-list))
  742. (if (> (length diff-list) 1)
  743. (setq diff-list (cdr (cdr diff-list)))
  744. (error "ediff-set-fine-overlays-for-combined-merge: corrupt list of
  745. delimiter regions"))
  746. )
  747. (setq overlay-list (reverse overlay-list))
  748. (ediff-set-fine-diff-vector
  749. reg-num 'C (apply 'vector overlay-list))
  750. ))
  751. ;; Convert diff list to overlays for a given DIFF-REGION
  752. ;; in buffer of type BUF-TYPE
  753. (defun ediff-set-fine-overlays-in-one-buffer (buf-type diff-list region-num)
  754. (let* ((current-diff -1)
  755. (reg-start (ediff-get-diff-posn buf-type 'beg region-num))
  756. (buff (ediff-get-buffer buf-type))
  757. (ctl-buf ediff-control-buffer)
  758. combined-merge-diff-list
  759. diff-overlay-list list-element
  760. begin end overlay)
  761. (ediff-clear-fine-differences-in-one-buffer region-num buf-type)
  762. (setq diff-list (cdr diff-list)) ; discard list type (words or points)
  763. (ediff-with-current-buffer buff (goto-char reg-start))
  764. ;; if it is a combined merge then set overlays in buff C specially
  765. (if (and ediff-merge-job (eq buf-type 'C)
  766. (setq combined-merge-diff-list
  767. (ediff-looks-like-combined-merge region-num)))
  768. (ediff-set-fine-overlays-for-combined-merge
  769. combined-merge-diff-list region-num)
  770. ;; regular fine diff
  771. (while diff-list
  772. (setq current-diff (1+ current-diff)
  773. list-element (car diff-list)
  774. begin (aref list-element (cond ((eq buf-type 'A) 0)
  775. ((eq buf-type 'B) 2)
  776. (t 4))) ; buf C
  777. end (aref list-element (cond ((eq buf-type 'A) 1)
  778. ((eq buf-type 'B) 3)
  779. (t 5)))) ; buf C
  780. (if (not (or begin end))
  781. () ; skip this diff
  782. ;; Put overlays at appropriate places in buffers
  783. ;; convert lines to points, if necessary
  784. (ediff-with-current-buffer ctl-buf
  785. (setq begin (ediff-goto-word (1+ begin) buff)
  786. end (ediff-goto-word end buff 'end)))
  787. (setq overlay (ediff-make-bullet-proof-overlay begin end buff))
  788. ;; record all overlays for this difference region
  789. (setq diff-overlay-list (nconc diff-overlay-list (list overlay))))
  790. (setq diff-list (cdr diff-list))
  791. ) ; while
  792. ;; convert the list of difference information into a vector
  793. ;; for fast access
  794. (ediff-set-fine-diff-vector
  795. region-num buf-type (vconcat diff-overlay-list))
  796. )))
  797. (defun ediff-convert-fine-diffs-to-overlays (diff-list region-num)
  798. (ediff-set-fine-overlays-in-one-buffer 'A diff-list region-num)
  799. (ediff-set-fine-overlays-in-one-buffer 'B diff-list region-num)
  800. (if ediff-3way-job
  801. (ediff-set-fine-overlays-in-one-buffer 'C diff-list region-num)
  802. ))
  803. ;; Stolen from emerge.el
  804. (defun ediff-get-diff3-group (file)
  805. ;; This save-excursion allows ediff-get-diff3-group to be called for the
  806. ;; various groups of lines (1, 2, 3) in any order, and for the lines to
  807. ;; appear in any order. The reason this is necessary is that Gnu diff3
  808. ;; can produce the groups in the order 1, 2, 3 or 1, 3, 2.
  809. (save-excursion
  810. (re-search-forward
  811. (concat "^" file ":\\([0-9]+\\)\\(,\\([0-9]+\\)\\)?\\([ac]\\)\C-m?$"))
  812. (beginning-of-line 2)
  813. ;; treatment depends on whether it is an "a" group or a "c" group
  814. (if (string-equal (buffer-substring (match-beginning 4) (match-end 4)) "c")
  815. ;; it is a "c" group
  816. (if (match-beginning 2)
  817. ;; it has two numbers
  818. (list (string-to-number
  819. (buffer-substring (match-beginning 1) (match-end 1)))
  820. (1+ (string-to-number
  821. (buffer-substring (match-beginning 3) (match-end 3)))))
  822. ;; it has one number
  823. (let ((x (string-to-number
  824. (buffer-substring (match-beginning 1) (match-end 1)))))
  825. (list x (1+ x))))
  826. ;; it is an "a" group
  827. (let ((x (1+ (string-to-number
  828. (buffer-substring (match-beginning 1) (match-end 1))))))
  829. (list x x)))))
  830. ;; If WORD-MODE, construct vector of diffs using word numbers.
  831. ;; Else, use point values.
  832. ;; WORD-MODE also tells if we are in the word-mode or not.
  833. ;; If THREE-WAY-COMP, then it is a 3-way comparison. Else, it is merging
  834. ;; with ancestor, in which case buffer-C contents is identical to buffer-A/B,
  835. ;; contents (unless buffer-A is narrowed) depending on ediff-default-variant's
  836. ;; value.
  837. ;; BOUNDS specifies visibility bounds to use.
  838. (defun ediff-extract-diffs3 (diff-buffer word-mode three-way-comp
  839. &optional bounds)
  840. (let ((A-buffer ediff-buffer-A)
  841. (B-buffer ediff-buffer-B)
  842. (C-buffer ediff-buffer-C)
  843. (anc-buffer ediff-ancestor-buffer)
  844. (a-prev 1) ; needed to set the first diff line correctly
  845. (a-prev-pt nil)
  846. (b-prev 1)
  847. (b-prev-pt nil)
  848. (c-prev 1)
  849. (c-prev-pt nil)
  850. (anc-prev 1)
  851. diff-list shift-A shift-B shift-C
  852. )
  853. ;; diff list contains word numbers or points, depending on word-mode
  854. (setq diff-list (cons (if word-mode 'words 'points)
  855. diff-list))
  856. (if bounds
  857. (setq shift-A
  858. (ediff-overlay-start
  859. (ediff-get-value-according-to-buffer-type 'A bounds))
  860. shift-B
  861. (ediff-overlay-start
  862. (ediff-get-value-according-to-buffer-type 'B bounds))
  863. shift-C
  864. (if three-way-comp
  865. (ediff-overlay-start
  866. (ediff-get-value-according-to-buffer-type 'C bounds)))))
  867. ;; reset point in buffers A, B, C
  868. (ediff-with-current-buffer A-buffer
  869. (goto-char (if shift-A shift-A (point-min))))
  870. (ediff-with-current-buffer B-buffer
  871. (goto-char (if shift-B shift-B (point-min))))
  872. (if three-way-comp
  873. (ediff-with-current-buffer C-buffer
  874. (goto-char (if shift-C shift-C (point-min)))))
  875. (if (ediff-buffer-live-p anc-buffer)
  876. (ediff-with-current-buffer anc-buffer
  877. (goto-char (point-min))))
  878. (ediff-with-current-buffer diff-buffer
  879. (goto-char (point-min))
  880. (while (re-search-forward ediff-match-diff3-line nil t)
  881. ;; leave point after matched line
  882. (beginning-of-line 2)
  883. (let ((agreement (buffer-substring (match-beginning 1) (match-end 1))))
  884. ;; if the files A and B are the same and not 3way-comparison,
  885. ;; ignore the difference
  886. (if (or three-way-comp (not (string-equal agreement "3")))
  887. (let* ((a-begin (car (ediff-get-diff3-group "1")))
  888. (a-end (nth 1 (ediff-get-diff3-group "1")))
  889. (b-begin (car (ediff-get-diff3-group "2")))
  890. (b-end (nth 1 (ediff-get-diff3-group "2")))
  891. (c-or-anc-begin (car (ediff-get-diff3-group "3")))
  892. (c-or-anc-end (nth 1 (ediff-get-diff3-group "3")))
  893. (state-of-merge
  894. (cond ((string-equal agreement "1") 'prefer-A)
  895. ((string-equal agreement "2") 'prefer-B)
  896. (t ediff-default-variant)))
  897. (state-of-diff-merge
  898. (if (memq state-of-merge '(default-A prefer-A)) 'B 'A))
  899. (state-of-diff-comparison
  900. (cond ((string-equal agreement "1") 'A)
  901. ((string-equal agreement "2") 'B)
  902. ((string-equal agreement "3") 'C)))
  903. state-of-ancestor
  904. c-begin c-end
  905. a-begin-pt a-end-pt
  906. b-begin-pt b-end-pt
  907. c-begin-pt c-end-pt
  908. anc-begin-pt anc-end-pt)
  909. (setq state-of-ancestor
  910. (= c-or-anc-begin c-or-anc-end))
  911. (cond (three-way-comp
  912. (setq c-begin c-or-anc-begin
  913. c-end c-or-anc-end))
  914. ((eq ediff-default-variant 'default-B)
  915. (setq c-begin b-begin
  916. c-end b-end))
  917. (t
  918. (setq c-begin a-begin
  919. c-end a-end)))
  920. ;; compute main diff vector
  921. (if word-mode
  922. ;; make diff-list contain word numbers
  923. (setq diff-list
  924. (nconc diff-list
  925. (list (vector
  926. (- a-begin a-prev) (- a-end a-begin)
  927. (- b-begin b-prev) (- b-end b-begin)
  928. (- c-begin c-prev) (- c-end c-begin)
  929. nil nil ; dummy ancestor
  930. nil ; state of diff
  931. nil ; state of merge
  932. nil ; state of ancestor
  933. )))
  934. a-prev a-end
  935. b-prev b-end
  936. c-prev c-end)
  937. ;; else convert lines to points
  938. (ediff-with-current-buffer A-buffer
  939. (goto-char (or a-prev-pt shift-A (point-min)))
  940. (forward-line (- a-begin a-prev))
  941. (setq a-begin-pt (point))
  942. (forward-line (- a-end a-begin))
  943. (setq a-end-pt (point)
  944. a-prev a-end
  945. a-prev-pt a-end-pt))
  946. (ediff-with-current-buffer B-buffer
  947. (goto-char (or b-prev-pt shift-B (point-min)))
  948. (forward-line (- b-begin b-prev))
  949. (setq b-begin-pt (point))
  950. (forward-line (- b-end b-begin))
  951. (setq b-end-pt (point)
  952. b-prev b-end
  953. b-prev-pt b-end-pt))
  954. (ediff-with-current-buffer C-buffer
  955. (goto-char (or c-prev-pt shift-C (point-min)))
  956. (forward-line (- c-begin c-prev))
  957. (setq c-begin-pt (point))
  958. (forward-line (- c-end c-begin))
  959. (setq c-end-pt (point)
  960. c-prev c-end
  961. c-prev-pt c-end-pt))
  962. (if (ediff-buffer-live-p anc-buffer)
  963. (ediff-with-current-buffer anc-buffer
  964. (forward-line (- c-or-anc-begin anc-prev))
  965. (setq anc-begin-pt (point))
  966. (forward-line (- c-or-anc-end c-or-anc-begin))
  967. (setq anc-end-pt (point)
  968. anc-prev c-or-anc-end)))
  969. (setq diff-list
  970. (nconc
  971. diff-list
  972. ;; if comparing with ancestor, then there also is a
  973. ;; state-of-difference marker
  974. (if three-way-comp
  975. (list (vector
  976. a-begin-pt a-end-pt
  977. b-begin-pt b-end-pt
  978. c-begin-pt c-end-pt
  979. nil nil ; ancestor begin/end
  980. state-of-diff-comparison
  981. nil ; state of merge
  982. nil ; state of ancestor
  983. ))
  984. (list (vector a-begin-pt a-end-pt
  985. b-begin-pt b-end-pt
  986. c-begin-pt c-end-pt
  987. anc-begin-pt anc-end-pt
  988. state-of-diff-merge
  989. state-of-merge
  990. state-of-ancestor
  991. )))
  992. )))
  993. ))
  994. ))) ; end ediff-with-current-buffer
  995. diff-list
  996. ))
  997. ;; Generate the difference vector and overlays for three files
  998. ;; File-C is either the third file to compare (in case of 3-way comparison)
  999. ;; or it is the ancestor file.
  1000. (defun ediff-setup-diff-regions3 (file-A file-B file-C)
  1001. ;; looking for '-i' or a 'i' among clustered non-long options
  1002. (if (string-match "^-i\\| -i\\|\\(^\\| \\)-[^- ]+i" ediff-diff-options)
  1003. (error "Option `-i' is not allowed in `ediff-diff3-options'"))
  1004. (or (ediff-buffer-live-p ediff-diff-buffer)
  1005. (setq ediff-diff-buffer
  1006. (get-buffer-create (ediff-unique-buffer-name "*ediff-diff" "*"))))
  1007. (message "Computing differences ...")
  1008. (ediff-exec-process ediff-diff3-program ediff-diff-buffer 'synchronize
  1009. ediff-actual-diff3-options file-A file-B file-C)
  1010. (ediff-prepare-error-list ediff-diff3-ok-lines-regexp ediff-diff-buffer)
  1011. ;;(message "Computing differences ... done")
  1012. (ediff-convert-diffs-to-overlays
  1013. (ediff-extract-diffs3
  1014. ediff-diff-buffer
  1015. ediff-word-mode ediff-3way-comparison-job ediff-narrow-bounds)
  1016. ))
  1017. ;; Execute PROGRAM asynchronously, unless OS/2, Windows-*, or DOS, or unless
  1018. ;; SYNCH is non-nil. BUFFER must be a buffer object, and must be alive. The
  1019. ;; OPTIONS arg is a list of options to pass to PROGRAM. It may be a blank
  1020. ;; string. All elements in FILES must be strings. We also delete nil from
  1021. ;; args.
  1022. (defun ediff-exec-process (program buffer synch options &rest files)
  1023. (let ((data (match-data))
  1024. ;; If this is a buffer job, we are diffing temporary files
  1025. ;; produced by Emacs with ediff-coding-system-for-write, so
  1026. ;; use the same encoding to read the results.
  1027. (coding-system-for-read
  1028. (if (string-match "buffer" (symbol-name ediff-job-name))
  1029. ediff-coding-system-for-write
  1030. ediff-coding-system-for-read))
  1031. args)
  1032. (setq args (append (split-string options) files))
  1033. (setq args (delete "" (delq nil args))) ; delete nil and "" from arguments
  1034. ;; the --binary option, if present, should be used only for buffer jobs
  1035. ;; or for refining the differences
  1036. (or (string-match "buffer" (symbol-name ediff-job-name))
  1037. (eq buffer ediff-fine-diff-buffer)
  1038. (setq args (delete "--binary" args)))
  1039. (unwind-protect
  1040. (let ((directory default-directory)
  1041. proc)
  1042. (with-current-buffer buffer
  1043. (erase-buffer)
  1044. (setq default-directory directory)
  1045. (if (or (memq system-type '(ms-dos windows-nt))
  1046. synch)
  1047. ;; In Windows do it synchronously, since Windows doesn't let us
  1048. ;; delete files used by other processes. Thus, in ediff-buffers
  1049. ;; and similar functions, we can't delete temp files because
  1050. ;; they might be used by the asynch process that computes
  1051. ;; custom diffs. So, we have to wait till custom diff
  1052. ;; subprocess is done.
  1053. ;; In DOS, must synchronize because DOS doesn't have
  1054. ;; asynchronous processes.
  1055. (apply 'call-process program nil buffer nil args)
  1056. ;; On other systems, do it asynchronously.
  1057. (setq proc (get-buffer-process buffer))
  1058. (if proc (kill-process proc))
  1059. (setq proc
  1060. (apply 'start-process "Custom Diff" buffer program args))
  1061. (setq mode-line-process '(":%s"))
  1062. (set-process-sentinel proc 'ediff-process-sentinel)
  1063. (set-process-filter proc 'ediff-process-filter)
  1064. )))
  1065. (store-match-data data))))
  1066. ;; This is shell-command-filter from simple.el in Emacs.
  1067. ;; Copied here because XEmacs doesn't have it.
  1068. (defun ediff-process-filter (proc string)
  1069. ;; Do save-excursion by hand so that we can leave point numerically unchanged
  1070. ;; despite an insertion immediately after it.
  1071. (let* ((obuf (current-buffer))
  1072. (buffer (process-buffer proc))
  1073. opoint
  1074. (window (get-buffer-window buffer))
  1075. (pos (window-start window)))
  1076. (unwind-protect
  1077. (progn
  1078. (set-buffer buffer)
  1079. (or (= (point) (point-max))
  1080. (setq opoint (point)))
  1081. (goto-char (point-max))
  1082. (insert-before-markers string))
  1083. ;; insert-before-markers moved this marker: set it back.
  1084. (set-window-start window pos)
  1085. ;; Finish our save-excursion.
  1086. (if opoint
  1087. (goto-char opoint))
  1088. (set-buffer obuf))))
  1089. ;; like shell-command-sentinel but doesn't print an exit status message
  1090. ;; we do this because diff always exits with status 1, if diffs are found
  1091. ;; so shell-command-sentinel displays a confusing message to the user
  1092. (defun ediff-process-sentinel (process _signal)
  1093. (if (and (memq (process-status process) '(exit signal))
  1094. (buffer-name (process-buffer process)))
  1095. (progn
  1096. (with-current-buffer (process-buffer process)
  1097. (setq mode-line-process nil))
  1098. (delete-process process))))
  1099. ;;; Word functions used to refine the current diff
  1100. (defvar ediff-forward-word-function 'ediff-forward-word
  1101. "Function to call to move to the next word.
  1102. Used for splitting difference regions into individual words.")
  1103. (make-variable-buffer-local 'ediff-forward-word-function)
  1104. ;; \240 is Unicode symbol for nonbreakable whitespace
  1105. (defvar ediff-whitespace " \n\t\f\r\240"
  1106. "Characters constituting white space.
  1107. These characters are ignored when differing regions are split into words.")
  1108. (make-variable-buffer-local 'ediff-whitespace)
  1109. (defvar ediff-word-1
  1110. (if (featurep 'xemacs) "a-zA-Z---_" "-[:word:]_")
  1111. "Characters that constitute words of type 1.
  1112. More precisely, [ediff-word-1] is a regexp that matches type 1 words.
  1113. See `ediff-forward-word' for more details.")
  1114. (make-variable-buffer-local 'ediff-word-1)
  1115. (defvar ediff-word-2 "0-9.,"
  1116. "Characters that constitute words of type 2.
  1117. More precisely, [ediff-word-2] is a regexp that matches type 2 words.
  1118. See `ediff-forward-word' for more details.")
  1119. (make-variable-buffer-local 'ediff-word-2)
  1120. (defvar ediff-word-3 "`'?!:;\"{}[]()"
  1121. "Characters that constitute words of type 3.
  1122. More precisely, [ediff-word-3] is a regexp that matches type 3 words.
  1123. See `ediff-forward-word' for more details.")
  1124. (make-variable-buffer-local 'ediff-word-3)
  1125. (defvar ediff-word-4
  1126. (concat "^" ediff-word-1 ediff-word-2 ediff-word-3 ediff-whitespace)
  1127. "Characters that constitute words of type 4.
  1128. More precisely, [ediff-word-4] is a regexp that matches type 4 words.
  1129. See `ediff-forward-word' for more details.")
  1130. (make-variable-buffer-local 'ediff-word-4)
  1131. ;; Split region along word boundaries. Each word will be on its own line.
  1132. ;; Output to buffer out-buffer.
  1133. (defun ediff-forward-word ()
  1134. "Move point one word forward.
  1135. There are four types of words, each of which consists entirely of
  1136. characters in `ediff-word-1', `ediff-word-2', `ediff-word-3', or
  1137. `ediff-word-4'. Words are recognized by passing these one after another as
  1138. arguments to `skip-chars-forward'."
  1139. (or (> (+ (skip-chars-forward ediff-word-1)
  1140. (skip-syntax-forward "w"))
  1141. 0)
  1142. (> (skip-chars-forward ediff-word-2) 0)
  1143. (> (skip-chars-forward ediff-word-3) 0)
  1144. (> (skip-chars-forward ediff-word-4) 0)
  1145. ))
  1146. (defun ediff-wordify (beg end in-buffer out-buffer &optional control-buf)
  1147. (let ((forward-word-function
  1148. ;; eval in control buf to let user create local versions for
  1149. ;; different invocations
  1150. (if control-buf
  1151. (ediff-with-current-buffer control-buf
  1152. ediff-forward-word-function)
  1153. ediff-forward-word-function))
  1154. inbuf-syntax-tbl sv-point diff-string)
  1155. (with-current-buffer in-buffer
  1156. (setq inbuf-syntax-tbl
  1157. (if control-buf
  1158. (ediff-with-current-buffer control-buf
  1159. ediff-syntax-table)
  1160. (syntax-table)))
  1161. (setq diff-string (buffer-substring-no-properties beg end))
  1162. (set-buffer out-buffer)
  1163. ;; Make sure that temp buff syntax table is the same as the original buf
  1164. ;; syntax tbl, because we use ediff-forward-word in both and
  1165. ;; ediff-forward-word depends on the syntax classes of characters.
  1166. (set-syntax-table inbuf-syntax-tbl)
  1167. (erase-buffer)
  1168. (insert diff-string)
  1169. (goto-char (point-min))
  1170. (skip-chars-forward ediff-whitespace)
  1171. (delete-region (point-min) (point))
  1172. (while (not (eobp))
  1173. (funcall forward-word-function)
  1174. (setq sv-point (point))
  1175. (skip-chars-forward ediff-whitespace)
  1176. (delete-region sv-point (point))
  1177. (insert "\n")))))
  1178. ;; copy string specified as BEG END from IN-BUF to OUT-BUF
  1179. (defun ediff-copy-to-buffer (beg end in-buffer out-buffer)
  1180. (with-current-buffer out-buffer
  1181. (erase-buffer)
  1182. (insert-buffer-substring in-buffer beg end)
  1183. (goto-char (point-min))))
  1184. ;; goto word #n starting at current position in buffer `buf'
  1185. ;; For ediff, a word is determined by ediff-forward-word-function
  1186. ;; If `flag' is non-nil, goto the end of the n-th word.
  1187. (defun ediff-goto-word (n buf &optional flag)
  1188. ;; remember val ediff-forward-word-function has in ctl buf
  1189. (let ((fwd-word-fun ediff-forward-word-function)
  1190. (syntax-tbl ediff-syntax-table))
  1191. (ediff-with-current-buffer buf
  1192. (skip-chars-forward ediff-whitespace)
  1193. (ediff-with-syntax-table syntax-tbl
  1194. (while (> n 1)
  1195. (funcall fwd-word-fun)
  1196. (skip-chars-forward ediff-whitespace)
  1197. (setq n (1- n)))
  1198. (if (and flag (> n 0))
  1199. (funcall fwd-word-fun)))
  1200. (point))))
  1201. (defun ediff-same-file-contents (f1 f2)
  1202. "Return t if files F1 and F2 have identical contents."
  1203. (if (and (not (file-directory-p f1))
  1204. (not (file-directory-p f2)))
  1205. (if (equal (file-remote-p f1) (file-remote-p f2))
  1206. (let ((res
  1207. ;; In the remote case, this works only if F1 and F2 are
  1208. ;; located on the same remote host.
  1209. (apply 'process-file ediff-cmp-program nil nil nil
  1210. (append ediff-cmp-options
  1211. (list (or (file-remote-p f1 'localname)
  1212. (expand-file-name f1))
  1213. (or (file-remote-p f2 'localname)
  1214. (expand-file-name f2)))))
  1215. ))
  1216. (and (numberp res) (eq res 0)))
  1217. ;; F1 and F2 are not located on the same host.
  1218. (let ((t1 (file-local-copy f1))
  1219. (t2 (file-local-copy f2)))
  1220. (unwind-protect
  1221. (ediff-same-file-contents (or t1 f1) (or t2 f2))
  1222. (and t1 (delete-file t1))
  1223. (and t2 (delete-file t2))))
  1224. )))
  1225. (defun ediff-same-contents (d1 d2 &optional filter-re)
  1226. "Return t if D1 and D2 have the same content.
  1227. D1 and D2 can either be both directories or both regular files.
  1228. Symlinks and the likes are not handled.
  1229. If FILTER-RE is non-nil, recursive checking in directories
  1230. affects only files whose names match the expression."
  1231. ;; Normalize empty filter RE to nil.
  1232. (unless (> (length filter-re) 0) (setq filter-re nil))
  1233. ;; Indicate progress
  1234. (message "Comparing `%s' and `%s' modulo `%s'" d1 d2 filter-re)
  1235. (cond
  1236. ;; D1 & D2 directories => recurse
  1237. ((and (file-directory-p d1)
  1238. (file-directory-p d2))
  1239. (if (null ediff-recurse-to-subdirectories)
  1240. (if (y-or-n-p "Compare subdirectories recursively? ")
  1241. (setq ediff-recurse-to-subdirectories 'yes)
  1242. (setq ediff-recurse-to-subdirectories 'no)))
  1243. (if (eq ediff-recurse-to-subdirectories 'yes)
  1244. (let* ((all-entries-1 (directory-files d1 t filter-re))
  1245. (all-entries-2 (directory-files d2 t filter-re))
  1246. (entries-1 (ediff-delete-all-matches "^\\.\\.?$" all-entries-1))
  1247. (entries-2 (ediff-delete-all-matches "^\\.\\.?$" all-entries-2))
  1248. )
  1249. (ediff-same-file-contents-lists entries-1 entries-2 filter-re)
  1250. ))
  1251. ) ; end of the directories case
  1252. ;; D1 & D2 are both files => compare directly
  1253. ((and (file-regular-p d1)
  1254. (file-regular-p d2))
  1255. (ediff-same-file-contents d1 d2))
  1256. ;; Otherwise => false: unequal contents
  1257. )
  1258. )
  1259. ;; If lists have the same length and names of files are pairwise equal
  1260. ;; (removing the directories) then compare contents pairwise.
  1261. ;; True if all contents are the same; false otherwise
  1262. (defun ediff-same-file-contents-lists (entries-1 entries-2 filter-re)
  1263. ;; First, check only the names (works quickly and ensures a
  1264. ;; precondition for subsequent code)
  1265. (if (and (= (length entries-1) (length entries-2))
  1266. (equal (mapcar 'file-name-nondirectory entries-1)
  1267. (mapcar 'file-name-nondirectory entries-2)))
  1268. ;; With name equality established, compare the entries
  1269. ;; through recursion.
  1270. (let ((continue t))
  1271. (while (and entries-1 continue)
  1272. (if (ediff-same-contents
  1273. (car entries-1) (car entries-2) filter-re)
  1274. (setq entries-1 (cdr entries-1)
  1275. entries-2 (cdr entries-2))
  1276. (setq continue nil))
  1277. )
  1278. ;; if reached the end then lists are equal
  1279. (null entries-1))
  1280. )
  1281. )
  1282. ;; ARG1 is a regexp, ARG2 is a list of full-filenames
  1283. ;; Delete all entries that match the regexp
  1284. (defun ediff-delete-all-matches (regex file-list-list)
  1285. (let (result elt)
  1286. (while file-list-list
  1287. (setq elt (car file-list-list))
  1288. (or (string-match regex (file-name-nondirectory elt))
  1289. (setq result (cons elt result)))
  1290. (setq file-list-list (cdr file-list-list)))
  1291. (reverse result)))
  1292. (defun ediff-set-actual-diff-options ()
  1293. (if ediff-ignore-case
  1294. (setq ediff-actual-diff-options
  1295. (concat ediff-diff-options " " ediff-ignore-case-option)
  1296. ediff-actual-diff3-options
  1297. (concat ediff-diff3-options " " ediff-ignore-case-option3))
  1298. (setq ediff-actual-diff-options ediff-diff-options
  1299. ediff-actual-diff3-options ediff-diff3-options)
  1300. )
  1301. (setq-default ediff-actual-diff-options ediff-actual-diff-options
  1302. ediff-actual-diff3-options ediff-actual-diff3-options)
  1303. )
  1304. ;; Ignore case handling - some ideas from drew.adams@@oracle.com
  1305. (defun ediff-toggle-ignore-case ()
  1306. (interactive)
  1307. (ediff-barf-if-not-control-buffer)
  1308. (setq ediff-ignore-case (not ediff-ignore-case))
  1309. (ediff-set-actual-diff-options)
  1310. (if ediff-ignore-case
  1311. (message "Ignoring regions that differ only in case")
  1312. (message "Ignoring case differences turned OFF"))
  1313. (cond (ediff-merge-job
  1314. (message "Ignoring letter case is too dangerous in merge jobs"))
  1315. ((and ediff-diff3-job (string= ediff-ignore-case-option3 ""))
  1316. (message "Ignoring letter case is not supported by this diff3 program"))
  1317. ((and (not ediff-3way-job) (string= ediff-ignore-case-option ""))
  1318. (message "Ignoring letter case is not supported by this diff program"))
  1319. (t
  1320. (sit-for 1)
  1321. (ediff-update-diffs)))
  1322. )
  1323. ;; Local Variables:
  1324. ;; eval: (put 'ediff-defvar-local 'lisp-indent-hook 'defun)
  1325. ;; eval: (put 'ediff-with-current-buffer 'lisp-indent-hook 1)
  1326. ;; eval: (put 'ediff-with-current-buffer 'edebug-form-spec '(form body))
  1327. ;; End:
  1328. ;;; ediff-diff.el ends here