PageRenderTime 90ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/emacs/elisp/psvn.el

http://inkedmn.googlecode.com/
Emacs Lisp | 4224 lines | 3346 code | 382 blank | 496 comment | 145 complexity | 90d3eb1b61bff1a0773ff6e4d7dc70ba MD5 | raw file
  1. ;;; psvn.el --- Subversion interface for emacs
  2. ;; Copyright (C) 2002-2006 by Stefan Reichoer
  3. ;; Author: Stefan Reichoer, <stefan@xsteve.at>
  4. ;; $Id: psvn.el 19791 2006-05-23 19:37:33Z xsteve $
  5. ;; psvn.el is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation; either version 2, or (at your option)
  8. ;; any later version.
  9. ;; psvn.el is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with GNU Emacs; see the file COPYING. If not, write to
  15. ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  16. ;; Boston, MA 02111-1307, USA.
  17. ;;; Commentary
  18. ;; psvn.el is tested with GNU Emacs 21.3 on windows, debian linux,
  19. ;; freebsd5, red hat el3 with svn 1.2.3
  20. ;; psvn.el is an interface for the revision control tool subversion
  21. ;; (see http://subversion.tigris.org)
  22. ;; psvn.el provides a similar interface for subversion as pcl-cvs for cvs.
  23. ;; At the moment the following commands are implemented:
  24. ;;
  25. ;; M-x svn-status: run 'svn -status -v'
  26. ;; M-x svn-examine (like pcl-cvs cvs-examine) is alias for svn-status
  27. ;;
  28. ;; and show the result in the svn-status-buffer-name buffer (normally: *svn-status*).
  29. ;; If svn-status-verbose is set to nil, only "svn status" without "-v"
  30. ;; is run. Currently you have to toggle this variable manually.
  31. ;; This buffer uses svn-status mode in which the following keys are defined:
  32. ;; g - svn-status-update: run 'svn status -v'
  33. ;; M-s - svn-status-update: run 'svn status -v'
  34. ;; C-u g - svn-status-update: run 'svn status -vu'
  35. ;; = - svn-status-show-svn-diff run 'svn diff'
  36. ;; l - svn-status-show-svn-log run 'svn log'
  37. ;; i - svn-status-info run 'svn info'
  38. ;; r - svn-status-revert run 'svn revert'
  39. ;; X v - svn-status-resolved run 'svn resolved'
  40. ;; U - svn-status-update-cmd run 'svn update'
  41. ;; M-u - svn-status-update-cmd run 'svn update'
  42. ;; c - svn-status-commit run 'svn commit'
  43. ;; a - svn-status-add-file run 'svn add --non-recursive'
  44. ;; A - svn-status-add-file-recursively run 'svn add'
  45. ;; + - svn-status-make-directory run 'svn mkdir'
  46. ;; R - svn-status-mv run 'svn mv'
  47. ;; D - svn-status-rm run 'svn rm'
  48. ;; M-c - svn-status-cleanup run 'svn cleanup'
  49. ;; b - svn-status-blame run 'svn blame'
  50. ;; X e - svn-status-export run 'svn export'
  51. ;; RET - svn-status-find-file-or-examine-directory
  52. ;; ^ - svn-status-examine-parent
  53. ;; ~ - svn-status-get-specific-revision
  54. ;; E - svn-status-ediff-with-revision
  55. ;; X X - svn-status-resolve-conflicts
  56. ;; s - svn-status-show-process-buffer
  57. ;; e - svn-status-toggle-edit-cmd-flag
  58. ;; ? - svn-status-toggle-hide-unknown
  59. ;; _ - svn-status-toggle-hide-unmodified
  60. ;; m - svn-status-set-user-mark
  61. ;; u - svn-status-unset-user-mark
  62. ;; $ - svn-status-toggle-elide
  63. ;; w - svn-status-copy-filename-as-kill
  64. ;; DEL - svn-status-unset-user-mark-backwards
  65. ;; * ! - svn-status-unset-all-usermarks
  66. ;; * ? - svn-status-mark-unknown
  67. ;; * A - svn-status-mark-added
  68. ;; * M - svn-status-mark-modified
  69. ;; * D - svn-status-mark-deleted
  70. ;; * * - svn-status-mark-changed
  71. ;; . - svn-status-goto-root-or-return
  72. ;; f - svn-status-find-file
  73. ;; o - svn-status-find-file-other-window
  74. ;; v - svn-status-view-file-other-window
  75. ;; I - svn-status-parse-info
  76. ;; V - svn-status-svnversion
  77. ;; P l - svn-status-property-list
  78. ;; P s - svn-status-property-set
  79. ;; P d - svn-status-property-delete
  80. ;; P e - svn-status-property-edit-one-entry
  81. ;; P i - svn-status-property-ignore-file
  82. ;; P I - svn-status-property-ignore-file-extension
  83. ;; P C-i - svn-status-property-edit-svn-ignore
  84. ;; P k - svn-status-property-set-keyword-list
  85. ;; P y - svn-status-property-set-eol-style
  86. ;; P x - svn-status-property-set-executable
  87. ;; h - svn-status-use-history
  88. ;; q - svn-status-bury-buffer
  89. ;; C-x C-j - svn-status-dired-jump
  90. ;; The output in the buffer contains this header to ease reading
  91. ;; of svn output:
  92. ;; FPH BASE CMTD Author em File
  93. ;; F = Filemark
  94. ;; P = Property mark
  95. ;; H = History mark
  96. ;; BASE = local base revision
  97. ;; CMTD = last committed revision
  98. ;; Author = author of change
  99. ;; em = "**" or "(Update Available)" [see `svn-status-short-mod-flag-p']
  100. ;; if file can be updated
  101. ;; File = path/filename
  102. ;;
  103. ;; To use psvn.el put the following line in your .emacs:
  104. ;; (require 'psvn)
  105. ;; Start the svn interface with M-x svn-status
  106. ;; The latest version of psvn.el can be found at:
  107. ;; http://www.xsteve.at/prg/emacs/psvn.el
  108. ;; Or you can check it out from the subversion repository:
  109. ;; svn co http://svn.collab.net/repos/svn/trunk/contrib/client-side/psvn psvn
  110. ;; TODO:
  111. ;; * shortcut for svn propset svn:keywords "Date" psvn.el
  112. ;; * docstrings for the functions
  113. ;; * perhaps shortcuts for ranges, dates
  114. ;; * when editing the command line - offer help from the svn client
  115. ;; * finish svn-status-property-set
  116. ;; * Add repository browser
  117. ;; * Improve support for svn blame
  118. ;; * Get rid of all byte-compiler warnings
  119. ;; * SVK working copy support
  120. ;; * multiple independent buffers in svn-status-mode
  121. ;; There are "TODO" comments in other parts of this file as well.
  122. ;; Overview over the implemented/not (yet) implemented svn sub-commands:
  123. ;; * add implemented
  124. ;; * blame implemented
  125. ;; * cat implemented
  126. ;; * checkout (co)
  127. ;; * cleanup implemented
  128. ;; * commit (ci) implemented
  129. ;; * copy (cp)
  130. ;; * delete (del, remove, rm) implemented
  131. ;; * diff (di) implemented
  132. ;; * export implemented
  133. ;; * help (?, h)
  134. ;; * import
  135. ;; * info implemented
  136. ;; * list (ls) implemented
  137. ;; * lock
  138. ;; * log implemented
  139. ;; * merge
  140. ;; * mkdir implemented
  141. ;; * move (mv, rename, ren) implemented
  142. ;; * propdel (pdel) implemented
  143. ;; * propedit (pedit, pe) not needed
  144. ;; * propget (pget, pg) used
  145. ;; * proplist (plist, pl) implemented
  146. ;; * propset (pset, ps) used
  147. ;; * resolved implemented
  148. ;; * revert implemented
  149. ;; * status (stat, st) implemented
  150. ;; * switch (sw)
  151. ;; * unlock
  152. ;; * update (up) implemented
  153. ;; For the not yet implemented commands you should use the command line
  154. ;; svn client. If there are user requests for any missing commands I will
  155. ;; probably implement them.
  156. ;; Comments / suggestions and bug reports are welcome!
  157. ;; Development notes
  158. ;; -----------------
  159. ;; "svn-" is the package prefix used in psvn.el. There are also longer
  160. ;; prefixes which clarify the code and help symbol completion, but they
  161. ;; are not intended to prevent name clashes with other packages. All
  162. ;; interactive commands meant to be used only in a specific mode should
  163. ;; have names beginning with the name of that mode: for example,
  164. ;; "svn-status-add-file" in "svn-status-mode". "psvn" should be used
  165. ;; only in names of files, customization groups, and features. If SVK
  166. ;; support is ever added, it should use "svn-svk-" when no existing
  167. ;; prefix is applicable.
  168. ;; Many of the variables marked as `risky-local-variable' are probably
  169. ;; impossible to abuse, as the commands that read them are used only in
  170. ;; buffers that are not visiting any files. Better safe than sorry.
  171. ;;; Code:
  172. (require 'easymenu)
  173. (condition-case nil
  174. (progn
  175. (require 'diff-mode))
  176. (error nil))
  177. (defconst svn-psvn-revision "$Id: psvn.el 19791 2006-05-23 19:37:33Z xsteve $"
  178. "The revision number of psvn.")
  179. ;;; user setable variables
  180. (defcustom svn-status-verbose t
  181. "*Add '-v' to svn status call."
  182. :type 'boolean
  183. :group 'psvn)
  184. (defcustom svn-log-edit-file-name "++svn-log++"
  185. "*Name of a saved log file.
  186. This can be either absolute, or relative to the default directory
  187. of the *svn-log-edit* buffer."
  188. :type 'file
  189. :group 'psvn)
  190. (put 'svn-log-edit-file-name 'risky-local-variable t)
  191. (defcustom svn-log-edit-insert-files-to-commit t
  192. "*Insert the filelist to commit in the *svn-log* buffer"
  193. :type 'boolean
  194. :group 'psvn)
  195. (defcustom svn-log-edit-use-log-edit-mode
  196. (and (condition-case nil (require 'log-edit) (error nil)) t)
  197. "*Use log-edit-mode as base for svn-log-edit-mode
  198. This variable takes effect only when psvn.el is being loaded."
  199. :type 'boolean
  200. :group 'psvn)
  201. (defcustom svn-status-hide-unknown nil
  202. "*Hide unknown files in `svn-status-buffer-name' buffer.
  203. This can be toggled with \\[svn-status-toggle-hide-unknown]."
  204. :type 'boolean
  205. :group 'psvn)
  206. (defcustom svn-status-hide-unmodified nil
  207. "*Hide unmodified files in `svn-status-buffer-name' buffer.
  208. This can be toggled with \\[svn-status-toggle-hide-unmodified]."
  209. :type 'boolean
  210. :group 'psvn)
  211. (defcustom svn-status-sort-status-buffer t
  212. "*Whether to sort the `svn-status-buffer-name' buffer.
  213. Setting this variable to nil speeds up \[M-x svn-status], however the
  214. listing may then become incorrect.
  215. This can be toggled with \\[svn-status-toggle-sort-status-buffer]."
  216. :type 'boolean
  217. :group 'psvn)
  218. (defcustom svn-status-unmark-files-after-list '(commit revert)
  219. "*List of operations after which all user marks will be removed.
  220. Possible values are: commit, revert."
  221. :type '(set (const commit)
  222. (const revert))
  223. :group 'psvn)
  224. (defcustom svn-status-preserve-window-configuration nil
  225. "*Try to preserve the window configuration."
  226. :type 'boolean
  227. :group 'psvn)
  228. (defcustom svn-status-negate-meaning-of-arg-commands '()
  229. "*List of operations that should use a negated meaning of the prefix argument.
  230. The supported functions are `svn-status' and `svn-status-set-user-mark'."
  231. :type '(set (function-item svn-status)
  232. (function-item svn-status-set-user-mark))
  233. :group 'psvn)
  234. (defcustom svn-status-svn-executable "svn"
  235. "*The name of the svn executable.
  236. This can be either absolute or looked up on `exec-path'."
  237. ;; Don't use (file :must-match t). It doesn't know about `exec-path'.
  238. :type 'file
  239. :group 'psvn)
  240. (put 'svn-status-svn-executable 'risky-local-variable t)
  241. (defcustom svn-status-default-export-directory "~/" "*The default directory that is suggested svn export."
  242. :type 'file
  243. :group 'psvn)
  244. (defcustom svn-status-svn-environment-var-list '()
  245. "*A list of environment variables that should be set for that svn process.
  246. Each element is either a string \"VARIABLE=VALUE\" which will be added to
  247. the environment when svn is run, or just \"VARIABLE\" which causes that
  248. variable to be entirely removed from the environment.
  249. You could set this for example to '(\"LANG=C\")"
  250. :type '(repeat string)
  251. :group 'psvn)
  252. (put 'svn-status-svn-environment-var-list 'risky-local-variable t)
  253. (defcustom svn-browse-url-function nil
  254. ;; If the user hasn't changed `svn-browse-url-function', then changing
  255. ;; `browse-url-browser-function' should affect psvn even after it has
  256. ;; been loaded.
  257. "Function to display a Subversion related WWW page in a browser.
  258. So far, this is used only for \"trac\" issue tracker integration.
  259. By default, this is nil, which means use `browse-url-browser-function'.
  260. Any non-nil value overrides that variable, with the same syntax."
  261. ;; It would be nice to show the full list of browsers supported by
  262. ;; browse-url, but (custom-variable-type 'browse-url-browser-function)
  263. ;; returns just `function' if browse-url has not yet been loaded,
  264. ;; and there seems to be no easy way to autoload browse-url when
  265. ;; the custom-type of svn-browse-url-function is actually needed.
  266. ;; So I'll only offer enough choices to cover all supported types.
  267. :type `(choice (const :tag "Specified by `browse-url-browser-function'" nil)
  268. (function :value browse-url-default-browser
  269. ;; In XEmacs 21.4.17, the `function' widget matches
  270. ;; all objects. Constrain it here so that alists
  271. ;; fall through to the next choice. Accept either
  272. ;; a symbol (fbound or not) or a lambda expression.
  273. :match ,(lambda (widget value)
  274. (or (symbolp value) (functionp value))))
  275. (svn-alist :tag "Regexp/function association list"
  276. :key-type regexp :value-type function
  277. :value (("." . browse-url-default-browser))))
  278. :link '(emacs-commentary-link "browse-url")
  279. :group 'psvn)
  280. ;; (put 'svn-browse-url-function 'risky-local-variable t)
  281. ;; already implied by "-function" suffix
  282. (defcustom svn-status-window-alist
  283. '((diff "*svn-diff*") (log "*svn-log*") (info t) (blame t) (proplist t) (update t))
  284. "An alist to specify which windows should be used for svn command outputs.
  285. The following keys are supported: diff, log, info, blame, proplist, update.
  286. The following values can be given:
  287. nil ... show in *svn-process* buffer
  288. t ... show in dedicated *svn-info* buffer
  289. invisible ... don't show the buffer (eventually useful for update)
  290. a string ... show in a buffer named string"
  291. :type '(svn-alist
  292. :key-type symbol
  293. :value-type (group
  294. (choice
  295. (const :tag "Show in *svn-process* buffer" nil)
  296. (const :tag "Show in dedicated *svn-info* buffer" t)
  297. (const :tag "Don't show the output" invisible)
  298. (string :tag "Show in a buffer named"))))
  299. :options '(diff log info blame proplist update)
  300. :group 'psvn)
  301. (defcustom svn-status-short-mod-flag-p t
  302. "*Whether the mark for out of date files is short or long.
  303. If this variable is is t, and a file is out of date (i.e., there is a newer
  304. version in the repository than the working copy), then the file will
  305. be marked by \"**\"
  306. If this variable is nil, and the file is out of date then the longer phrase
  307. \"(Update Available)\" is used.
  308. In either case the mark gets the face
  309. `svn-status-update-available-face', and will only be visible if
  310. `\\[svn-status-update]' is run with a prefix argument"
  311. :type '(choice (const :tag "Short \"**\"" t)
  312. (const :tag "Long \"(Update Available)\"" nil))
  313. :group 'psvn)
  314. (defvar svn-status-debug-level 0 "The psvn.el debugging verbosity level.
  315. The higher the number, the more debug messages are shown.
  316. See `svn-status-message' for the meaning of values for that variable.")
  317. (defvar svn-status-buffer-name "*svn-status*" "Name for the svn status buffer")
  318. (defcustom svn-status-use-header-line
  319. (if (boundp 'header-line-format) t 'inline)
  320. "*Whether a header line should be used.
  321. When t: Use the emacs header line
  322. When 'inline: Insert the header line in the `svn-status-buffer-name' buffer
  323. Otherwise: Don't display a header line"
  324. :type '(choice (const :tag "Show column titles as a header line" t)
  325. (const :tag "Insert column titles as text in the buffer" inline)
  326. (other :tag "No column titles" nil))
  327. :group 'psvn)
  328. ;;; default arguments to pass to svn commands
  329. ;; TODO: When customizing, an option menu or completion might be nice....
  330. (defcustom svn-status-default-log-arguments '()
  331. "*List of arguments to pass to svn log.
  332. \(used in `svn-status-show-svn-log'; override these by giving prefixes\)."
  333. :type '(repeat string)
  334. :group 'psvn)
  335. (put 'svn-status-default-log-arguments 'risky-local-variable t)
  336. (defcustom svn-status-default-commit-arguments '()
  337. "*List of arguments to pass to svn commit.
  338. If you don't like recursive commits, set this value to (\"-N\")
  339. or mark the directory before committing it.
  340. Do not put an empty string here, except as an argument of an option:
  341. Subversion and the operating system may treat that as a file name
  342. equivalent to \".\", so you would commit more than you intended."
  343. :type '(repeat string)
  344. :group 'psvn)
  345. (put 'svn-status-default-commit-arguments 'risky-local-variable t)
  346. (defcustom svn-status-default-diff-arguments '()
  347. "*A list of arguments that is passed to the svn diff command.
  348. If you'd like to suppress whitespace changes use the following value:
  349. '(\"--diff-cmd\" \"diff\" \"-x\" \"-wbBu\")"
  350. :type '(repeat string)
  351. :group 'psvn)
  352. (put 'svn-status-default-diff-arguments 'risky-local-variable t)
  353. (defvar svn-trac-project-root nil
  354. "Path for an eventual existing trac issue tracker.
  355. This can be set with \\[svn-status-set-trac-project-root].")
  356. (defvar svn-status-module-name nil
  357. "*A short name for the actual project.
  358. This can be set with \\[svn-status-set-module-name].")
  359. (defvar svn-status-load-state-before-svn-status t
  360. "*Whether to automatically restore state from ++psvn.state file before running svn-status.")
  361. ;;; hooks
  362. (defvar svn-log-edit-mode-hook nil "Hook run when entering `svn-log-edit-mode'.")
  363. (defvar svn-log-edit-done-hook nil "Hook run after commiting files via svn.")
  364. ;; (put 'svn-log-edit-mode-hook 'risky-local-variable t)
  365. ;; (put 'svn-log-edit-done-hook 'risky-local-variable t)
  366. ;; already implied by "-hook" suffix
  367. (defvar svn-status-coding-system nil
  368. "A special coding system is needed for the output of svn.
  369. svn-status-coding-system is used in svn-run, if it is not nil.")
  370. (defcustom svn-status-wash-control-M-in-process-buffers
  371. (eq system-type 'windows-nt)
  372. "*Remove any trailing ^M from the *svn-process* buffer."
  373. :type 'boolean
  374. :group 'psvn)
  375. ;;; experimental features
  376. (defvar svn-status-track-user-input nil "Track user/password queries.
  377. This feature is implemented via a process filter.
  378. It is an experimental feature.")
  379. ;;; Customize group
  380. (defgroup psvn nil
  381. "Subversion interface for Emacs."
  382. :group 'tools)
  383. (defgroup psvn-faces nil
  384. "psvn faces."
  385. :group 'psvn)
  386. (eval-and-compile
  387. (require 'cl)
  388. (defconst svn-xemacsp (featurep 'xemacs))
  389. (if svn-xemacsp
  390. (require 'overlay)
  391. (require 'overlay nil t)))
  392. (defcustom svn-status-display-full-path nil
  393. "Specifies how the filenames look like in the listing.
  394. If t, their full path name will be displayed, else only the filename."
  395. :type 'boolean
  396. :group 'psvn)
  397. (defcustom svn-status-prefix-key [(control x) (meta s)]
  398. "Prefix key for the psvn commands in the global keymap."
  399. :type '(choice (const [(control x) ?v ?S])
  400. (const [(super s)])
  401. (const [(hyper s)])
  402. (const [(control x) ?v])
  403. (const [(control x) ?V])
  404. (sexp))
  405. :group 'psvn
  406. :set (lambda (var value)
  407. (if (boundp var)
  408. (global-unset-key (symbol-value var)))
  409. (set var value)
  410. (global-set-key (symbol-value var) 'svn-global-keymap)))
  411. ;; Use the normally used mode for files ending in .~HEAD~, .~BASE~, ...
  412. (add-to-list 'auto-mode-alist '("\\.~?\\(HEAD\\|BASE\\|PREV\\)~?\\'" ignore t))
  413. ;;; internal variables
  414. (defvar svn-status-directory-history nil "List of visited svn working directories.")
  415. (defvar svn-process-cmd nil)
  416. (defvar svn-status-info nil)
  417. (defvar svn-status-filename-to-buffer-position-cache (make-hash-table :test 'equal :weakness t))
  418. (defvar svn-status-base-info nil "The parsed result from the svn info command.")
  419. (defvar svn-status-initial-window-configuration nil)
  420. (defvar svn-status-default-column 23)
  421. (defvar svn-status-default-revision-width 4)
  422. (defvar svn-status-default-author-width 9)
  423. (defvar svn-status-line-format " %c%c%c %4s %4s %-9s")
  424. (defvar svn-start-of-file-list-line-number 0)
  425. (defvar svn-status-files-to-commit nil
  426. "List of files to commit at `svn-log-edit-done'.
  427. This is always set together with `svn-status-recursive-commit'.")
  428. (defvar svn-status-recursive-commit nil
  429. "Non-nil if the next commit should be recursive.
  430. This is always set together with `svn-status-files-to-commit'.")
  431. (defvar svn-log-edit-update-log-entry nil
  432. "Revision number whose log entry is being edited.
  433. This is nil if the log entry is for a new commit.")
  434. (defvar svn-status-pre-commit-window-configuration nil)
  435. (defvar svn-status-pre-propedit-window-configuration nil)
  436. (defvar svn-status-head-revision nil)
  437. (defvar svn-status-root-return-info nil)
  438. (defvar svn-status-property-edit-must-match-flag nil)
  439. (defvar svn-status-propedit-property-name nil)
  440. (defvar svn-status-propedit-file-list nil)
  441. (defvar svn-status-mode-line-process "")
  442. (defvar svn-status-mode-line-process-status "")
  443. (defvar svn-status-mode-line-process-edit-flag "")
  444. (defvar svn-status-edit-svn-command nil)
  445. (defvar svn-status-update-previous-process-output nil)
  446. (defvar svn-pre-run-asynch-recent-keys nil)
  447. (defvar svn-status-temp-dir
  448. (expand-file-name
  449. (or
  450. (when (boundp 'temporary-file-directory) temporary-file-directory) ;emacs
  451. ;; XEmacs 21.4.17 can return "/tmp/kalle" from (temp-directory).
  452. ;; `file-name-as-directory' adds a slash so we can append a file name.
  453. (when (fboundp 'temp-directory) (file-name-as-directory (temp-directory)))
  454. "/tmp/")) "The directory that is used to store temporary files for psvn.")
  455. ;; Because `temporary-file-directory' is not a risky local variable in
  456. ;; GNU Emacs 22.0.51, we don't mark `svn-status-temp-dir' as such either.
  457. (defvar svn-temp-suffix (make-temp-name "."))
  458. (put 'svn-temp-suffix 'risky-local-variable t)
  459. (defvar svn-status-temp-file-to-remove nil)
  460. (put 'svn-status-temp-file-to-remove 'risky-local-variable t)
  461. (defvar svn-status-temp-arg-file (concat svn-status-temp-dir "svn.arg" svn-temp-suffix))
  462. (put 'svn-status-temp-arg-file 'risky-local-variable t)
  463. (defvar svn-status-options nil)
  464. (defvar svn-status-remote)
  465. (defvar svn-status-commit-rev-number nil)
  466. (defvar svn-status-operated-on-dot nil)
  467. (defvar svn-status-elided-list nil)
  468. (defvar svn-status-custom-hide-function nil)
  469. ;; (put 'svn-status-custom-hide-function 'risky-local-variable t)
  470. ;; already implied by "-function" suffix
  471. (defvar svn-status-get-specific-revision-file-info)
  472. (defvar svn-status-last-output-buffer-name)
  473. (defvar svn-status-pre-run-svn-buffer nil)
  474. (defvar svn-status-update-list nil)
  475. (defvar svn-transient-buffers)
  476. (defvar svn-ediff-windows)
  477. (defvar svn-ediff-result)
  478. ;; Emacs 21 defines these in ediff-init.el but it seems more robust
  479. ;; to just declare the variables here than try to load that file.
  480. ;; It is Ediff's job to declare these as risky-local-variable if needed.
  481. (defvar ediff-buffer-A)
  482. (defvar ediff-buffer-B)
  483. (defvar ediff-buffer-C)
  484. (defvar ediff-quit-hook)
  485. ;; Ditto for log-edit.el.
  486. (defvar log-edit-initial-files)
  487. (defvar log-edit-callback)
  488. (defvar log-edit-listfun)
  489. ;; Ediff does not use this variable in GNU Emacs 20.7, GNU Emacs 21.4,
  490. ;; nor XEmacs 21.4.17. However, pcl-cvs (a.k.a. pcvs) does.
  491. ;; TODO: Check if this should be moved into the "svn-" namespace.
  492. (defvar ediff-after-quit-destination-buffer)
  493. ;; That is an example for the svn-status-custom-hide-function:
  494. ;; (setq svn-status-custom-hide-function 'svn-status-hide-pyc-files)
  495. ;; (defun svn-status-hide-pyc-files (info)
  496. ;; "Hide all pyc files in the `svn-status-buffer-name' buffer."
  497. ;; (let* ((fname (svn-status-line-info->filename-nondirectory info))
  498. ;; (fname-len (length fname)))
  499. ;; (and (> fname-len 4) (string= (substring fname (- fname-len 4)) ".pyc"))))
  500. ;;; faces
  501. (defface svn-status-marked-face
  502. '((((type tty) (class color)) (:foreground "green" :weight light))
  503. (((class color) (background light)) (:foreground "green3"))
  504. (((class color) (background dark)) (:foreground "palegreen2"))
  505. (t (:weight bold)))
  506. "Face to highlight the mark for user marked files in svn status buffers."
  507. :group 'psvn-faces)
  508. (defface svn-status-marked-popup-face
  509. '((((type tty) (class color)) (:foreground "green" :weight light))
  510. (((class color) (background light)) (:foreground "green3"))
  511. (((class color) (background dark)) (:foreground "palegreen2"))
  512. (t (:weight bold)))
  513. "Face to highlight the actual file, if a popup menu is activated."
  514. :group 'psvn-faces)
  515. (defface svn-status-update-available-face
  516. '((((type tty) (class color)) (:foreground "magenta" :weight light))
  517. (((class color) (background light)) (:foreground "magenta"))
  518. (((class color) (background dark)) (:foreground "yellow"))
  519. (t (:weight bold)))
  520. "Face used to highlight the 'out of date' mark.
  521. \(i.e., the mark used when there is a newer version in the repository
  522. than the working copy.\)
  523. See also `svn-status-short-mod-flag-p'."
  524. :group 'psvn-faces)
  525. ;based on cvs-filename-face
  526. (defface svn-status-directory-face
  527. '((((type tty) (class color)) (:foreground "lightblue" :weight light))
  528. (((class color) (background light)) (:foreground "blue4"))
  529. (((class color) (background dark)) (:foreground "lightskyblue1"))
  530. (t (:weight bold)))
  531. "Face for directories in *svn-status* buffers.
  532. See `svn-status--line-info->directory-p' for what counts as a directory."
  533. :group 'psvn-faces)
  534. ;based on font-lock-comment-face
  535. (defface svn-status-filename-face
  536. '((((class color) (background light)) (:foreground "chocolate"))
  537. (((class color) (background dark)) (:foreground "beige")))
  538. "Face for non-directories in *svn-status* buffers.
  539. See `svn-status--line-info->directory-p' for what counts as a directory."
  540. :group 'psvn-faces)
  541. ;based on font-lock-warning-face
  542. (defface svn-status-locked-face
  543. '((t
  544. (:weight bold :foreground "Red")))
  545. "Face for the phrase \"[ LOCKED ]\" `svn-status-buffer-name' buffers."
  546. :group 'psvn-faces)
  547. ;based on vhdl-font-lock-directive-face
  548. (defface svn-status-switched-face
  549. '((((class color)
  550. (background light))
  551. (:foreground "CadetBlue"))
  552. (((class color)
  553. (background dark))
  554. (:foreground "Aquamarine"))
  555. (t
  556. (:bold t :italic t)))
  557. "Face for the phrase \"(switched)\" non-directories in svn status buffers."
  558. :group 'psvn-faces)
  559. (defvar svn-highlight t)
  560. ;; stolen from PCL-CVS
  561. (defun svn-add-face (str face &optional keymap)
  562. "Return string STR decorated with the specified FACE.
  563. If `svn-highlight' is nil then just return STR."
  564. (when svn-highlight
  565. ;; Do not use `list*'; cl.el might not have been loaded. We could
  566. ;; put (require 'cl) at the top but let's try to manage without.
  567. (add-text-properties 0 (length str)
  568. `(face ,face
  569. mouse-face highlight)
  570. ;; 18.10.2004: the keymap parameter is not used (yet) in psvn.el
  571. ;; ,@(when keymap
  572. ;; `(mouse-face highlight
  573. ;; local-map ,keymap)))
  574. str))
  575. str)
  576. (defun svn-status-maybe-add-face (condition text face)
  577. "If CONDITION then add FACE to TEXT.
  578. Else return TEXT unchanged."
  579. (if condition
  580. (svn-add-face text face)
  581. text))
  582. (defun svn-status-choose-face-to-add (condition text face1 face2)
  583. "If CONDITION then add FACE1 to TEXT, else add FACE2 to TEXT."
  584. (if condition
  585. (svn-add-face text face1)
  586. (svn-add-face text face2)))
  587. (defun svn-status-maybe-add-string (condition string face)
  588. "If CONDITION then return STRING decorated with FACE.
  589. Otherwise, return \"\"."
  590. (if condition
  591. (svn-add-face string face)
  592. ""))
  593. ; compatibility
  594. ; emacs 20
  595. (defalias 'svn-point-at-eol
  596. (if (fboundp 'point-at-eol) 'point-at-eol 'line-end-position))
  597. (defalias 'svn-point-at-bol
  598. (if (fboundp 'point-at-bol) 'point-at-bol 'line-beginning-position))
  599. (defalias 'svn-read-directory-name
  600. (if (fboundp 'read-directory-name) 'read-directory-name 'read-file-name))
  601. (eval-when-compile
  602. (if (not (fboundp 'gethash))
  603. (require 'cl-macs)))
  604. (defalias 'svn-puthash (if (fboundp 'puthash) 'puthash 'cl-puthash))
  605. ; xemacs
  606. ;; Evaluate the defsubst at compile time, so that the byte compiler
  607. ;; knows the definition and can inline calls. It cannot detect the
  608. ;; defsubst automatically from within the if form.
  609. (eval-and-compile
  610. (if (fboundp 'match-string-no-properties)
  611. (defalias 'svn-match-string-no-properties 'match-string-no-properties)
  612. (defsubst svn-match-string-no-properties (match)
  613. (buffer-substring-no-properties (match-beginning match) (match-end match)))))
  614. ;; XEmacs 21.4.17 does not have an `alist' widget. Define a replacement.
  615. ;; To find out whether the `alist' widget exists, we cannot check just
  616. ;; (get 'alist 'widget-type), because GNU Emacs 21.4 defines it in
  617. ;; "wid-edit.el", which is not preloaded; it will be autoloaded when
  618. ;; `widget-create' is called. Instead, we call `widgetp', which is
  619. ;; also autoloaded from "wid-edit.el". XEmacs 21.4.17 does not have
  620. ;; `widgetp' either, so we check that first.
  621. (if (and (fboundp 'widgetp) (widgetp 'alist))
  622. (define-widget 'svn-alist 'alist
  623. "An association list.
  624. Use this instead of `alist', for XEmacs 21.4 compatibility.")
  625. (define-widget 'svn-alist 'list
  626. "An association list.
  627. Use this instead of `alist', for XEmacs 21.4 compatibility."
  628. :convert-widget 'svn-alist-convert-widget
  629. :tag "Association List"
  630. :key-type 'sexp
  631. :value-type 'sexp)
  632. (defun svn-alist-convert-widget (widget)
  633. (let* ((value-type (widget-get widget :value-type))
  634. (option-widgets (loop for option in (widget-get widget :options)
  635. collect `(cons :format "%v"
  636. (const :format "%t: %v\n"
  637. :tag "Key"
  638. ,option)
  639. ,value-type))))
  640. (widget-put widget :args
  641. `(,@(when option-widgets
  642. `((set :inline t :format "%v"
  643. ,@option-widgets)))
  644. (editable-list :inline t
  645. (cons :format "%v"
  646. ,(widget-get widget :key-type)
  647. ,value-type)))))
  648. widget))
  649. ;;; keymaps
  650. (defvar svn-global-keymap nil "Global keymap for psvn.el.
  651. To bind this to a different key, customize `svn-status-prefix-key'.")
  652. (put 'svn-global-keymap 'risky-local-variable t)
  653. (when (not svn-global-keymap)
  654. (setq svn-global-keymap (make-sparse-keymap))
  655. (define-key svn-global-keymap (kbd "s") 'svn-status-this-directory)
  656. (define-key svn-global-keymap (kbd "l") 'svn-status-show-svn-log)
  657. (define-key svn-global-keymap (kbd "u") 'svn-status-update-cmd)
  658. (define-key svn-global-keymap (kbd "=") 'svn-status-show-svn-diff)
  659. (define-key svn-global-keymap (kbd "b") 'svn-status-blame)
  660. (define-key svn-global-keymap (kbd "c") 'svn-status-commit)
  661. (define-key svn-global-keymap (kbd "S") 'svn-status-switch-to-status-buffer)
  662. (define-key svn-global-keymap (kbd "o") 'svn-status-pop-to-status-buffer))
  663. (defvar svn-status-diff-mode-map ()
  664. "Keymap used in `svn-status-diff-mode' for additional commands that are not defined in diff-mode.")
  665. (put 'svn-status-diff-mode-map 'risky-local-variable t) ;for Emacs 20.7
  666. (when (not svn-status-diff-mode-map)
  667. (setq svn-status-diff-mode-map (copy-keymap diff-mode-shared-map))
  668. (define-key svn-status-diff-mode-map [?w] 'svn-status-diff-save-current-defun-as-kill))
  669. (defvar svn-global-trac-map ()
  670. "Subkeymap used in `svn-global-keymap' for trac issue tracker commands.")
  671. (put 'svn-global-trac-map 'risky-local-variable t) ;for Emacs 20.7
  672. (when (not svn-global-trac-map)
  673. (setq svn-global-trac-map (make-sparse-keymap))
  674. (define-key svn-global-trac-map (kbd "t") 'svn-trac-browse-timeline)
  675. (define-key svn-global-trac-map (kbd "i") 'svn-trac-browse-ticket)
  676. (define-key svn-global-trac-map (kbd "c") 'svn-trac-browse-changeset)
  677. (define-key svn-global-keymap (kbd "t") svn-global-trac-map))
  678. ;; The setter of `svn-status-prefix-key' makes a binding in the global
  679. ;; map refer to the `svn-global-keymap' symbol, rather than directly
  680. ;; to the keymap. Emacs then implicitly uses the symbol-function.
  681. ;; This has the advantage that `describe-bindings' (C-h b) can show
  682. ;; the name of the keymap and link to its documentation.
  683. (defalias 'svn-global-keymap svn-global-keymap)
  684. ;; `defalias' of GNU Emacs 21.4 doesn't allow a docstring argument.
  685. (put 'svn-global-keymap 'function-documentation
  686. '(documentation-property 'svn-global-keymap 'variable-documentation t))
  687. ;; named after SVN_WC_ADM_DIR_NAME in svn_wc.h
  688. (defun svn-wc-adm-dir-name ()
  689. "Return the name of the \".svn\" subdirectory or equivalent."
  690. (if (and (eq system-type 'windows-nt)
  691. (getenv "SVN_ASP_DOT_NET_HACK"))
  692. "_svn"
  693. ".svn"))
  694. (defun svn-status-message (level &rest args)
  695. "If LEVEL is lower than `svn-status-debug-level' print ARGS using `message'.
  696. Guideline for numbers:
  697. 1 - error messages, 3 - non-serious error messages, 5 - messages for things
  698. that take a long time, 7 - not very important messages on stuff, 9 - messages
  699. inside loops."
  700. (if (<= level svn-status-debug-level)
  701. (apply 'message args)))
  702. (defun svn-status-flatten-list (list)
  703. "Flatten any lists within ARGS, so that there are no sublists."
  704. (loop for item in list
  705. if (listp item) nconc (svn-status-flatten-list item)
  706. else collect item))
  707. ;;;###autoload (defalias 'svn-examine 'svn-status)
  708. (defalias 'svn-examine 'svn-status)
  709. ;;;###autoload
  710. (defun svn-status (dir &optional arg)
  711. "Examine the status of Subversion working copy in directory DIR.
  712. If ARG is -, allow editing of the parameters. One could add -N to
  713. run svn status non recursively to make it faster.
  714. For every other non nil ARG pass the -u argument to `svn status'.
  715. If there is no .svn directory, examine if there is SVN and run
  716. `cvs-examine'. Otherwise ask if to run `dired'."
  717. (interactive (list (svn-read-directory-name "SVN status directory: "
  718. nil default-directory nil)
  719. current-prefix-arg))
  720. (let ((svn-dir (format "%s%s"
  721. (file-name-as-directory dir)
  722. (svn-wc-adm-dir-name)))
  723. (cvs-dir (format "%sCVS" (file-name-as-directory dir))))
  724. (cond
  725. ((file-directory-p svn-dir)
  726. (setq arg (svn-status-possibly-negate-meaning-of-arg arg 'svn-status))
  727. (svn-status-1 dir arg))
  728. ((and (file-directory-p cvs-dir)
  729. (fboundp 'cvs-examine))
  730. (cvs-examine dir nil))
  731. (t
  732. (when (y-or-n-p
  733. (format
  734. (concat
  735. "%s "
  736. "is not Subversion controlled (missing %s "
  737. "directory). "
  738. "Run dired instead? ")
  739. dir
  740. (svn-wc-adm-dir-name)))
  741. (dired dir))))))
  742. (defvar svn-status-display-new-status-buffer nil)
  743. (defun svn-status-1 (dir &optional arg)
  744. "Examine DIR. See `svn-status' for more information."
  745. (unless (file-directory-p dir)
  746. (error "%s is not a directory" dir))
  747. (setq dir (file-name-as-directory dir))
  748. (when svn-status-load-state-before-svn-status
  749. (unless (string= dir (car svn-status-directory-history))
  750. (svn-status-load-state t)))
  751. (setq svn-status-directory-history (delete dir svn-status-directory-history))
  752. (add-to-list 'svn-status-directory-history dir)
  753. (if (string= (buffer-name) svn-status-buffer-name)
  754. (setq svn-status-display-new-status-buffer nil)
  755. (setq svn-status-display-new-status-buffer t)
  756. ;;(message "psvn: Saving initial window configuration")
  757. (setq svn-status-initial-window-configuration
  758. (current-window-configuration)))
  759. (let* ((status-buf (get-buffer-create svn-status-buffer-name))
  760. (proc-buf (get-buffer-create "*svn-process*"))
  761. (want-edit (eq arg '-))
  762. (status-option (if want-edit
  763. (if svn-status-verbose "-v" "")
  764. (if svn-status-verbose
  765. (if arg "-uv" "-v")
  766. (if arg "-u" ""))))
  767. (svn-status-edit-svn-command
  768. (or want-edit svn-status-edit-svn-command)))
  769. (save-excursion
  770. (set-buffer status-buf)
  771. (setq default-directory dir)
  772. (set-buffer proc-buf)
  773. (setq default-directory dir
  774. svn-status-remote (when arg t))
  775. (svn-run t t 'status "status" status-option))))
  776. (defun svn-status-this-directory (arg)
  777. "Run `svn-status' for the `default-directory'"
  778. (interactive "P")
  779. (svn-status default-directory arg))
  780. (defun svn-status-use-history ()
  781. (interactive)
  782. (let* ((hist svn-status-directory-history)
  783. (dir (read-from-minibuffer "svn-status on directory: "
  784. (cadr svn-status-directory-history)
  785. nil nil 'hist)))
  786. (if (file-directory-p dir)
  787. (svn-status dir)
  788. (error "%s is not a directory" dir))))
  789. (defun svn-had-user-input-since-asynch-run ()
  790. (not (equal (recent-keys) svn-pre-run-asynch-recent-keys)))
  791. (defun svn-process-environment ()
  792. "Construct the environment for the svn process.
  793. It is a combination of `svn-status-svn-environment-var-list' and
  794. the usual `process-environment'."
  795. ;; If there are duplicate elements in `process-environment', then GNU
  796. ;; Emacs 21.4 guarantees that the first one wins; but GNU Emacs 20.7
  797. ;; and XEmacs 21.4.17 don't document what happens. We'll just remove
  798. ;; any duplicates ourselves, then. This also gives us an opportunity
  799. ;; to handle the "VARIABLE" syntax that none of them supports.
  800. (loop with found = '()
  801. for elt in (append svn-status-svn-environment-var-list
  802. process-environment)
  803. for has-value = (string-match "=" elt)
  804. for name = (substring elt 0 has-value)
  805. unless (member name found)
  806. do (push name found)
  807. and when has-value
  808. collect elt))
  809. (defun svn-run (run-asynchron clear-process-buffer cmdtype &rest arglist)
  810. "Run svn with arguments ARGLIST.
  811. If RUN-ASYNCHRON is t then run svn asynchronously.
  812. If CLEAR-PROCESS-BUFFER is t then erase the contents of the
  813. *svn-process* buffer before commencing.
  814. CMDTYPE is a symbol such as 'mv, 'revert, or 'add, representing the
  815. command to run.
  816. ARGLIST is a list of arguments \(which must include the command name,
  817. for example: '(\"revert\" \"file1\"\)
  818. ARGLIST is flattened and any every nil value is discarded.
  819. If the variable `svn-status-edit-svn-command' is non-nil then the user
  820. can edit ARGLIST before running svn."
  821. (setq arglist (svn-status-flatten-list arglist))
  822. (if (eq (process-status "svn") nil)
  823. (progn
  824. (when svn-status-edit-svn-command
  825. (setq arglist (append
  826. (list (car arglist))
  827. (split-string
  828. (read-from-minibuffer
  829. (format "svn %s flags: " (car arglist))
  830. (mapconcat 'identity (cdr arglist) " ")))))
  831. (when (eq svn-status-edit-svn-command t)
  832. (svn-status-toggle-edit-cmd-flag t))
  833. (message "svn-run %s: %S" cmdtype arglist))
  834. (let* ((proc-buf (get-buffer-create "*svn-process*"))
  835. (svn-exe svn-status-svn-executable)
  836. (svn-proc))
  837. (when (listp (car arglist))
  838. (setq arglist (car arglist)))
  839. (save-excursion
  840. (set-buffer proc-buf)
  841. (when svn-status-coding-system
  842. (setq buffer-file-coding-system svn-status-coding-system))
  843. (setq buffer-read-only nil)
  844. (fundamental-mode)
  845. (if clear-process-buffer
  846. (delete-region (point-min) (point-max))
  847. (goto-char (point-max)))
  848. (setq svn-process-cmd cmdtype)
  849. (setq svn-status-mode-line-process-status (format " running %s" cmdtype))
  850. (svn-status-update-mode-line)
  851. (sit-for 0.1)
  852. (if run-asynchron
  853. (progn
  854. ;;(message "running asynchron: %s %S" svn-exe arglist)
  855. (setq svn-pre-run-asynch-recent-keys (recent-keys))
  856. (let ((process-environment (svn-process-environment))
  857. (process-connection-type nil))
  858. ;; Communicate with the subprocess via pipes rather
  859. ;; than via a pseudoterminal, so that if the svn+ssh
  860. ;; scheme is being used, SSH will not ask for a
  861. ;; passphrase via stdio; psvn.el is currently unable
  862. ;; to answer such prompts. Instead, SSH will run
  863. ;; x11-ssh-askpass if possible. If Emacs is being
  864. ;; run on a TTY without $DISPLAY, this will fail; in
  865. ;; such cases, the user should start ssh-agent and
  866. ;; then run ssh-add explicitly.
  867. (setq svn-proc (apply 'start-process "svn" proc-buf svn-exe arglist)))
  868. (set-process-sentinel svn-proc 'svn-process-sentinel)
  869. (when svn-status-track-user-input
  870. (set-process-filter svn-proc 'svn-process-filter)))
  871. ;;(message "running synchron: %s %S" svn-exe arglist)
  872. (let ((process-environment (svn-process-environment)))
  873. ;; `call-process' ignores `process-connection-type' and
  874. ;; never opens a pseudoterminal.
  875. (apply 'call-process svn-exe nil proc-buf nil arglist))
  876. (setq svn-status-mode-line-process-status "")
  877. (svn-status-update-mode-line)))
  878. (setq svn-status-pre-run-svn-buffer (current-buffer))))
  879. (error "You can only run one svn process at once!")))
  880. (defun svn-process-sentinel-fixup-path-seperators ()
  881. "Convert all path separators to UNIX style.
  882. \(This is a no-op unless `system-type' is windows-nt\)"
  883. (when (eq system-type 'windows-nt)
  884. (save-excursion
  885. (goto-char (point-min))
  886. (while (search-forward "\\" nil t)
  887. (replace-match "/")))))
  888. (defun svn-process-sentinel (process event)
  889. ;;(princ (format "Process: %s had the event `%s'" process event)))
  890. ;;(save-excursion
  891. (let ((act-buf (current-buffer)))
  892. (set-buffer (process-buffer process))
  893. (setq svn-status-mode-line-process-status "")
  894. (svn-status-update-mode-line)
  895. (cond ((string= event "finished\n")
  896. (cond ((eq svn-process-cmd 'status)
  897. ;;(message "svn status finished")
  898. (svn-process-sentinel-fixup-path-seperators)
  899. (svn-parse-status-result)
  900. (set-buffer act-buf)
  901. (svn-status-update-buffer)
  902. (when svn-status-update-previous-process-output
  903. (set-buffer (process-buffer process))
  904. (delete-region (point-min) (point-max))
  905. (insert "Output from svn command:\n")
  906. (insert svn-status-update-previous-process-output)
  907. (goto-char (point-min))
  908. (setq svn-status-update-previous-process-output nil))
  909. (when svn-status-update-list
  910. ;; (message "Using svn-status-update-list: %S" svn-status-update-list)
  911. (save-excursion
  912. (svn-status-update-with-command-list svn-status-update-list))
  913. (setq svn-status-update-list nil))
  914. (when svn-status-display-new-status-buffer
  915. (set-window-configuration svn-status-initial-window-configuration)
  916. (if (svn-had-user-input-since-asynch-run)
  917. (message "svn status finished")
  918. (switch-to-buffer svn-status-buffer-name))))
  919. ((eq svn-process-cmd 'log)
  920. (svn-status-show-process-output 'log t)
  921. (pop-to-buffer svn-status-last-output-buffer-name)
  922. (svn-log-view-mode)
  923. (forward-line 3)
  924. (font-lock-fontify-buffer)
  925. (message "svn log finished"))
  926. ((eq svn-process-cmd 'info)
  927. (svn-status-show-process-output 'info t)
  928. (message "svn info finished"))
  929. ((eq svn-process-cmd 'ls)
  930. (svn-status-show-process-output 'info t)
  931. (message "svn ls finished"))
  932. ((eq svn-process-cmd 'parse-info)
  933. (svn-status-parse-info-result))
  934. ((eq svn-process-cmd 'blame)
  935. (svn-status-show-process-output 'blame t)
  936. (when svn-status-pre-run-svn-buffer
  937. (with-current-buffer svn-status-pre-run-svn-buffer
  938. (unless (eq major-mode 'svn-status-mode)
  939. (goto-line (line-number-at-pos) (get-buffer svn-status-last-output-buffer-name)))))
  940. (message "svn blame finished"))
  941. ((eq svn-process-cmd 'commit)
  942. (svn-process-sentinel-fixup-path-seperators)
  943. (svn-status-remove-temp-file-maybe)
  944. (when (member 'commit svn-status-unmark-files-after-list)
  945. (svn-status-unset-all-usermarks))
  946. (svn-status-update-with-command-list (svn-status-parse-commit-output))
  947. (run-hooks 'svn-log-edit-done-hook)
  948. (setq svn-status-files-to-commit nil
  949. svn-status-recursive-commit nil)
  950. (message "svn commit finished"))
  951. ((eq svn-process-cmd 'update)
  952. (svn-status-show-process-output 'update t)
  953. (setq svn-status-update-list (svn-status-parse-update-output))
  954. (svn-status-update)
  955. (message "svn update finished"))
  956. ((eq svn-process-cmd 'add)
  957. (svn-status-update-with-command-list (svn-status-parse-ar-output))
  958. (message "svn add finished"))
  959. ((eq svn-process-cmd 'mkdir)
  960. (svn-status-update)
  961. (message "svn mkdir finished"))
  962. ((eq svn-process-cmd 'revert)
  963. (when (member 'revert svn-status-unmark-files-after-list)
  964. (svn-status-unset-all-usermarks))
  965. (svn-status-update)
  966. (message "svn revert finished"))
  967. ((eq svn-process-cmd 'resolved)
  968. (svn-status-update)
  969. (message "svn resolved finished"))
  970. ((eq svn-process-cmd 'mv)
  971. (svn-status-update)
  972. (message "svn mv finished"))
  973. ((eq svn-process-cmd 'rm)
  974. (svn-status-update-with-command-list (svn-status-parse-ar-output))
  975. (message "svn rm finished"))
  976. ((eq svn-process-cmd 'cleanup)
  977. (message "svn cleanup finished"))
  978. ((eq svn-process-cmd 'proplist)
  979. (svn-status-show-process-output 'proplist t)
  980. (message "svn proplist finished"))
  981. ((eq svn-process-cmd 'proplist-parse)
  982. (svn-status-property-parse-property-names))
  983. ((eq svn-process-cmd 'propset)
  984. (svn-status-remove-temp-file-maybe)
  985. (if (member svn-status-propedit-property-name '("svn:keywords"))
  986. (svn-status-update-with-command-list (svn-status-parse-property-output))
  987. (svn-status-update)))
  988. ((eq svn-process-cmd 'propdel)
  989. (svn-status-update))))
  990. ((string= event "killed\n")
  991. (message "svn process killed"))
  992. ((string-match "exited abnormally" event)
  993. (while (accept-process-output process 0 100))
  994. ;; find last error message and show it.
  995. (goto-char (point-max))
  996. (message "svn failed: %s"
  997. (if (re-search-backward "^svn: \\(.*\\)" nil t)
  998. (match-string 1)
  999. event)))
  1000. (t
  1001. (message "svn process had unknown event: %s" event))
  1002. (svn-status-show-process-output nil t))))
  1003. (defun svn-process-filter (process str)
  1004. (save-window-excursion
  1005. (set-buffer "*svn-process*")
  1006. ;;(message "svn-process-filter: %s" str)
  1007. (goto-char (point-max))
  1008. (insert str)
  1009. (save-excursion
  1010. (goto-char (svn-point-at-bol))
  1011. (when (looking-at "Password for '\\(.+\\)': ")
  1012. ;(svn-status-show-process-buffer)
  1013. (let ((passwd (read-passwd
  1014. (format "Enter svn password for %s: " (match-string 1)))))
  1015. (svn-process-send-string (concat passwd "\n") t)))
  1016. (when (looking-at "Username: ")
  1017. (let ((user-name (read-string "Username for svn operation: ")))
  1018. (svn-process-send-string (concat user-name "\n")))))))
  1019. (defun svn-parse-rev-num (str)
  1020. (if (and str (stringp str)
  1021. (save-match-data (string-match "^[0-9]+" str)))
  1022. (string-to-number str)
  1023. -1))
  1024. (defsubst svn-status-make-ui-status ()
  1025. "Make a ui-status structure for a file in a svn working copy.
  1026. The initial values in the structure returned by this function
  1027. are good for a file or directory that the user hasn't seen before.
  1028. The ui-status structure keeps track of how the file or directory
  1029. should be displayed in svn-status mode. Updating the svn-status
  1030. buffer from the working copy preserves the ui-status if possible.
  1031. User commands modify this structure; each file or directory must
  1032. thus have its own copy.
  1033. Currently, the ui-status is a list (USER-MARK USER-ELIDE).
  1034. USER-MARK is non-nil iff the user has marked the file or directory,
  1035. typically with `svn-status-set-user-mark'. To read USER-MARK,
  1036. call `svn-status-line-info->has-usermark'.
  1037. USER-ELIDE is non-nil iff the user has elided the file or directory
  1038. from the svn-status buffer, typically with `svn-status-toggle-elide'.
  1039. To read USER-ELIDE, call `svn-status-line-info->user-elide'.
  1040. Call `svn-status-line-info->ui-status' to access the whole ui-status
  1041. structure."
  1042. (list nil nil))
  1043. (defun svn-status-make-dummy-dirs (dir-list old-ui-information)
  1044. (append (mapcar (lambda (dir)
  1045. (list (or (gethash dir old-ui-information)
  1046. (svn-status-make-ui-status))
  1047. 32 nil dir -1 -1 "?" nil nil nil nil))
  1048. dir-list)
  1049. svn-status-info))
  1050. (defun svn-parse-status-result ()
  1051. "Parse the *svn-process* buffer.
  1052. The results are used to build the `svn-status-info' variable."
  1053. (setq svn-status-head-revision nil)
  1054. (save-excursion
  1055. (let ((old-ui-information (svn-status-ui-information-hash-table))
  1056. (svn-marks)
  1057. (svn-file-mark)
  1058. (svn-property-mark)
  1059. (svn-locked-mark)
  1060. (svn-with-history-mark)
  1061. (svn-switched-mark)
  1062. (svn-update-mark)
  1063. (local-rev)
  1064. (last-change-rev)
  1065. (author)
  1066. (path)
  1067. (dir)
  1068. (revision-width svn-status-default-revision-width)
  1069. (author-width svn-status-default-author-width)
  1070. (svn-marks-length (if (and svn-status-verbose svn-status-remote)
  1071. 8 5))
  1072. (dir-set '(".")))
  1073. (set-buffer "*svn-process*")
  1074. (setq svn-status-info nil)
  1075. (goto-char (point-min))
  1076. (while (< (point) (point-max))
  1077. (cond
  1078. ((= (svn-point-at-eol) (svn-point-at-bol)) ;skip blank lines
  1079. nil)
  1080. ((looking-at "Status against revision:[ ]+\\([0-9]+\\)")
  1081. ;; the above message appears for the main listing plus once for each svn:externals entry
  1082. (unless svn-status-head-revision
  1083. (setq svn-status-head-revision (match-string 1))))
  1084. ((looking-at "Performing status on external item at '\\(.*\\)'")
  1085. ;; The *next* line has info about the directory named in svn:externals
  1086. ;; [ie the directory in (match-string 1)]
  1087. ;; we should parse it, and merge the info with what we have already know
  1088. ;; but for now just ignore the line completely
  1089. (forward-line)
  1090. )
  1091. (t
  1092. (setq svn-marks (buffer-substring (point) (+ (point) svn-marks-length))
  1093. svn-file-mark (elt svn-marks 0) ; 1st column - M,A,C,D,G,? etc
  1094. svn-property-mark (elt svn-marks 1) ; 2nd column - M,C (properties)
  1095. svn-locked-mark (elt svn-marks 2) ; 3rd column - L or blank
  1096. svn-with-history-mark (elt svn-marks 3) ; 4th column - + or blank
  1097. svn-switched-mark (elt svn-marks 4)) ; 5th column - S or blank
  1098. (if (and svn-status-verbose svn-status-remote)
  1099. (setq svn-update-mark (elt svn-marks 7))) ; 8th column - * or blank
  1100. (when (eq svn-property-mark ?\ ) (setq svn-property-mark nil))
  1101. (when (eq svn-locked-mark ?\ ) (setq svn-locked-mark nil))
  1102. (when (eq svn-with-history-mark ?\ ) (setq svn-with-history-mark nil))
  1103. (when (eq svn-switched-mark ?\ ) (setq svn-switched-mark nil))
  1104. (when (eq svn-update-mark ?\ ) (setq svn-update-mark nil))
  1105. (forward-char svn-marks-length)
  1106. (skip-chars-forward " ")
  1107. (cond
  1108. ((looking-at "\\([-?]\\|[0-9]+\\) +\\([-?]\\|[0-9]+\\) +\\([^ ]+\\) *\\(.+\\)$")
  1109. (setq local-rev (svn-parse-rev-num (match-string 1))
  1110. last-change-rev (svn-parse-rev-num (match-string 2))
  1111. author (match-string 3)
  1112. path (match-string 4)))
  1113. ((looking-at "\\([-?]\\|[0-9]+\\) +\\([^ ]+\\)$")
  1114. (setq local-rev (svn-parse-rev-num (match-string 1))
  1115. last-change-rev -1
  1116. author "?"
  1117. path (match-string 2)))
  1118. ((looking-at "\\(.*\\)")
  1119. (setq path (match-string 1)
  1120. local-rev -1
  1121. last-change-rev -1
  1122. author (if (eq svn-file-mark 88) "" "?"))) ;clear author of svn:externals dirs
  1123. (t
  1124. (error "Unknown status line format")))
  1125. (unless path (setq path "."))
  1126. (setq dir (file-name-directory path))
  1127. (if (and (not svn-status-verbose) dir)
  1128. (let ((dirname (directory-file-name dir)))
  1129. (if (not (member dirname dir-set))
  1130. (setq dir-set (cons dirname dir-set)))))
  1131. (setq svn-status-info (cons (list (or (gethash path old-ui-information)
  1132. (svn-status-make-ui-status))
  1133. svn-file-mark
  1134. svn-property-mark
  1135. path
  1136. local-rev
  1137. last-change-rev
  1138. author
  1139. svn-update-mark
  1140. svn-locked-mark
  1141. svn-with-history-mark
  1142. svn-switched-mark)
  1143. svn-status-info))
  1144. (setq revision-width (max revision-width
  1145. (length (number-to-string local-rev))
  1146. (length (number-to-string last-change-rev))))
  1147. (setq author-width (max author-width (length author)))))
  1148. (forward-line 1))
  1149. (unless svn-status-verbose
  1150. (setq svn-status-info (svn-status-make-dummy-dirs dir-set
  1151. old-ui-information)))
  1152. (setq svn-status-default-column
  1153. (+ 6 revision-width revision-width author-width
  1154. (if svn-status-short-mod-flag-p 3 0)))
  1155. (setq svn-status-line-format (format " %%c%%c%%c %%%ds %%%ds %%-%ds"
  1156. revision-width
  1157. revision-width
  1158. author-width))
  1159. (setq svn-status-info (nreverse svn-status-info))
  1160. (when svn-status-sort-status-buffer
  1161. (setq svn-status-info (sort svn-status-info 'svn-status-sort-predicate))))))
  1162. ;;(string-lessp "." "%") => nil
  1163. ;(svn-status-sort-predicate '(t t t ".") '(t t t "%")) => t
  1164. (defun svn-status-sort-predicate (a b)
  1165. "Return t if A should appear before B in the `svn-status-buffer-name' buffer.
  1166. A and B must be line-info's."
  1167. (string-lessp (concat (svn-status-line-info->full-path a) "/")
  1168. (concat (svn-status-line-info->full-path b) "/")))
  1169. (defun svn-status-remove-temp-file-maybe ()
  1170. "Remove any (no longer required) temporary files created by psvn.el."
  1171. (when svn-status-temp-file-to-remove
  1172. (when (file-exists-p svn-status-temp-file-to-remove)
  1173. (delete-file svn-status-temp-file-to-remove))
  1174. (when (file-exists-p svn-status-temp-arg-file)
  1175. (delete-file svn-status-temp-arg-file))
  1176. (setq svn-status-temp-file-to-remove nil)))
  1177. (defun svn-status-remove-control-M ()
  1178. "Remove ^M at end of line in the whole buffer."
  1179. (interactive)
  1180. (let ((buffer-read-only nil))
  1181. (save-match-data
  1182. (save-excursion
  1183. (goto-char (point-min))
  1184. (while (re-search-forward "\r$" (point-max) t)
  1185. (replace-match "" nil nil))))))
  1186. (condition-case nil
  1187. ;;(easy-menu-add-item nil '("tools") ["SVN Status" svn-status t] "PCL-CVS")
  1188. (easy-menu-add-item nil '("tools") ["SVN Status" svn-status t])
  1189. (error (message "psvn: could not install menu")))
  1190. (defvar svn-status-mode-map () "Keymap used in `svn-status-mode' buffers.")
  1191. (put 'svn-status-mode-map 'risky-local-variable t) ;for Emacs 20.7
  1192. (defvar svn-status-mode-mark-map ()
  1193. "Subkeymap used in `svn-status-mode' for mark commands.")
  1194. (put 'svn-status-mode-mark-map 'risky-local-variable t) ;for Emacs 20.7
  1195. (defvar svn-status-mode-property-map ()
  1196. "Subkeymap used in `svn-status-mode' for property commands.")
  1197. (put 'svn-status-mode-property-map 'risky-local-variable t) ;for Emacs 20.7
  1198. (defvar svn-status-mode-options-map ()
  1199. "Subkeymap used in `svn-status-mode' for option commands.")
  1200. (put 'svn-status-mode-options-map 'risky-local-variable t) ;for Emacs 20.7
  1201. (defvar svn-status-mode-trac-map ()
  1202. "Subkeymap used in `svn-status-mode' for trac issue tracker commands.")
  1203. (put 'svn-status-mode-trac-map 'risky-local-variable t) ;for Emacs 20.7
  1204. (defvar svn-status-mode-extension-map ()
  1205. "Subkeymap used in `svn-status-mode' for some seldom used commands.")
  1206. (put 'svn-status-mode-extension-map 'risky-local-variable t) ;for Emacs 20.7
  1207. (when (not svn-status-mode-map)
  1208. (setq svn-status-mode-map (make-sparse-keymap))
  1209. (suppress-keymap svn-status-mode-map)
  1210. ;; Don't use (kbd "<return>"); it's unreachable with GNU Emacs 21.3 on a TTY.
  1211. (define-key svn-status-mode-map (kbd "RET") 'svn-status-find-file-or-examine-directory)
  1212. (define-key svn-status-mode-map (kbd "<mouse-2>") 'svn-status-mouse-find-file-or-examine-directory)
  1213. (define-key svn-status-mode-map (kbd "^") 'svn-status-examine-parent)
  1214. (define-key svn-status-mode-map (kbd "s") 'svn-status-show-process-buffer)
  1215. (define-key svn-status-mode-map (kbd "f") 'svn-status-find-files)
  1216. (define-key svn-status-mode-map (kbd "o") 'svn-status-find-file-other-window)
  1217. (define-key svn-status-mode-map (kbd "v") 'svn-status-view-file-other-window)
  1218. (define-key svn-status-mode-map (kbd "e") 'svn-status-toggle-edit-cmd-flag)
  1219. (define-key svn-status-mode-map (kbd "g") 'svn-status-update)
  1220. (define-key svn-status-mode-map (kbd "M-s") 'svn-status-update) ;; PCL-CVS compatibility
  1221. (define-key svn-status-mode-map (kbd "q") 'svn-status-bury-buffer)
  1222. (define-key svn-status-mode-map (kbd "h") 'svn-status-use-history)
  1223. (define-key svn-status-mode-map (kbd "m") 'svn-status-set-user-mark)
  1224. (define-key svn-status-mode-map (kbd "u") 'svn-status-unset-user-mark)
  1225. ;; This matches a binding of `dired-unmark-all-files' in `dired-mode-map'
  1226. ;; of both GNU Emacs and XEmacs. It seems unreachable with XEmacs on
  1227. ;; TTY, but if that's a problem then its Dired needs fixing too.
  1228. ;; Or you could just use "*!".
  1229. (define-key svn-status-mode-map "\M-\C-?" 'svn-status-unset-all-usermarks)
  1230. ;; The key that normally deletes characters backwards should here
  1231. ;; instead unmark files backwards. In GNU Emacs, that would be (kbd
  1232. ;; "DEL") aka [?\177], but XEmacs treats those as [(delete)] and
  1233. ;; would bind a key that normally deletes forwards. [(backspace)]
  1234. ;; is unreachable with GNU Emacs on a tty. Try to recognize the
  1235. ;; dialect and act accordingly.
  1236. ;;
  1237. ;; XEmacs has a `delete-forward-p' function that checks the
  1238. ;; `delete-key-deletes-forward' option. We don't use those, for two
  1239. ;; reasons: psvn.el may be loaded before user customizations, and
  1240. ;; XEmacs allows simultaneous connections to multiple devices with
  1241. ;; different keyboards.
  1242. (define-key svn-status-mode-map
  1243. (if (member (kbd "DEL") '([(delete)] [delete]))
  1244. [(backspace)] ; XEmacs
  1245. (kbd "DEL")) ; GNU Emacs
  1246. 'svn-status-unset-user-mark-backwards)
  1247. (define-key svn-status-mode-map (kbd "$") 'svn-status-toggle-elide)
  1248. (define-key svn-status-mode-map (kbd "w") 'svn-status-copy-filename-as-kill)
  1249. (define-key svn-status-mode-map (kbd ".") 'svn-status-goto-root-or-return)
  1250. (define-key svn-status-mode-map (kbd "I") 'svn-status-parse-info)
  1251. (define-key svn-status-mode-map (kbd "V") 'svn-status-svnversion)
  1252. (define-key svn-status-mode-map (kbd "?") 'svn-status-toggle-hide-unknown)
  1253. (define-key svn-status-mode-map (kbd "_") 'svn-status-toggle-hide-unmodified)
  1254. (define-key svn-status-mode-map (kbd "a") 'svn-status-add-file)
  1255. (define-key svn-status-mode-map (kbd "A") 'svn-status-add-file-recursively)
  1256. (define-key svn-status-mode-map (kbd "+") 'svn-status-make-directory)
  1257. (define-key svn-status-mode-map (kbd "R") 'svn-status-mv)
  1258. (define-key svn-status-mode-map (kbd "D") 'svn-status-rm)
  1259. (define-key svn-status-mode-map (kbd "c") 'svn-status-commit)
  1260. (define-key svn-status-mode-map (kbd "M-c") 'svn-status-cleanup)
  1261. (define-key svn-status-mode-map (kbd "U") 'svn-status-update-cmd)
  1262. (define-key svn-status-mode-map (kbd "M-u") 'svn-status-update-cmd)
  1263. (define-key svn-status-mode-map (kbd "r") 'svn-status-revert)
  1264. (define-key svn-status-mode-map (kbd "l") 'svn-status-show-svn-log)
  1265. (define-key svn-status-mode-map (kbd "i") 'svn-status-info)
  1266. (define-key svn-status-mode-map (kbd "b") 'svn-status-blame)
  1267. (define-key svn-status-mode-map (kbd "=") 'svn-status-show-svn-diff)
  1268. ;; [(control ?=)] is unreachable on TTY, but you can use "*u" instead.
  1269. ;; (Is the "u" mnemonic for something?)
  1270. (define-key svn-status-mode-map (kbd "C-=") 'svn-status-show-svn-diff-for-marked-files)
  1271. (define-key svn-status-mode-map (kbd "~") 'svn-status-get-specific-revision)
  1272. (define-key svn-status-mode-map (kbd "E") 'svn-status-ediff-with-revision)
  1273. (define-key svn-status-mode-map (kbd "C-n") 'svn-status-next-line)
  1274. (define-key svn-status-mode-map (kbd "C-p") 'svn-status-previous-line)
  1275. (define-key svn-status-mode-map (kbd "n") 'svn-status-next-line)
  1276. (define-key svn-status-mode-map (kbd "p") 'svn-status-previous-line)
  1277. (define-key svn-status-mode-map (kbd "<down>") 'svn-status-next-line)
  1278. (define-key svn-status-mode-map (kbd "<up>") 'svn-status-previous-line)
  1279. (define-key svn-status-mode-map (kbd "C-x C-j") 'svn-status-dired-jump)
  1280. (define-key svn-status-mode-map [down-mouse-3] 'svn-status-popup-menu)
  1281. (setq svn-status-mode-mark-map (make-sparse-keymap))
  1282. (define-key svn-status-mode-map (kbd "*") svn-status-mode-mark-map)
  1283. (define-key svn-status-mode-mark-map (kbd "!") 'svn-status-unset-all-usermarks)
  1284. (define-key svn-status-mode-mark-map (kbd "?") 'svn-status-mark-unknown)
  1285. (define-key svn-status-mode-mark-map (kbd "A") 'svn-status-mark-added)
  1286. (define-key svn-status-mode-mark-map (kbd "M") 'svn-status-mark-modified)
  1287. (define-key svn-status-mode-mark-map (kbd "D") 'svn-status-mark-deleted)
  1288. (define-key svn-status-mode-mark-map (kbd "*") 'svn-status-mark-changed)
  1289. (define-key svn-status-mode-mark-map (kbd "u") 'svn-status-show-svn-diff-for-marked-files))
  1290. (when (not svn-status-mode-property-map)
  1291. (setq svn-status-mode-property-map (make-sparse-keymap))
  1292. (define-key svn-status-mode-property-map (kbd "l") 'svn-status-property-list)
  1293. (define-key svn-status-mode-property-map (kbd "s") 'svn-status-property-set)
  1294. (define-key svn-status-mode-property-map (kbd "d") 'svn-status-property-delete)
  1295. (define-key svn-status-mode-property-map (kbd "e") 'svn-status-property-edit-one-entry)
  1296. (define-key svn-status-mode-property-map (kbd "i") 'svn-status-property-ignore-file)
  1297. (define-key svn-status-mode-property-map (kbd "I") 'svn-status-property-ignore-file-extension)
  1298. ;; XEmacs 21.4.15 on TTY (vt420) converts `C-i' to `TAB',
  1299. ;; which [(control ?i)] won't match. Handle it separately.
  1300. ;; On GNU Emacs, the following two forms bind the same key,
  1301. ;; reducing clutter in `where-is'.
  1302. (define-key svn-status-mode-property-map [(control ?i)] 'svn-status-property-edit-svn-ignore)
  1303. (define-key svn-status-mode-property-map (kbd "TAB") 'svn-status-property-edit-svn-ignore)
  1304. (define-key svn-status-mode-property-map (kbd "k") 'svn-status-property-set-keyword-list)
  1305. (define-key svn-status-mode-property-map (kbd "y") 'svn-status-property-set-eol-style)
  1306. (define-key svn-status-mode-property-map (kbd "x") 'svn-status-property-set-executable)
  1307. ;; TODO: Why is `svn-status-select-line' in `svn-status-mode-property-map'?
  1308. (define-key svn-status-mode-property-map (kbd "RET") 'svn-status-select-line)
  1309. (define-key svn-status-mode-map (kbd "P") svn-status-mode-property-map))
  1310. (when (not svn-status-mode-extension-map)
  1311. (setq svn-status-mode-extension-map (make-sparse-keymap))
  1312. (define-key svn-status-mode-extension-map (kbd "v") 'svn-status-resolved)
  1313. (define-key svn-status-mode-extension-map (kbd "X") 'svn-status-resolve-conflicts)
  1314. (define-key svn-status-mode-extension-map (kbd "e") 'svn-status-export)
  1315. (define-key svn-status-mode-map (kbd "X") svn-status-mode-extension-map))
  1316. (when (not svn-status-mode-options-map)
  1317. (setq svn-status-mode-options-map (make-sparse-keymap))
  1318. (define-key svn-status-mode-options-map (kbd "s") 'svn-status-save-state)
  1319. (define-key svn-status-mode-options-map (kbd "l") 'svn-status-load-state)
  1320. (define-key svn-status-mode-options-map (kbd "x") 'svn-status-toggle-sort-status-buffer)
  1321. (define-key svn-status-mode-options-map (kbd "f") 'svn-status-toggle-display-full-path)
  1322. (define-key svn-status-mode-options-map (kbd "t") 'svn-status-set-trac-project-root)
  1323. (define-key svn-status-mode-options-map (kbd "n") 'svn-status-set-module-name)
  1324. (define-key svn-status-mode-map (kbd "O") svn-status-mode-options-map))
  1325. (when (not svn-status-mode-trac-map)
  1326. (setq svn-status-mode-trac-map (make-sparse-keymap))
  1327. (define-key svn-status-mode-trac-map (kbd "t") 'svn-trac-browse-timeline)
  1328. (define-key svn-status-mode-map (kbd "T") svn-status-mode-trac-map))
  1329. (easy-menu-define svn-status-mode-menu svn-status-mode-map
  1330. "'svn-status-mode' menu"
  1331. '("SVN"
  1332. ["svn status" svn-status-update t]
  1333. ["svn update" svn-status-update-cmd t]
  1334. ["svn commit" svn-status-commit t]
  1335. ["svn log" svn-status-show-svn-log t]
  1336. ["svn info" svn-status-info t]
  1337. ["svn blame" svn-status-blame t]
  1338. ("Diff"
  1339. ["svn diff current file" svn-status-show-svn-diff t]
  1340. ["svn diff marked files" svn-status-show-svn-diff-for-marked-files t]
  1341. ["svn ediff current file" svn-status-ediff-with-revision t]
  1342. ["svn resolve conflicts" svn-status-resolve-conflicts]
  1343. )
  1344. ["svn cat ..." svn-status-get-specific-revision t]
  1345. ["svn add" svn-status-add-file t]
  1346. ["svn add recursively" svn-status-add-file-recursively t]
  1347. ["svn mkdir..." svn-status-make-directory t]
  1348. ["svn mv..." svn-status-mv t]
  1349. ["svn rm..." svn-status-rm t]
  1350. ["svn export..." svn-status-export t]
  1351. ["Up Directory" svn-status-examine-parent t]
  1352. ["Elide Directory" svn-status-toggle-elide t]
  1353. ["svn revert" svn-status-revert t]
  1354. ["svn resolved" svn-status-resolved t]
  1355. ["svn cleanup" svn-status-cleanup t]
  1356. ["Show Process Buffer" svn-status-show-process-buffer t]
  1357. ("Property"
  1358. ["svn proplist" svn-status-property-list t]
  1359. ["Set Multiple Properties..." svn-status-property-set t]
  1360. ["Edit One Property..." svn-status-property-edit-one-entry t]
  1361. ["svn propdel..." svn-status-property-delete t]
  1362. "---"
  1363. ["svn:ignore File..." svn-status-property-ignore-file t]
  1364. ["svn:ignore File Extension..." svn-status-property-ignore-file-extension t]
  1365. ["Edit svn:ignore Property" svn-status-property-edit-svn-ignore t]
  1366. "---"
  1367. ["Edit svn:keywords List" svn-status-property-set-keyword-list t]
  1368. ["Select svn:eol-style" svn-status-property-set-eol-style t]
  1369. ["Set svn:executable" svn-status-property-set-executable t]
  1370. )
  1371. ("Options"
  1372. ["Save Options" svn-status-save-state t]
  1373. ["Load Options" svn-status-load-state t]
  1374. ["Set Trac project root" svn-status-set-trac-project-root t]
  1375. ["Set Short module name" svn-status-set-module-name t]
  1376. ["Toggle sorting of *svn-status* buffer" svn-status-toggle-sort-status-buffer
  1377. :style toggle :selected svn-status-sort-status-buffer]
  1378. ["Toggle display of full path names" svn-status-toggle-display-full-path
  1379. :style toggle :selected svn-status-display-full-path]
  1380. )
  1381. ("Trac"
  1382. ["Browse timeline" svn-trac-browse-timeline t]
  1383. ["Set Trac project root" svn-status-set-trac-project-root t]
  1384. )
  1385. "---"
  1386. ["Edit Next SVN Cmd Line" svn-status-toggle-edit-cmd-flag t]
  1387. ["Work Directory History..." svn-status-use-history t]
  1388. ("Mark / Unmark"
  1389. ["Mark" svn-status-set-user-mark t]
  1390. ["Unmark" svn-status-unset-user-mark t]
  1391. ["Unmark all" svn-status-unset-all-usermarks t]
  1392. "---"
  1393. ["Mark/Unmark unknown" svn-status-mark-unknown t]
  1394. ["Mark/Unmark added" svn-status-mark-added t]
  1395. ["Mark/Unmark modified" svn-status-mark-modified t]
  1396. ["Mark/Unmark deleted" svn-status-mark-deleted t]
  1397. ["Mark/Unmark modified/added/deleted" svn-status-mark-changed t]
  1398. )
  1399. ["Hide Unknown" svn-status-toggle-hide-unknown
  1400. :style toggle :selected svn-status-hide-unknown]
  1401. ["Hide Unmodified" svn-status-toggle-hide-unmodified
  1402. :style toggle :selected svn-status-hide-unmodified]
  1403. ))
  1404. (defun svn-status-popup-menu (event)
  1405. (interactive "e")
  1406. (mouse-set-point event)
  1407. (let* ((line-info (svn-status-get-line-information))
  1408. (name (svn-status-line-info->filename line-info)))
  1409. (when line-info
  1410. (easy-menu-define svn-status-actual-popup-menu nil nil
  1411. (list name
  1412. ["svn diff" svn-status-show-svn-diff t]
  1413. ["svn commit" svn-status-commit t]
  1414. ["svn log" svn-status-show-svn-log t]
  1415. ["svn info" svn-status-info t]
  1416. ["svn blame" svn-status-blame t]))
  1417. (svn-status-face-set-temporary-during-popup
  1418. 'svn-status-marked-popup-face (svn-point-at-bol) (svn-point-at-eol)
  1419. svn-status-actual-popup-menu))))
  1420. (defun svn-status-face-set-temporary-during-popup (face begin end menu &optional prefix)
  1421. "Put FACE on BEGIN and END in the buffer during Popup MENU.
  1422. PREFIX is passed to `popup-menu'."
  1423. (let (o)
  1424. (unwind-protect
  1425. (progn
  1426. (setq o (make-overlay begin end))
  1427. (overlay-put o 'face face)
  1428. (sit-for 0)
  1429. (popup-menu menu prefix))
  1430. (delete-overlay o))))
  1431. (defun svn-status-mode ()
  1432. "Major mode used by psvn.el to display the output of \"svn status\".
  1433. The Output has the following format:
  1434. FPH BASE CMTD Author em File
  1435. F = Filemark
  1436. P = Property mark
  1437. H = History mark
  1438. BASE = local base revision
  1439. CMTD = last committed revision
  1440. Author = author of change
  1441. em = \"**\" or \"(Update Available)\" [see `svn-status-short-mod-flag-p']
  1442. if file can be updated
  1443. File = path/filename
  1444. The following keys are defined:
  1445. \\{svn-status-mode-map}"
  1446. (interactive)
  1447. (kill-all-local-variables)
  1448. (use-local-map svn-status-mode-map)
  1449. (easy-menu-add svn-status-mode-menu)
  1450. (setq major-mode 'svn-status-mode)
  1451. (setq mode-name "svn-status")
  1452. (setq mode-line-process 'svn-status-mode-line-process)
  1453. (let ((view-read-only nil))
  1454. (toggle-read-only 1)))
  1455. (defun svn-status-update-mode-line ()
  1456. (setq svn-status-mode-line-process
  1457. (concat svn-status-mode-line-process-edit-flag svn-status-mode-line-process-status))
  1458. (force-mode-line-update))
  1459. (defun svn-status-bury-buffer (arg)
  1460. "Bury the buffers used by psvn.el
  1461. Currently this is:
  1462. `svn-status-buffer-name'
  1463. *svn-log-edit*
  1464. *svn-property-edit*
  1465. *svn-log*
  1466. *svn-process*
  1467. When called with a prefix argument, ARG, switch back to the window configuration that was
  1468. in use before `svn-status' was called."
  1469. (interactive "P")
  1470. (cond (arg
  1471. (when svn-status-initial-window-configuration
  1472. (set-window-configuration svn-status-initial-window-configuration)))
  1473. (t
  1474. (let ((bl '("*svn-log-edit*" "*svn-property-edit*" "*svn-log*" "*svn-process*")))
  1475. (while bl
  1476. (when (get-buffer (car bl))
  1477. (bury-buffer (car bl)))
  1478. (setq bl (cdr bl)))
  1479. (when (string= (buffer-name) svn-status-buffer-name)
  1480. (bury-buffer))))))
  1481. (defun svn-status-save-some-buffers (&optional tree)
  1482. "Save all buffers visiting a file in TREE.
  1483. If TREE is not given, try `svn-status-base-dir' as TREE."
  1484. (interactive)
  1485. (let ((ok t)
  1486. (tree (or (svn-status-base-dir)
  1487. tree)))
  1488. (unless tree
  1489. (error "Not in a svn project tree"))
  1490. (dolist (buffer (buffer-list))
  1491. (with-current-buffer buffer
  1492. (when (buffer-modified-p)
  1493. (let ((file (buffer-file-name)))
  1494. (when file
  1495. (let ((root (svn-status-base-dir (file-name-directory file))))
  1496. (when (and root
  1497. (string= root tree)
  1498. ;; buffer is modified and in the tree TREE.
  1499. (or (y-or-n-p (concat "Save buffer " (buffer-name) "? "))
  1500. (setq ok nil)))
  1501. (save-buffer))))))))
  1502. ok))
  1503. (defun svn-status-find-files ()
  1504. "Open selected file(s) for editing.
  1505. See `svn-status-marked-files' for what counts as selected."
  1506. (interactive)
  1507. (let ((fnames (mapcar 'svn-status-line-info->full-path (svn-status-marked-files))))
  1508. (mapc 'find-file fnames)))
  1509. (defun svn-status-find-file-other-window ()
  1510. "Open the file in the other window for editing."
  1511. (interactive)
  1512. (svn-status-ensure-cursor-on-file)
  1513. (find-file-other-window (svn-status-line-info->filename
  1514. (svn-status-get-line-information))))
  1515. (defun svn-status-view-file-other-window ()
  1516. "Open the file in the other window for viewing."
  1517. (interactive)
  1518. (svn-status-ensure-cursor-on-file)
  1519. (view-file-other-window (svn-status-line-info->filename
  1520. (svn-status-get-line-information))))
  1521. (defun svn-status-find-file-or-examine-directory ()
  1522. "If point is on a directory, run `svn-status' on that directory.
  1523. Otherwise run `find-file'."
  1524. (interactive)
  1525. (svn-status-ensure-cursor-on-file)
  1526. (let ((line-info (svn-status-get-line-information)))
  1527. (if (svn-status-line-info->directory-p line-info)
  1528. (svn-status (svn-status-line-info->full-path line-info))
  1529. (find-file (svn-status-line-info->filename line-info)))))
  1530. (defun svn-status-examine-parent ()
  1531. "Run `svn-status' on the parent of the current directory."
  1532. (interactive)
  1533. (svn-status (expand-file-name "../")))
  1534. (defun svn-status-mouse-find-file-or-examine-directory (event)
  1535. "Move point to where EVENT occurred, and do `svn-status-find-file-or-examine-directory'
  1536. EVENT could be \"mouse clicked\" or similar."
  1537. (interactive "e")
  1538. (mouse-set-point event)
  1539. (svn-status-find-file-or-examine-directory))
  1540. (defun svn-status-line-info->ui-status (line-info)
  1541. "Return the ui-status structure of LINE-INFO.
  1542. See `svn-status-make-ui-status' for information about the ui-status."
  1543. (nth 0 line-info))
  1544. (defun svn-status-line-info->has-usermark (line-info) (nth 0 (nth 0 line-info)))
  1545. (defun svn-status-line-info->user-elide (line-info) (nth 1 (nth 0 line-info)))
  1546. (defun svn-status-line-info->filemark (line-info) (nth 1 line-info))
  1547. (defun svn-status-line-info->propmark (line-info) (nth 2 line-info))
  1548. (defun svn-status-line-info->filename (line-info) (nth 3 line-info))
  1549. (defun svn-status-line-info->filename-nondirectory (line-info)
  1550. (file-name-nondirectory (svn-status-line-info->filename line-info)))
  1551. (defun svn-status-line-info->localrev (line-info)
  1552. (if (>= (nth 4 line-info) 0)
  1553. (nth 4 line-info)
  1554. nil))
  1555. (defun svn-status-line-info->lastchangerev (line-info)
  1556. "Return the last revision in which LINE-INFO was modified."
  1557. (let ((l (nth 5 line-info)))
  1558. (if (and l (>= l 0))
  1559. l
  1560. nil)))
  1561. (defun svn-status-line-info->author (line-info) (nth 6 line-info))
  1562. (defun svn-status-line-info->update-available (line-info)
  1563. "Return whether LINE-INFO is out of date.
  1564. In other words, whether there is a newer version available in the
  1565. repository than the working copy."
  1566. (nth 7 line-info))
  1567. (defun svn-status-line-info->locked (line-info)
  1568. "Return whether LINE-INFO represents a locked file.
  1569. This is column three of the `svn status' output.
  1570. The result will be nil or \"L\".
  1571. \(A file becomes locked when an operation is interupted; run \\[svn-status-cleanup]'
  1572. to unlock it.\)"
  1573. (nth 8 line-info))
  1574. (defun svn-status-line-info->historymark (line-info)
  1575. "Mark from column four of output from `svn status'.
  1576. This will be nil unless the file is scheduled for addition with
  1577. history, when it will be \"+\"."
  1578. (nth 9 line-info))
  1579. (defun svn-status-line-info->switched (line-info)
  1580. "Return whether LINE-INFO is switched relative to its parent.
  1581. This is column five of the output from `svn status'.
  1582. The result will be nil or \"S\"."
  1583. (nth 10 line-info))
  1584. (defun svn-status-line-info->is-visiblep (line-info)
  1585. (not (or (svn-status-line-info->hide-because-unknown line-info)
  1586. (svn-status-line-info->hide-because-unmodified line-info)
  1587. (svn-status-line-info->hide-because-user-elide line-info))))
  1588. (defun svn-status-line-info->hide-because-unknown (line-info)
  1589. (and svn-status-hide-unknown
  1590. (eq (svn-status-line-info->filemark line-info) ??)))
  1591. (defun svn-status-line-info->hide-because-unmodified (line-info)
  1592. ;;(message " %S %S %S %S - %s" svn-status-hide-unmodified (svn-status-line-info->propmark line-info) ?_
  1593. ;; (svn-status-line-info->filemark line-info) (svn-status-line-info->filename line-info))
  1594. (and svn-status-hide-unmodified
  1595. (and (or (eq (svn-status-line-info->filemark line-info) ?_)
  1596. (eq (svn-status-line-info->filemark line-info) ? ))
  1597. (or (eq (svn-status-line-info->propmark line-info) ?_)
  1598. (eq (svn-status-line-info->propmark line-info) ? )
  1599. (eq (svn-status-line-info->propmark line-info) nil)))))
  1600. (defun svn-status-line-info->hide-because-user-elide (line-info)
  1601. (eq (svn-status-line-info->user-elide line-info) t))
  1602. (defun svn-status-line-info->show-user-elide-continuation (line-info)
  1603. (eq (svn-status-line-info->user-elide line-info) 'directory))
  1604. ;; modify the line-info
  1605. (defun svn-status-line-info->set-filemark (line-info value)
  1606. (setcar (nthcdr 1 line-info) value))
  1607. (defun svn-status-line-info->set-propmark (line-info value)
  1608. (setcar (nthcdr 2 line-info) value))
  1609. (defun svn-status-line-info->set-localrev (line-info value)
  1610. (setcar (nthcdr 4 line-info) value))
  1611. (defun svn-status-line-info->set-lastchangerev (line-info value)
  1612. (setcar (nthcdr 5 line-info) value))
  1613. (defun svn-status-copy-filename-as-kill (arg)
  1614. "Copy the actual file name to the kill-ring.
  1615. When called with the prefix argument 0, use the full path name."
  1616. (interactive "P")
  1617. (let ((str (if (eq arg 0)
  1618. (svn-status-line-info->full-path (svn-status-get-line-information))
  1619. (svn-status-line-info->filename (svn-status-get-line-information)))))
  1620. (kill-new str)
  1621. (message "Copied %s" str)))
  1622. (defun svn-status-toggle-elide ()
  1623. (interactive)
  1624. (let ((st-info svn-status-info)
  1625. (fname)
  1626. (test (svn-status-line-info->filename (svn-status-get-line-information)))
  1627. (len-test)
  1628. (len-fname)
  1629. (new-elide-mark t)
  1630. (elide-mark))
  1631. (if (member test svn-status-elided-list)
  1632. (setq svn-status-elided-list (delete test svn-status-elided-list))
  1633. (add-to-list 'svn-status-elided-list test))
  1634. (when (string= test ".")
  1635. (setq test ""))
  1636. (setq len-test (length test))
  1637. (while st-info
  1638. (setq fname (svn-status-line-info->filename (car st-info)))
  1639. (setq len-fname (length fname))
  1640. (when (and (>= len-fname len-test)
  1641. (string= (substring fname 0 len-test) test))
  1642. (setq elide-mark new-elide-mark)
  1643. (when (or (string= fname ".")
  1644. (and (= len-fname len-test) (svn-status-line-info->directory-p (car st-info))))
  1645. (message "Elided directory %s and all its files." fname)
  1646. (setq new-elide-mark (not (svn-status-line-info->user-elide (car st-info))))
  1647. (setq elide-mark (if new-elide-mark 'directory nil)))
  1648. ;;(message "elide-mark: %S member: %S" elide-mark (member fname svn-status-elided-list))
  1649. (when (and (member fname svn-status-elided-list) (not elide-mark))
  1650. (setq svn-status-elided-list (delete fname svn-status-elided-list)))
  1651. (setcar (nthcdr 1 (svn-status-line-info->ui-status (car st-info))) elide-mark))
  1652. (setq st-info (cdr st-info))))
  1653. ;;(message "svn-status-elided-list: %S" svn-status-elided-list)
  1654. (svn-status-update-buffer))
  1655. (defun svn-status-apply-elide-list ()
  1656. "Elide files/directories according to `svn-status-elided-list'."
  1657. (interactive)
  1658. (let ((st-info svn-status-info)
  1659. (fname)
  1660. (len-fname)
  1661. (test)
  1662. (len-test)
  1663. (elided-list)
  1664. (elide-mark))
  1665. (while st-info
  1666. (setq fname (svn-status-line-info->filename (car st-info)))
  1667. (setq len-fname (length fname))
  1668. (setq elided-list svn-status-elided-list)
  1669. (setq elide-mark nil)
  1670. (while elided-list
  1671. (setq test (car elided-list))
  1672. (when (string= test ".")
  1673. (setq test ""))
  1674. (setq len-test (length test))
  1675. (when (and (>= len-fname len-test)
  1676. (string= (substring fname 0 len-test) test))
  1677. (setq elide-mark t)
  1678. (when (or (string= fname ".")
  1679. (and (= len-fname len-test) (svn-status-line-info->directory-p (car st-info))))
  1680. (setq elide-mark 'directory)))
  1681. (setq elided-list (cdr elided-list)))
  1682. ;;(message "fname: %s elide-mark: %S" fname elide-mark)
  1683. (setcar (nthcdr 1 (svn-status-line-info->ui-status (car st-info))) elide-mark)
  1684. (setq st-info (cdr st-info))))
  1685. (svn-status-update-buffer))
  1686. (defun svn-status-update-with-command-list (cmd-list)
  1687. (save-excursion
  1688. (set-buffer svn-status-buffer-name)
  1689. (let ((st-info)
  1690. (found)
  1691. (action)
  1692. (fname (svn-status-line-info->filename (svn-status-get-line-information)))
  1693. (fname-pos (point))
  1694. (column (current-column)))
  1695. (setq cmd-list (sort cmd-list '(lambda (item1 item2) (string-lessp (car item1) (car item2)))))
  1696. (while cmd-list
  1697. (unless st-info (setq st-info svn-status-info))
  1698. ;;(message "%S" (caar cmd-list))
  1699. (setq found nil)
  1700. (while (and (not found) st-info)
  1701. (setq found (string= (caar cmd-list) (svn-status-line-info->filename (car st-info))))
  1702. ;;(message "found: %S" found)
  1703. (unless found (setq st-info (cdr st-info))))
  1704. (unless found
  1705. (svn-status-message 3 "psvn: continue to search for %s" (caar cmd-list))
  1706. (setq st-info svn-status-info)
  1707. (while (and (not found) st-info)
  1708. (setq found (string= (caar cmd-list) (svn-status-line-info->filename (car st-info))))
  1709. (unless found (setq st-info (cdr st-info)))))
  1710. (if found
  1711. ;;update the info line
  1712. (progn
  1713. (setq action (cadar cmd-list))
  1714. ;;(message "found %s, action: %S" (caar cmd-list) action)
  1715. (svn-status-annotate-status-buffer-entry action (car st-info)))
  1716. (svn-status-message 3 "psvn: did not find %s" (caar cmd-list)))
  1717. (setq cmd-list (cdr cmd-list)))
  1718. (if fname
  1719. (progn
  1720. (goto-char fname-pos)
  1721. (svn-status-goto-file-name fname)
  1722. (goto-char (+ column (svn-point-at-bol))))
  1723. (goto-char (+ (next-overlay-change (point-min)) svn-status-default-column))))))
  1724. (defun svn-status-annotate-status-buffer-entry (action line-info)
  1725. (let ((tag-string))
  1726. (svn-status-goto-file-name (svn-status-line-info->filename line-info))
  1727. (when (and (member action '(committed added))
  1728. svn-status-commit-rev-number)
  1729. (svn-status-line-info->set-localrev line-info svn-status-commit-rev-number)
  1730. (svn-status-line-info->set-lastchangerev line-info svn-status-commit-rev-number))
  1731. (cond ((equal action 'committed)
  1732. (setq tag-string " <committed>"))
  1733. ((equal action 'added)
  1734. (setq tag-string " <added>"))
  1735. ((equal action 'deleted)
  1736. (setq tag-string " <deleted>"))
  1737. ((equal action 'replaced)
  1738. (setq tag-string " <replaced>"))
  1739. ((equal action 'updated)
  1740. (setq tag-string " <updated>"))
  1741. ((equal action 'propset)
  1742. ;;(setq tag-string " <propset>")
  1743. (svn-status-line-info->set-propmark line-info svn-status-file-modified-after-save-flag))
  1744. ((equal action 'added-wc)
  1745. (svn-status-line-info->set-filemark line-info ?A)
  1746. (svn-status-line-info->set-localrev line-info 0))
  1747. ((equal action 'deleted-wc)
  1748. (svn-status-line-info->set-filemark line-info ?D))
  1749. (t
  1750. (error "Unknown action '%s for %s" action (svn-status-line-info->filename line-info))))
  1751. (when tag-string
  1752. (svn-status-line-info->set-filemark line-info ? )
  1753. (svn-status-line-info->set-propmark line-info ? ))
  1754. (let ((buffer-read-only nil))
  1755. (delete-region (svn-point-at-bol) (svn-point-at-eol))
  1756. (svn-insert-line-in-status-buffer line-info)
  1757. (backward-char 1)
  1758. (when tag-string
  1759. (insert tag-string))
  1760. (delete-char 1))))
  1761. ;; (svn-status-update-with-command-list '(("++ideas" committed) ("a.txt" committed) ("alf")))
  1762. ;; (svn-status-update-with-command-list (svn-status-parse-commit-output))
  1763. (defun svn-status-parse-commit-output ()
  1764. "Parse the output of svn commit.
  1765. Return a list that is suitable for `svn-status-update-with-command-list'"
  1766. (save-excursion
  1767. (set-buffer "*svn-process*")
  1768. (let ((action)
  1769. (name)
  1770. (skip)
  1771. (result))
  1772. (goto-char (point-min))
  1773. (setq svn-status-commit-rev-number nil)
  1774. (setq skip nil) ; set to t whenever we find a line not about a committed file
  1775. (while (< (point) (point-max))
  1776. (cond ((= (svn-point-at-eol) (svn-point-at-bol)) ;skip blank lines
  1777. (setq skip t))
  1778. ((looking-at "Sending")
  1779. (setq action 'committed))
  1780. ((looking-at "Adding")
  1781. (setq action 'added))
  1782. ((looking-at "Deleting")
  1783. (setq action 'deleted))
  1784. ((looking-at "Replacing")
  1785. (setq action 'replaced))
  1786. ((looking-at "Transmitting file data")
  1787. (setq skip t))
  1788. ((looking-at "Committed revision \\([0-9]+\\)")
  1789. (setq svn-status-commit-rev-number
  1790. (string-to-number (svn-match-string-no-properties 1)))
  1791. (setq skip t))
  1792. (t ;; this should never be needed(?)
  1793. (setq action 'unknown)))
  1794. (unless skip ;found an interesting line
  1795. (forward-char 15)
  1796. (when svn-status-operated-on-dot
  1797. ;; when the commit used . as argument, delete the trailing directory
  1798. ;; from the svn output
  1799. (search-forward "/" nil t))
  1800. (setq name (buffer-substring-no-properties (point) (svn-point-at-eol)))
  1801. (setq result (cons (list name action)
  1802. result))
  1803. (setq skip nil))
  1804. (forward-line 1))
  1805. result)))
  1806. ;;(svn-status-parse-commit-output)
  1807. ;;(svn-status-annotate-status-buffer-entry)
  1808. (defun svn-status-parse-ar-output ()
  1809. "Parse the output of svn add|remove.
  1810. Return a list that is suitable for `svn-status-update-with-command-list'"
  1811. (save-excursion
  1812. (set-buffer "*svn-process*")
  1813. (let ((action)
  1814. (name)
  1815. (skip)
  1816. (result))
  1817. (goto-char (point-min))
  1818. (while (< (point) (point-max))
  1819. (cond ((= (svn-point-at-eol) (svn-point-at-bol)) ;skip blank lines
  1820. (setq skip t))
  1821. ((looking-at "A")
  1822. (setq action 'added-wc))
  1823. ((looking-at "D")
  1824. (setq action 'deleted-wc))
  1825. (t ;; this should never be needed(?)
  1826. (setq action 'unknown)))
  1827. (unless skip ;found an interesting line
  1828. (forward-char 10)
  1829. (setq name (buffer-substring-no-properties (point) (svn-point-at-eol)))
  1830. (setq result (cons (list name action)
  1831. result))
  1832. (setq skip nil))
  1833. (forward-line 1))
  1834. result)))
  1835. ;; (svn-status-parse-ar-output)
  1836. ;; (svn-status-update-with-command-list (svn-status-parse-ar-output))
  1837. (defun svn-status-parse-update-output ()
  1838. "Parse the output of svn update.
  1839. Return a list that is suitable for `svn-status-update-with-command-list'"
  1840. (save-excursion
  1841. (set-buffer "*svn-process*")
  1842. (let ((action)
  1843. (name)
  1844. (skip)
  1845. (result))
  1846. (goto-char (point-min))
  1847. (while (< (point) (point-max))
  1848. (cond ((= (svn-point-at-eol) (svn-point-at-bol)) ;skip blank lines
  1849. (setq skip t))
  1850. ((looking-at "Updated to")
  1851. (setq skip t))
  1852. ((looking-at "At revision")
  1853. (setq skip t))
  1854. ((looking-at "U")
  1855. (setq action 'updated))
  1856. ((looking-at "A")
  1857. (setq action 'added))
  1858. ((looking-at "D")
  1859. (setq skip t))
  1860. ;;(setq action 'deleted)) ;;deleted files are not displayed in the svn status output.
  1861. (t ;; this should never be needed(?)
  1862. (setq action 'unknown)))
  1863. (unless skip ;found an interesting line
  1864. (forward-char 3)
  1865. (setq name (buffer-substring-no-properties (point) (svn-point-at-eol)))
  1866. (setq result (cons (list name action)
  1867. result))
  1868. (setq skip nil))
  1869. (forward-line 1))
  1870. result)))
  1871. ;; (svn-status-parse-update-output)
  1872. ;; (svn-status-update-with-command-list (svn-status-parse-update-output))
  1873. (defun svn-status-parse-property-output ()
  1874. "Parse the output of svn propset.
  1875. Return a list that is suitable for `svn-status-update-with-command-list'"
  1876. (save-excursion
  1877. (set-buffer "*svn-process*")
  1878. (let ((result))
  1879. (dolist (line (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n"))
  1880. (message "%s" line)
  1881. (when (string-match "property '\\(.+\\)' set on '\\(.+\\)'" line)
  1882. ;;(message "property %s - file %s" (match-string 1 line) (match-string 2 line))
  1883. (setq result (cons (list (match-string 2 line) 'propset) result))))
  1884. result)))
  1885. ;; (svn-status-parse-property-output)
  1886. ;; (svn-status-update-with-command-list (svn-status-parse-property-output))
  1887. (defun svn-status-line-info->symlink-p (line-info)
  1888. "Return non-nil if LINE-INFO refers to a symlink, nil otherwise.
  1889. The value is the name of the file to which it is linked. \(See
  1890. `file-symlink-p'.\)
  1891. On win32 systems this won't work, even though symlinks are supported
  1892. by subversion on such systems."
  1893. ;; on win32 would need to see how svn does symlinks
  1894. (file-symlink-p (svn-status-line-info->filename line-info)))
  1895. (defun svn-status-line-info->directory-p (line-info)
  1896. "Return t if LINE-INFO refers to a directory, nil otherwise.
  1897. Symbolic links to directories count as directories (see `file-directory-p')."
  1898. (file-directory-p (svn-status-line-info->filename line-info)))
  1899. (defun svn-status-line-info->full-path (line-info)
  1900. "Return the full path of the file represented by LINE-INFO."
  1901. (expand-file-name
  1902. (svn-status-line-info->filename line-info)))
  1903. ;;Not convinced that this is the fastest way, but...
  1904. (defun svn-status-count-/ (string)
  1905. "Return number of \"/\"'s in STRING."
  1906. (let ((n 0)
  1907. (last 0))
  1908. (while (setq last (string-match "/" string (1+ last)))
  1909. (setq n (1+ n)))
  1910. n))
  1911. (defun svn-insert-line-in-status-buffer (line-info)
  1912. "Format LINE-INFO and insert the result in the current buffer."
  1913. (let ((usermark (if (svn-status-line-info->has-usermark line-info) "*" " "))
  1914. (update-available (if (svn-status-line-info->update-available line-info)
  1915. (svn-add-face (if svn-status-short-mod-flag-p
  1916. "** "
  1917. " (Update Available)")
  1918. 'svn-status-update-available-face)
  1919. (if svn-status-short-mod-flag-p " " "")))
  1920. (filename ;; <indentation>file or /path/to/file
  1921. (concat
  1922. (if (or svn-status-display-full-path
  1923. svn-status-hide-unmodified)
  1924. (svn-add-face
  1925. (let ((dir-name (file-name-as-directory
  1926. (svn-status-line-info->directory-containing-line-info
  1927. line-info nil))))
  1928. (if (and (<= 2 (length dir-name))
  1929. (= ?. (aref dir-name 0))
  1930. (= ?/ (aref dir-name 1)))
  1931. (substring dir-name 2)
  1932. dir-name))
  1933. 'svn-status-directory-face)
  1934. ;; showing all files, so add indentation
  1935. (make-string (* 2 (svn-status-count-/
  1936. (svn-status-line-info->filename line-info)))
  1937. 32))
  1938. (svn-status-choose-face-to-add
  1939. (svn-status-line-info->directory-p line-info)
  1940. (svn-status-line-info->filename-nondirectory line-info)
  1941. 'svn-status-directory-face
  1942. 'svn-status-filename-face)
  1943. ;; if it's a symlkink, add '-> target'
  1944. (let ((target (svn-status-line-info->symlink-p line-info)))
  1945. (when target
  1946. (concat " -> "
  1947. ;; add face to target: could maybe
  1948. ;; use different faces for
  1949. ;; unversioned targets?
  1950. (svn-status-choose-face-to-add
  1951. (file-directory-p target)
  1952. (file-relative-name
  1953. target
  1954. (svn-status-line-info->directory-containing-line-info
  1955. line-info t)); name relative to dir of line-info, not '.'
  1956. 'svn-status-directory-face
  1957. 'svn-status-filename-face)
  1958. )))
  1959. ))
  1960. (elide-hint (if (svn-status-line-info->show-user-elide-continuation line-info) " ..." "")))
  1961. (svn-puthash (svn-status-line-info->filename line-info)
  1962. (point)
  1963. svn-status-filename-to-buffer-position-cache)
  1964. (insert (svn-status-maybe-add-face
  1965. (svn-status-line-info->has-usermark line-info)
  1966. (concat usermark
  1967. (format svn-status-line-format
  1968. (svn-status-line-info->filemark line-info)
  1969. (or (svn-status-line-info->propmark line-info) ? )
  1970. (or (svn-status-line-info->historymark line-info) ? )
  1971. (or (svn-status-line-info->localrev line-info) "")
  1972. (or (svn-status-line-info->lastchangerev line-info) "")
  1973. (svn-status-line-info->author line-info))
  1974. (if svn-status-short-mod-flag-p update-available filename)
  1975. (if svn-status-short-mod-flag-p filename update-available)
  1976. (svn-status-maybe-add-string (svn-status-line-info->locked line-info)
  1977. " [ LOCKED ]" 'svn-status-locked-face)
  1978. (svn-status-maybe-add-string (svn-status-line-info->switched line-info)
  1979. " (switched)" 'svn-status-switched-face)
  1980. elide-hint)
  1981. 'svn-status-marked-face)
  1982. "\n")))
  1983. (defun svn-status-update-buffer ()
  1984. "Update the `svn-status-buffer-name' buffer, using `svn-status-info'."
  1985. (interactive)
  1986. ;(message "buffer-name: %s" (buffer-name))
  1987. (unless (string= (buffer-name) svn-status-buffer-name)
  1988. (set-buffer svn-status-buffer-name))
  1989. (svn-status-mode)
  1990. (let ((st-info svn-status-info)
  1991. (buffer-read-only nil)
  1992. (start-pos)
  1993. (overlay)
  1994. (unmodified-count 0) ;how many unmodified files are hidden
  1995. (unknown-count 0) ;how many unknown files are hidden
  1996. (custom-hide-count 0) ;how many files are hidden via svn-status-custom-hide-function
  1997. (marked-count 0) ;how many files are elided
  1998. (user-elide-count 0)
  1999. (first-line t)
  2000. (fname (svn-status-line-info->filename (svn-status-get-line-information)))
  2001. (fname-pos (point))
  2002. (header-line-string)
  2003. (column (current-column)))
  2004. (delete-region (point-min) (point-max))
  2005. (insert "\n")
  2006. ;; Insert all files and directories
  2007. (while st-info
  2008. (setq start-pos (point))
  2009. (cond ((or (svn-status-line-info->has-usermark (car st-info)) first-line)
  2010. ;; Show a marked file and the "." always
  2011. (svn-insert-line-in-status-buffer (car st-info))
  2012. (setq first-line nil))
  2013. ((svn-status-line-info->update-available (car st-info))
  2014. (svn-insert-line-in-status-buffer (car st-info)))
  2015. ((and svn-status-custom-hide-function
  2016. (apply svn-status-custom-hide-function (list (car st-info))))
  2017. (setq custom-hide-count (1+ custom-hide-count)))
  2018. ((svn-status-line-info->hide-because-user-elide (car st-info))
  2019. (setq user-elide-count (1+ user-elide-count)))
  2020. ((svn-status-line-info->hide-because-unknown (car st-info))
  2021. (setq unknown-count (1+ unknown-count)))
  2022. ((svn-status-line-info->hide-because-unmodified (car st-info))
  2023. (setq unmodified-count (1+ unmodified-count)))
  2024. (t
  2025. (svn-insert-line-in-status-buffer (car st-info))))
  2026. (when (svn-status-line-info->has-usermark (car st-info))
  2027. (setq marked-count (+ marked-count 1)))
  2028. (setq overlay (make-overlay start-pos (point)))
  2029. (overlay-put overlay 'svn-info (car st-info))
  2030. (setq st-info (cdr st-info)))
  2031. ;; Insert status information at the buffer beginning
  2032. (goto-char (point-min))
  2033. (insert (format "svn status for directory %s%s\n"
  2034. default-directory
  2035. (if svn-status-head-revision (format " (status against revision: %s)"
  2036. svn-status-head-revision)
  2037. "")))
  2038. (when svn-status-module-name
  2039. (insert (format "Project name: %s\n" svn-status-module-name)))
  2040. (when svn-status-base-info
  2041. (insert (concat "Repository: " (svn-status-base-info->url) "\n")))
  2042. (when svn-status-hide-unknown
  2043. (insert
  2044. (format "%d Unknown file(s) are hidden - press `?' to toggle hiding\n"
  2045. unknown-count)))
  2046. (when svn-status-hide-unmodified
  2047. (insert
  2048. (format "%d Unmodified file(s) are hidden - press `_' to toggle hiding\n"
  2049. unmodified-count)))
  2050. (when (> custom-hide-count 0)
  2051. (insert
  2052. (format "%d file(s) are hidden via the svn-status-custom-hide-function\n"
  2053. custom-hide-count)))
  2054. (when (> user-elide-count 0)
  2055. (insert (format "%d file(s) elided\n" user-elide-count)))
  2056. (insert (format "%d file(s) marked\n" marked-count))
  2057. (setq header-line-string (concat (format svn-status-line-format
  2058. 70 80 72 "BASE" "CMTD" "Author")
  2059. (if svn-status-short-mod-flag-p "em " "")
  2060. "File"))
  2061. (cond ((eq svn-status-use-header-line t)
  2062. (setq header-line-format (concat " " header-line-string)))
  2063. ((eq svn-status-use-header-line 'inline)
  2064. (insert "\n " header-line-string "\n")))
  2065. (setq svn-start-of-file-list-line-number (+ (count-lines (point-min) (point)) 1))
  2066. (if fname
  2067. (progn
  2068. (goto-char fname-pos)
  2069. (svn-status-goto-file-name fname)
  2070. (goto-char (+ column (svn-point-at-bol))))
  2071. (goto-char (+ (next-overlay-change (point-min)) svn-status-default-column)))))
  2072. (defun svn-status-parse-info (arg)
  2073. "Parse the svn info output for the base directory.
  2074. Show the repository url after this call in the `svn-status-buffer-name' buffer.
  2075. When called with the prefix argument 0, reset the information to nil.
  2076. This hides the repository information again.
  2077. When ARG is t, don't update the svn status buffer. This is useful for
  2078. non-interactive use."
  2079. (interactive "P")
  2080. (if (eq arg 0)
  2081. (setq svn-status-base-info nil)
  2082. (svn-run nil t 'parse-info "info" ".")
  2083. (svn-status-parse-info-result))
  2084. (unless (eq arg t)
  2085. (svn-status-update-buffer)))
  2086. (defun svn-status-parse-info-result ()
  2087. "Parse the result from the svn info command.
  2088. Put the found values in `svn-status-base-info'."
  2089. (let ((url)
  2090. (repository-root))
  2091. (save-excursion
  2092. (set-buffer "*svn-process*")
  2093. (goto-char (point-min))
  2094. (let ((case-fold-search t))
  2095. (search-forward "url: ")
  2096. (setq url (buffer-substring-no-properties (point) (svn-point-at-eol)))
  2097. (search-forward "repository root: ")
  2098. (setq repository-root (buffer-substring-no-properties (point) (svn-point-at-eol)))))
  2099. (setq svn-status-base-info `((url ,url) (repository-root ,repository-root)))))
  2100. (defun svn-status-base-info->url ()
  2101. "Extract the url part from `svn-status-base-info'."
  2102. (if svn-status-base-info
  2103. (cadr (assoc 'url svn-status-base-info))
  2104. ""))
  2105. (defun svn-status-base-info->repository-root ()
  2106. "Extract the repository-root part from `svn-status-base-info'."
  2107. (if svn-status-base-info
  2108. (cadr (assoc 'repository-root svn-status-base-info))
  2109. ""))
  2110. (defun svn-status-ls (path)
  2111. "Run svn ls PATH."
  2112. (interactive "sPath for svn ls: ")
  2113. (svn-run t t 'ls "ls" path))
  2114. (defun svn-status-ls-branches ()
  2115. "Show, which branches exist for the actual working copy.
  2116. Note: this command assumes the proposed standard svn repository layout."
  2117. (interactive)
  2118. (svn-status-parse-info t)
  2119. (svn-status-ls (concat (svn-status-base-info->repository-root) "/branches")))
  2120. (defun svn-status-toggle-edit-cmd-flag (&optional reset)
  2121. "Allow the user to edit the parameters for the next svn command.
  2122. This command toggles between
  2123. * editing the next command parameters (EditCmd)
  2124. * editing all all command parameters (EditCmd#)
  2125. * don't edit the command parameters ()
  2126. The string in parentheses is shown in the status line to show the state."
  2127. (interactive)
  2128. (cond ((or reset (eq svn-status-edit-svn-command 'sticky))
  2129. (setq svn-status-edit-svn-command nil))
  2130. ((eq svn-status-edit-svn-command nil)
  2131. (setq svn-status-edit-svn-command t))
  2132. ((eq svn-status-edit-svn-command t)
  2133. (setq svn-status-edit-svn-command 'sticky)))
  2134. (cond ((eq svn-status-edit-svn-command t)
  2135. (setq svn-status-mode-line-process-edit-flag " EditCmd"))
  2136. ((eq svn-status-edit-svn-command 'sticky)
  2137. (setq svn-status-mode-line-process-edit-flag " EditCmd#"))
  2138. (t
  2139. (setq svn-status-mode-line-process-edit-flag "")))
  2140. (svn-status-update-mode-line))
  2141. (defun svn-status-goto-root-or-return ()
  2142. "Bounce point between the root (\".\") and the current line."
  2143. (interactive)
  2144. (if (string= (svn-status-line-info->filename (svn-status-get-line-information)) ".")
  2145. (when svn-status-root-return-info
  2146. (svn-status-goto-file-name
  2147. (svn-status-line-info->filename svn-status-root-return-info)))
  2148. (setq svn-status-root-return-info (svn-status-get-line-information))
  2149. (svn-status-goto-file-name ".")))
  2150. (defun svn-status-next-line (nr-of-lines)
  2151. (interactive "p")
  2152. (next-line nr-of-lines)
  2153. (when (svn-status-get-line-information)
  2154. (goto-char (+ (svn-point-at-bol) svn-status-default-column))))
  2155. (defun svn-status-previous-line (nr-of-lines)
  2156. (interactive "p")
  2157. (previous-line nr-of-lines)
  2158. (when (svn-status-get-line-information)
  2159. (goto-char (+ (svn-point-at-bol) svn-status-default-column))))
  2160. (defun svn-status-dired-jump ()
  2161. "Jump to a dired buffer, containing the file at point."
  2162. (interactive)
  2163. (let* ((line-info (svn-status-get-line-information))
  2164. (file-full-path (svn-status-line-info->full-path line-info)))
  2165. (let ((default-directory
  2166. (file-name-as-directory
  2167. (expand-file-name (svn-status-line-info->directory-containing-line-info line-info t)))))
  2168. (dired-jump))
  2169. (dired-goto-file file-full-path)))
  2170. (defun svn-status-possibly-negate-meaning-of-arg (arg &optional command)
  2171. "Negate arg, if this-command is a member of svn-status-possibly-negate-meaning-of-arg."
  2172. (unless command
  2173. (setq command this-command))
  2174. (if (member command svn-status-negate-meaning-of-arg-commands)
  2175. (not arg)
  2176. arg))
  2177. (defun svn-status-update (&optional arg)
  2178. "Run 'svn status -v'.
  2179. When called with a prefix argument run 'svn status -vu'."
  2180. (interactive "P")
  2181. (unless (interactive-p)
  2182. (save-excursion
  2183. (set-buffer "*svn-process*")
  2184. (setq svn-status-update-previous-process-output
  2185. (buffer-substring (point-min) (point-max)))))
  2186. (svn-status default-directory arg))
  2187. (defun svn-status-get-line-information ()
  2188. "Find out about the file under point.
  2189. The result may be parsed with the various `svn-status-line-info->...' functions."
  2190. (if (eq major-mode 'svn-status-mode)
  2191. (let ((svn-info nil))
  2192. (dolist (overlay (overlays-at (point)))
  2193. (setq svn-info (or svn-info
  2194. (overlay-get overlay 'svn-info))))
  2195. svn-info)
  2196. ;; different mode, means called not from the *svn-status* buffer
  2197. '((nil nil) 32 nil "." 0 0 "" nil nil nil nil)))
  2198. (defun svn-status-get-file-list (use-marked-files)
  2199. "Get either the selected files or the file under point.
  2200. USE-MARKED-FILES decides which we do.
  2201. See `svn-status-marked-files' for what counts as selected."
  2202. (if use-marked-files
  2203. (svn-status-marked-files)
  2204. (list (svn-status-get-line-information))))
  2205. (defun svn-status-get-file-list-names (use-marked-files)
  2206. (mapcar 'svn-status-line-info->filename (svn-status-get-file-list use-marked-files)))
  2207. (defun svn-status-get-file-information ()
  2208. "Find out about the file under point.
  2209. The result may be parsed with the various `svn-status-line-info->...' functions.
  2210. When called from a *svn-status* buffer, do the same as `svn-status-get-file-information'.
  2211. When called from a file buffer provide a structure that contains the filename."
  2212. (cond ((eq major-mode 'svn-status-mode)
  2213. (svn-status-get-file-information))
  2214. (t
  2215. ;; a fake strukture that contains the buffername for the current buffer
  2216. (list '(nil nil) 32 nil (buffer-file-name (current-buffer)) 0 0 "" nil nil nil nil))))
  2217. (defun svn-status-select-line ()
  2218. "Return information about the file under point.
  2219. \(Only used for debugging\)"
  2220. (interactive)
  2221. (let ((info (svn-status-get-line-information)))
  2222. (if info
  2223. (message "%S %S %S" info (svn-status-line-info->hide-because-unknown info)
  2224. (svn-status-line-info->hide-because-unmodified info))
  2225. (message "No file on this line"))))
  2226. (defun svn-status-ensure-cursor-on-file ()
  2227. "Raise an error unless point is on a valid file."
  2228. (unless (svn-status-get-line-information)
  2229. (error "No file on the current line")))
  2230. (defun svn-status-directory-containing-point (allow-self)
  2231. "Find the (full path of) directory containing the file under point.
  2232. If ALLOW-SELF and the file is a directory, return that directory,
  2233. otherwise return the directory containing the file under point."
  2234. ;;the first `or' below is because s-s-g-l-i returns `nil' if
  2235. ;;point was outside the file list, but we need
  2236. ;;s-s-l-i->f to return a string to add to `default-directory'.
  2237. (let ((line-info (or (svn-status-get-line-information)
  2238. '(nil nil nil ""))))
  2239. (file-name-as-directory
  2240. (expand-file-name
  2241. (svn-status-line-info->directory-containing-line-info line-info allow-self)))))
  2242. (defun svn-status-line-info->directory-containing-line-info (line-info allow-self)
  2243. "Find the directory containing for LINE-INFO.
  2244. If ALLOW-SELF is t and LINE-INFO refers to a directory then return the
  2245. directory itself, in all other cases find the parent directory"
  2246. (if (and allow-self (svn-status-line-info->directory-p line-info))
  2247. (svn-status-line-info->filename line-info)
  2248. ;;The next `or' is because (file-name-directory "file") returns nil
  2249. (or (file-name-directory (svn-status-line-info->filename line-info))
  2250. ".")))
  2251. (defun svn-status-set-user-mark (arg)
  2252. "Set a user mark on the current file or directory.
  2253. If the cursor is on a file this file is marked and the cursor advances to the next line.
  2254. If the cursor is on a directory all files in this directory are marked.
  2255. If this function is called with a prefix argument, only the current line is
  2256. marked, even if it is a directory."
  2257. (interactive "P")
  2258. (setq arg (svn-status-possibly-negate-meaning-of-arg arg 'svn-status-set-user-mark))
  2259. (let ((info (svn-status-get-line-information)))
  2260. (if info
  2261. (progn
  2262. (svn-status-apply-usermark t arg)
  2263. (svn-status-next-line 1))
  2264. (message "No file on this line - cannot set a mark"))))
  2265. (defun svn-status-unset-user-mark (arg)
  2266. "Remove a user mark on the current file or directory.
  2267. If the cursor is on a file, this file is unmarked and the cursor advances to the next line.
  2268. If the cursor is on a directory, all files in this directory are unmarked.
  2269. If this function is called with a prefix argument, only the current line is
  2270. unmarked, even if is a directory."
  2271. (interactive "P")
  2272. (setq arg (svn-status-possibly-negate-meaning-of-arg arg 'svn-status-set-user-mark))
  2273. (let ((info (svn-status-get-line-information)))
  2274. (if info
  2275. (progn
  2276. (svn-status-apply-usermark nil arg)
  2277. (svn-status-next-line 1))
  2278. (message "No file on this line - cannot unset a mark"))))
  2279. (defun svn-status-unset-user-mark-backwards ()
  2280. "Remove a user mark from the previous file.
  2281. Then move to that line."
  2282. ;; This is consistent with `dired-unmark-backward' and
  2283. ;; `cvs-mode-unmark-up'.
  2284. (interactive)
  2285. (let ((info (save-excursion
  2286. (svn-status-next-line -1)
  2287. (svn-status-get-line-information))))
  2288. (if info
  2289. (progn
  2290. (svn-status-next-line -1)
  2291. (svn-status-apply-usermark nil t))
  2292. (message "No file on previous line - cannot unset a mark"))))
  2293. (defun svn-status-apply-usermark (set-mark only-this-line)
  2294. "Do the work for the various marking/unmarking functions."
  2295. (let* ((st-info svn-status-info)
  2296. (mark-count 0)
  2297. (line-info (svn-status-get-line-information))
  2298. (file-name (svn-status-line-info->filename line-info))
  2299. (sub-file-regexp (concat "^" (regexp-quote
  2300. (file-name-as-directory file-name))))
  2301. (newcursorpos-fname)
  2302. (i-fname)
  2303. (first-line t)
  2304. (current-line svn-start-of-file-list-line-number))
  2305. (while st-info
  2306. (when (or (svn-status-line-info->is-visiblep (car st-info)) first-line)
  2307. (setq current-line (1+ current-line))
  2308. (setq first-line nil))
  2309. (setq i-fname (svn-status-line-info->filename (car st-info)))
  2310. (when (or (string= file-name i-fname)
  2311. (string-match sub-file-regexp i-fname))
  2312. (when (svn-status-line-info->is-visiblep (car st-info))
  2313. (when (or (not only-this-line) (string= file-name i-fname))
  2314. (setq newcursorpos-fname i-fname)
  2315. (unless (eq (car (svn-status-line-info->ui-status (car st-info))) set-mark)
  2316. (setcar (svn-status-line-info->ui-status (car st-info)) set-mark)
  2317. (setq mark-count (+ 1 mark-count))
  2318. (save-excursion
  2319. (let ((buffer-read-only nil))
  2320. (goto-line current-line)
  2321. (delete-region (svn-point-at-bol) (svn-point-at-eol))
  2322. (svn-insert-line-in-status-buffer (car st-info))
  2323. (delete-char 1)))
  2324. (message "%s %s" (if set-mark "Marked" "Unmarked") i-fname)))))
  2325. (setq st-info (cdr st-info)))
  2326. ;;(svn-status-update-buffer)
  2327. (svn-status-goto-file-name newcursorpos-fname)
  2328. (when (> mark-count 1)
  2329. (message "%s %d files" (if set-mark "Marked" "Unmarked") mark-count))))
  2330. (defun svn-status-apply-usermark-checked (check-function set-mark)
  2331. "Mark or unmark files, whether a given function returns t.
  2332. The function is called with the line information. Therefore the
  2333. svn-status-line-info->* functions can be used in the check."
  2334. (let ((st-info svn-status-info)
  2335. (mark-count 0))
  2336. (while st-info
  2337. (when (apply check-function (list (car st-info)))
  2338. (unless (eq (svn-status-line-info->has-usermark (car st-info)) set-mark)
  2339. (setq mark-count (+ 1 mark-count))
  2340. (message "%s %s"
  2341. (if set-mark "Marked" "Unmarked")
  2342. (svn-status-line-info->filename (car st-info))))
  2343. (setcar (svn-status-line-info->ui-status (car st-info)) set-mark))
  2344. (setq st-info (cdr st-info)))
  2345. (svn-status-update-buffer)
  2346. (when (> mark-count 1)
  2347. (message "%s %d files" (if set-mark "Marked" "Unmarked") mark-count))))
  2348. (defun svn-status-mark-unknown (arg)
  2349. "Mark all unknown files.
  2350. These are the files marked with '?' in the `svn-status-buffer-name' buffer.
  2351. If the function is called with a prefix arg, unmark all these files."
  2352. (interactive "P")
  2353. (svn-status-apply-usermark-checked
  2354. '(lambda (info) (eq (svn-status-line-info->filemark info) ??)) (not arg)))
  2355. (defun svn-status-mark-added (arg)
  2356. "Mark all added files.
  2357. These are the files marked with 'A' in the `svn-status-buffer-name' buffer.
  2358. If the function is called with a prefix ARG, unmark all these files."
  2359. (interactive "P")
  2360. (svn-status-apply-usermark-checked
  2361. '(lambda (info) (eq (svn-status-line-info->filemark info) ?A)) (not arg)))
  2362. (defun svn-status-mark-modified (arg)
  2363. "Mark all modified files.
  2364. These are the files marked with 'M' in the `svn-status-buffer-name' buffer.
  2365. If the function is called with a prefix ARG, unmark all these files."
  2366. (interactive "P")
  2367. (svn-status-apply-usermark-checked
  2368. '(lambda (info) (or (eq (svn-status-line-info->filemark info) ?M)
  2369. (eq (svn-status-line-info->filemark info)
  2370. svn-status-file-modified-after-save-flag)))
  2371. (not arg)))
  2372. (defun svn-status-mark-deleted (arg)
  2373. "Mark all files scheduled for deletion.
  2374. These are the files marked with 'D' in the `svn-status-buffer-name' buffer.
  2375. If the function is called with a prefix ARG, unmark all these files."
  2376. (interactive "P")
  2377. (svn-status-apply-usermark-checked
  2378. '(lambda (info) (eq (svn-status-line-info->filemark info) ?D)) (not arg)))
  2379. (defun svn-status-mark-changed (arg)
  2380. "Mark all files that could be committed.
  2381. This means we mark
  2382. * all modified files
  2383. * all files scheduled for addition
  2384. * all files scheduled for deletion
  2385. The last two categories include all copied and moved files.
  2386. If called with a prefix ARG, unmark all such files."
  2387. (interactive "P")
  2388. (svn-status-mark-added arg)
  2389. (svn-status-mark-modified arg)
  2390. (svn-status-mark-deleted arg))
  2391. (defun svn-status-unset-all-usermarks ()
  2392. (interactive)
  2393. (svn-status-apply-usermark-checked '(lambda (info) t) nil))
  2394. (defun svn-status-toggle-hide-unknown ()
  2395. (interactive)
  2396. (setq svn-status-hide-unknown (not svn-status-hide-unknown))
  2397. (svn-status-update-buffer))
  2398. (defun svn-status-toggle-hide-unmodified ()
  2399. (interactive)
  2400. (setq svn-status-hide-unmodified (not svn-status-hide-unmodified))
  2401. (svn-status-update-buffer))
  2402. (defun svn-status-get-file-name-buffer-position (name)
  2403. "Find the buffer position for a file.
  2404. If the file is not found, return nil."
  2405. (let ((start-pos (let ((cached-pos (gethash name
  2406. svn-status-filename-to-buffer-position-cache)))
  2407. (when cached-pos
  2408. (goto-char (previous-overlay-change cached-pos)))
  2409. (point)))
  2410. (found))
  2411. ;; performance optimization: search from point to end of buffer
  2412. (while (and (not found) (< (point) (point-max)))
  2413. (goto-char (next-overlay-change (point)))
  2414. (when (string= name (svn-status-line-info->filename
  2415. (svn-status-get-line-information)))
  2416. (setq start-pos (+ (point) svn-status-default-column))
  2417. (setq found t)))
  2418. ;; search from buffer start to point
  2419. (goto-char (point-min))
  2420. (while (and (not found) (< (point) start-pos))
  2421. (goto-char (next-overlay-change (point)))
  2422. (when (string= name (svn-status-line-info->filename
  2423. (svn-status-get-line-information)))
  2424. (setq start-pos (+ (point) svn-status-default-column))
  2425. (setq found t)))
  2426. (and found start-pos)))
  2427. (defun svn-status-goto-file-name (name)
  2428. "Move the cursor the the line that displays NAME."
  2429. (let ((pos (svn-status-get-file-name-buffer-position name)))
  2430. (if pos
  2431. (goto-char pos)
  2432. (svn-status-message 7 "Note: svn-status-goto-file-name: %s not found" name))))
  2433. (defun svn-status-find-info-for-file-name (name)
  2434. (let* ((st-info svn-status-info)
  2435. (info))
  2436. (while st-info
  2437. (when (string= name (svn-status-line-info->filename (car st-info)))
  2438. (setq info (car st-info))
  2439. (setq st-info nil)) ; terminate loop
  2440. (setq st-info (cdr st-info)))
  2441. info))
  2442. (defun svn-status-marked-files ()
  2443. "Return all files marked by `svn-status-set-user-mark',
  2444. or (if no files were marked) the file under point."
  2445. (let* ((st-info svn-status-info)
  2446. (file-list))
  2447. (while st-info
  2448. (when (svn-status-line-info->has-usermark (car st-info))
  2449. (setq file-list (append file-list (list (car st-info)))))
  2450. (setq st-info (cdr st-info)))
  2451. (or file-list
  2452. (if (svn-status-get-line-information)
  2453. (list (svn-status-get-line-information))
  2454. nil))))
  2455. (defun svn-status-marked-file-names ()
  2456. (mapcar 'svn-status-line-info->filename (svn-status-marked-files)))
  2457. (defun svn-status-some-files-marked-p ()
  2458. "Return non-nil iff a file has been marked by `svn-status-set-user-mark'.
  2459. Unlike `svn-status-marked-files', this does not select the file under point
  2460. if no files have been marked."
  2461. ;; `some' would be shorter but requires cl-seq at runtime.
  2462. ;; (Because it accepts both lists and vectors, it is difficult to inline.)
  2463. (loop for file in svn-status-info
  2464. thereis (svn-status-line-info->has-usermark file)))
  2465. (defun svn-status-ui-information-hash-table ()
  2466. (let ((st-info svn-status-info)
  2467. (svn-status-ui-information (make-hash-table :test 'equal)))
  2468. (while st-info
  2469. (svn-puthash (svn-status-line-info->filename (car st-info))
  2470. (svn-status-line-info->ui-status (car st-info))
  2471. svn-status-ui-information)
  2472. (setq st-info (cdr st-info)))
  2473. svn-status-ui-information))
  2474. (defun svn-status-create-arg-file (file-name prefix file-info-list postfix)
  2475. (with-temp-file file-name
  2476. (insert prefix)
  2477. (let ((st-info file-info-list))
  2478. (while st-info
  2479. (insert (svn-status-line-info->filename (car st-info)))
  2480. (insert "\n")
  2481. (setq st-info (cdr st-info)))
  2482. (insert postfix))))
  2483. (defun svn-status-show-process-buffer-internal (&optional scroll-to-top)
  2484. (when (string= (buffer-name) svn-status-buffer-name)
  2485. (delete-other-windows))
  2486. (pop-to-buffer "*svn-process*")
  2487. (svn-process-mode)
  2488. (when svn-status-wash-control-M-in-process-buffers
  2489. (svn-status-remove-control-M))
  2490. (when scroll-to-top
  2491. (goto-char (point-min)))
  2492. (other-window 1))
  2493. (defun svn-status-show-process-output (cmd &optional scroll-to-top)
  2494. "Display the result of a svn command.
  2495. Consider svn-status-window-alist to choose the buffer name."
  2496. (let ((window-mode (cadr (assoc cmd svn-status-window-alist))))
  2497. (cond ((eq window-mode nil) ;; use *svn-process* buffer
  2498. (setq svn-status-last-output-buffer-name "*svn-process*"))
  2499. ((eq window-mode t) ;; use *svn-info* buffer
  2500. (setq svn-status-last-output-buffer-name "*svn-info*"))
  2501. ((eq window-mode 'invisible) ;; don't display the buffer
  2502. (setq svn-status-last-output-buffer-name nil))
  2503. (t
  2504. (setq svn-status-last-output-buffer-name window-mode)))
  2505. (when svn-status-last-output-buffer-name
  2506. (if window-mode
  2507. (progn
  2508. (unless svn-status-preserve-window-configuration
  2509. (when (string= (buffer-name) svn-status-buffer-name)
  2510. (delete-other-windows)))
  2511. (pop-to-buffer "*svn-process*")
  2512. (switch-to-buffer (get-buffer-create svn-status-last-output-buffer-name))
  2513. (let ((buffer-read-only nil))
  2514. (delete-region (point-min) (point-max))
  2515. (insert-buffer-substring "*svn-process*")
  2516. (when scroll-to-top
  2517. (goto-char (point-min))))
  2518. (when (eq window-mode t) ;; *svn-info* buffer
  2519. (svn-info-mode))
  2520. (other-window 1))
  2521. (svn-status-show-process-buffer-internal scroll-to-top)))))
  2522. (defun svn-status-show-svn-log (arg)
  2523. "Run `svn log' on selected files.
  2524. The output is put into the *svn-log* buffer
  2525. The optional prefix argument ARG determines which switches are passed to `svn log':
  2526. no prefix --- use whatever is in the list `svn-status-default-log-arguments'
  2527. prefix argument of -1 --- use no arguments
  2528. prefix argument of 0: --- use the -q switch (quiet)
  2529. other prefix arguments: --- use the -v switch (verbose)
  2530. See `svn-status-marked-files' for what counts as selected."
  2531. (interactive "P")
  2532. (let ((switches (cond ((eq arg 0) '("-q"))
  2533. ((eq arg -1) '())
  2534. (arg '("-v"))
  2535. (t svn-status-default-log-arguments))))
  2536. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
  2537. (svn-run t t 'log "log" "--targets" svn-status-temp-arg-file switches)
  2538. (save-excursion
  2539. (set-buffer "*svn-process*")
  2540. (svn-log-view-mode))))
  2541. (defun svn-status-info ()
  2542. "Run `svn info' on all selected files.
  2543. See `svn-status-marked-files' for what counts as selected."
  2544. (interactive)
  2545. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
  2546. (svn-run t t 'info "info" "--targets" svn-status-temp-arg-file))
  2547. (defun svn-status-blame (revision)
  2548. "Run `svn blame' on the current file.
  2549. When called with a prefix argument, ask the user for the REVISION to use.
  2550. When called from a file buffer, go to the current line in the resulting blame output."
  2551. (interactive "P")
  2552. (when current-prefix-arg
  2553. (setq revision (svn-status-read-revision-string "Blame for version: " "BASE")))
  2554. (unless revision (setq revision "BASE"))
  2555. (svn-run t t 'blame "blame" "-r" revision (svn-status-line-info->filename (svn-status-get-file-information))))
  2556. (defun svn-status-show-svn-diff (arg)
  2557. "Run `svn diff' on the current file.
  2558. If the current file is a directory, compare it recursively.
  2559. If there is a newer revision in the repository, the diff is done against HEAD,
  2560. otherwise compare the working copy with BASE.
  2561. If ARG then prompt for revision to diff against."
  2562. (interactive "P")
  2563. (svn-status-ensure-cursor-on-file)
  2564. (svn-status-show-svn-diff-internal (list (svn-status-get-line-information)) t
  2565. (if arg :ask :auto)))
  2566. (defun svn-status-show-svn-diff-for-marked-files (arg)
  2567. "Run `svn diff' on all selected files.
  2568. If some files have been marked, compare those non-recursively;
  2569. this is because marking a directory with \\[svn-status-set-user-mark]
  2570. normally marks all of its files as well.
  2571. If no files have been marked, compare recursively the file at point.
  2572. If ARG then prompt for revision to diff against, else compare working copy with BASE."
  2573. (interactive "P")
  2574. (svn-status-show-svn-diff-internal (svn-status-marked-files)
  2575. (not (svn-status-some-files-marked-p))
  2576. (if arg :ask "BASE")))
  2577. (defun svn-status-show-svn-diff-internal (line-infos recursive revision)
  2578. ;; REVISION must be one of:
  2579. ;; - a string: whatever the -r option allows.
  2580. ;; - `:ask': asks the user to specify the revision, which then becomes
  2581. ;; saved in `minibuffer-history' rather than in `command-history'.
  2582. ;; - `:auto': use "HEAD" if an update is known to exist, "BASE" otherwise.
  2583. ;; In the future, `nil' might mean omit the -r option entirely;
  2584. ;; but that currently seems to imply "BASE", so we just use that.
  2585. (when (eq revision :ask)
  2586. (setq revision (svn-status-read-revision-string
  2587. "Diff with files for version: " "PREV")))
  2588. (let ((clear-buf t)
  2589. (beginning nil))
  2590. (dolist (line-info line-infos)
  2591. (svn-run nil clear-buf 'diff "diff" svn-status-default-diff-arguments
  2592. "-r" (if (eq revision :auto)
  2593. (if (svn-status-line-info->update-available line-info)
  2594. "HEAD" "BASE")
  2595. revision)
  2596. (unless recursive "--non-recursive")
  2597. (svn-status-line-info->filename line-info))
  2598. (setq clear-buf nil)
  2599. ;; "svn diff --non-recursive" skips only subdirectories, not files.
  2600. ;; But a non-recursive diff via psvn should skip files too, because
  2601. ;; the user would have marked them if he wanted them to be compared.
  2602. ;; So we'll look for the "Index: foo" line that marks the first file
  2603. ;; in the diff output, and delete it and everything that follows.
  2604. ;; This is made more complicated by the fact that `svn-status-activate-diff-mode'
  2605. ;; expects the output to be left in the *svn-process* buffer.
  2606. (unless recursive
  2607. ;; Check `directory-p' relative to the `default-directory' of the
  2608. ;; "*svn-status*" buffer, not that of the "*svn-process*" buffer.
  2609. (let ((directory-p (svn-status-line-info->directory-p line-info)))
  2610. (with-current-buffer "*svn-process*"
  2611. (when directory-p
  2612. (goto-char (or beginning (point-min)))
  2613. (when (re-search-forward "^Index: " nil t)
  2614. (delete-region (match-beginning 0) (point-max))))
  2615. (goto-char (setq beginning (point-max))))))))
  2616. (svn-status-activate-diff-mode))
  2617. (defun svn-status-diff-save-current-defun-as-kill ()
  2618. "Copy the function name for the change at point to the kill-ring.
  2619. That function uses `add-log-current-defun'"
  2620. (interactive)
  2621. (let ((func-name (add-log-current-defun)))
  2622. (if func-name
  2623. (progn
  2624. (kill-new func-name)
  2625. (message "Copied %S" func-name))
  2626. (message "No current defun detected."))))
  2627. (defun svn-status-activate-diff-mode ()
  2628. "Show the *svn-process* buffer, using the diff-mode."
  2629. (svn-status-show-process-output 'diff t)
  2630. (save-excursion
  2631. (set-buffer svn-status-last-output-buffer-name)
  2632. (svn-status-diff-mode)
  2633. (setq buffer-read-only t)))
  2634. (define-derived-mode svn-status-diff-mode fundamental-mode "svn-diff"
  2635. "Major mode to display svn diffs. Derives from `diff-mode'.
  2636. Commands:
  2637. \\{svn-status-diff-mode-map}
  2638. "
  2639. (let ((diff-mode-shared-map (copy-keymap svn-status-diff-mode-map))
  2640. major-mode mode-name)
  2641. (diff-mode)))
  2642. (defun svn-status-show-process-buffer ()
  2643. "Show the content of the *svn-process* buffer"
  2644. (interactive)
  2645. (svn-status-show-process-output nil))
  2646. (defun svn-status-add-file-recursively (arg)
  2647. "Run `svn add' on all selected files.
  2648. When a directory is added, add files recursively.
  2649. See `svn-status-marked-files' for what counts as selected.
  2650. When this function is called with a prefix argument, use the actual file instead."
  2651. (interactive "P")
  2652. (message "adding: %S" (svn-status-get-file-list-names (not arg)))
  2653. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-get-file-list (not arg)) "")
  2654. (svn-run t t 'add "add" "--targets" svn-status-temp-arg-file))
  2655. (defun svn-status-add-file (arg)
  2656. "Run `svn add' on all selected files.
  2657. When a directory is added, don't add the files of the directory
  2658. (svn add --non-recursive <file-list> is called).
  2659. See `svn-status-marked-files' for what counts as selected.
  2660. When this function is called with a prefix argument, use the actual file instead."
  2661. (interactive "P")
  2662. (message "adding: %S" (svn-status-get-file-list-names (not arg)))
  2663. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-get-file-list (not arg)) "")
  2664. (svn-run t t 'add "add" "--non-recursive" "--targets" svn-status-temp-arg-file))
  2665. (defun svn-status-make-directory (dir)
  2666. "Run `svn mkdir DIR'."
  2667. ;; TODO: Allow entering a URI interactively.
  2668. ;; Currently, `read-file-name' corrupts it.
  2669. (interactive (list (read-file-name "Make directory: "
  2670. (svn-status-directory-containing-point t))))
  2671. (unless (string-match "^[^:/]+://" dir) ; Is it a URI?
  2672. (setq dir (file-relative-name dir)))
  2673. (svn-run t t 'mkdir "mkdir" "--" dir))
  2674. ;;TODO: write a svn-status-cp similar to this---maybe a common
  2675. ;;function to do both?
  2676. (defun svn-status-mv ()
  2677. "Prompt for a destination, and `svn mv' selected files there.
  2678. See `svn-status-marked-files' for what counts as `selected'.
  2679. If one file was selected then the destination DEST should be a
  2680. filename to rename the selected file to, or a directory to move the
  2681. file into; if multiple files were selected then DEST should be a
  2682. directory to move the selected files into.
  2683. The default DEST is the directory containing point.
  2684. BUG: If we've marked some directory containging a file as well as the
  2685. file itself, then we should just mv the directory, but this implementation
  2686. doesn't check for that.
  2687. SOLUTION: for each dir, umark all its contents (but not the dir
  2688. itself) before running mv."
  2689. (interactive)
  2690. (let* ((marked-files (svn-status-marked-files))
  2691. (num-of-files (length marked-files))
  2692. dest)
  2693. (if (= 1 num-of-files)
  2694. ;; one file to rename, prompt for new name, or directory to move the
  2695. ;; file into.
  2696. (setq dest (read-file-name (format "Rename %s to: "
  2697. (svn-status-line-info->filename (car marked-files)))
  2698. (svn-status-directory-containing-point t)
  2699. (svn-status-line-info->full-path (car marked-files))))
  2700. ;;multiple files selected, so prompt for existing directory to mv them into.
  2701. (setq dest (svn-read-directory-name (format "Move %d files to directory: " num-of-files)
  2702. (svn-status-directory-containing-point t) nil t))
  2703. (unless (file-directory-p dest)
  2704. (error "%s is not a directory" dest)))
  2705. (when (string= dest "")
  2706. (error "No destination entered; no files moved"))
  2707. (unless (string-match "^[^:/]+://" dest) ; Is it a URI?
  2708. (setq dest (file-relative-name dest)))
  2709. ;
  2710. ;;do the move: svn mv only lets us move things once at a time, so
  2711. ;;we need to run svn mv once for each file (hence second arg to
  2712. ;;svn-run is nil.)
  2713. ;;TODO: before doing any moving, For every marked directory,
  2714. ;;ensure none of its contents are also marked, since we dont want
  2715. ;;to move both file *and* its parent...
  2716. ;; what about hidden files?? what if user marks a dir+contents, then presses `_' ??
  2717. ;; ;one solution:
  2718. ;; (dolist (original marked-files)
  2719. ;; (when (svn-status-line-info->directory-p original)
  2720. ;; ;; run svn-status-goto-file-name to move point to line of file
  2721. ;; ;; run svn-status-unset-user-mark to unmark dir+all contents
  2722. ;; ;; run svn-status-set-user-mark to remark dir
  2723. ;; ;; maybe check for local mods here, and unmark if user does't say --force?
  2724. ;; ))
  2725. (dolist (original marked-files)
  2726. (let ((original-name (svn-status-line-info->filename original))
  2727. (original-filemarks (svn-status-line-info->filemark original))
  2728. (original-propmarks (svn-status-line-info->propmark original)))
  2729. (cond
  2730. ((or (eq original-filemarks 77) ;;original has local mods: maybe do `svn mv --force'
  2731. (eq original-propmarks 77)) ;;original has local prop mods: maybe do `svn mv --force'
  2732. (if (yes-or-no-p (format "%s has local modifications; use `--force' to really move it? "
  2733. original-name))
  2734. (svn-run nil t 'mv "mv" "--force" "--" original-name dest)
  2735. (message "Not moving %s" original-name)))
  2736. ((eq original-filemarks 63) ;;original is unversioned: maybe do plain `mv'
  2737. (if (yes-or-no-p (format "%s is unversioned. Use plain `mv -i %s %s'? "
  2738. original-name original-name dest))
  2739. (call-process "mv" nil (get-buffer-create "*svn-process*") nil "-i" original-name dest)
  2740. (message "Not moving %s" original-name)))
  2741. ((eq original-filemarks 65) ;;original has `A' mark (eg it was `svn add'ed, but not committed)
  2742. (message "Not moving %s (try committing it first)" original-name))
  2743. ((eq original-filemarks 32) ;;original is unmodified: can use `svn mv'
  2744. (svn-run nil t 'mv "mv" "--" original-name dest))
  2745. ;;file is conflicted in some way?
  2746. (t
  2747. (if (yes-or-no-p (format "The status of %s looks scary. Risk moving it anyway? " original-name))
  2748. (svn-run nil t 'mv "mv" "--" original-name dest)
  2749. (message "Not moving %s" original-name))))))
  2750. (svn-status-update)))
  2751. (defun svn-status-revert ()
  2752. "Run `svn revert' on all selected files.
  2753. See `svn-status-marked-files' for what counts as selected."
  2754. (interactive)
  2755. (let* ((marked-files (svn-status-marked-files))
  2756. (num-of-files (length marked-files)))
  2757. (when (yes-or-no-p
  2758. (if (= 1 num-of-files)
  2759. (format "Revert %s? " (svn-status-line-info->filename (car marked-files)))
  2760. (format "Revert %d files? " num-of-files)))
  2761. (message "reverting: %S" (svn-status-marked-file-names))
  2762. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
  2763. (svn-run t t 'revert "revert" "--targets" svn-status-temp-arg-file))))
  2764. (defun svn-status-rm (force)
  2765. "Run `svn rm' on all selected files.
  2766. See `svn-status-marked-files' for what counts as selected.
  2767. When called with a prefix argument add the command line switch --force."
  2768. (interactive "P")
  2769. (let* ((marked-files (svn-status-marked-files))
  2770. (num-of-files (length marked-files)))
  2771. (when (yes-or-no-p
  2772. (if (= 1 num-of-files)
  2773. (format "%sRemove %s? " (if force "Force " "") (svn-status-line-info->filename (car marked-files)))
  2774. (format "%sRemove %d files? " (if force "Force " "") num-of-files)))
  2775. (message "removing: %S" (svn-status-marked-file-names))
  2776. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
  2777. (if force
  2778. (svn-run t t 'rm "rm" "--force" "--targets" svn-status-temp-arg-file)
  2779. (svn-run t t 'rm "rm" "--targets" svn-status-temp-arg-file)))))
  2780. (defun svn-status-update-cmd (arg)
  2781. "Run svn update.
  2782. When called with a prefix argument, ask the user for the revision to update to."
  2783. (interactive "P")
  2784. (let ((rev (when arg (svn-status-read-revision-string (format "Directory: %s: Run svn update -r " default-directory)))))
  2785. (message "Running svn-update for %s" default-directory)
  2786. ;;TODO: use file names also??
  2787. (svn-run t t 'update "update" (when rev (list "-r" rev)))))
  2788. (defun svn-status-commit ()
  2789. "Commit selected files.
  2790. If some files have been marked, commit those non-recursively;
  2791. this is because marking a directory with \\[svn-status-set-user-mark]
  2792. normally marks all of its files as well.
  2793. If no files have been marked, commit recursively the file at point."
  2794. (interactive)
  2795. (svn-status-save-some-buffers)
  2796. (let* ((selected-files (svn-status-marked-files))
  2797. (marked-files-p (svn-status-some-files-marked-p)))
  2798. (setq svn-status-files-to-commit selected-files
  2799. svn-status-recursive-commit (not marked-files-p))
  2800. (svn-log-edit-show-files-to-commit)
  2801. (svn-status-pop-to-commit-buffer)
  2802. (when svn-log-edit-insert-files-to-commit
  2803. (svn-log-edit-insert-files-to-commit))))
  2804. (defun svn-status-pop-to-commit-buffer ()
  2805. (interactive)
  2806. (setq svn-status-pre-commit-window-configuration (current-window-configuration))
  2807. (let* ((use-existing-buffer (get-buffer "*svn-log-edit*"))
  2808. (commit-buffer (get-buffer-create "*svn-log-edit*"))
  2809. (dir default-directory))
  2810. (pop-to-buffer commit-buffer)
  2811. (setq default-directory dir)
  2812. (unless use-existing-buffer
  2813. (when (and svn-log-edit-file-name (file-readable-p svn-log-edit-file-name))
  2814. (insert-file-contents svn-log-edit-file-name)))
  2815. (svn-log-edit-mode)))
  2816. (defun svn-status-switch-to-status-buffer ()
  2817. "Switch to the `svn-status-buffer-name' buffer."
  2818. (interactive)
  2819. (switch-to-buffer svn-status-buffer-name))
  2820. (defun svn-status-pop-to-status-buffer ()
  2821. "Pop to the `svn-status-buffer-name' buffer."
  2822. (interactive)
  2823. (pop-to-buffer svn-status-buffer-name))
  2824. (defun svn-status-export ()
  2825. "Run `svn export' for the current working copy.
  2826. Ask the user for the destination path.
  2827. `svn-status-default-export-directory' is suggested as export directory."
  2828. (interactive)
  2829. (let* ((src default-directory)
  2830. (dir1-name (nth 1 (nreverse (split-string src "/"))))
  2831. (dest (read-file-name (format "Export %s to " src) (concat svn-status-default-export-directory dir1-name))))
  2832. (svn-run t t 'export "export" (expand-file-name src) (expand-file-name dest))
  2833. (message "svn-status-export %s %s" src dest)))
  2834. (defun svn-status-cleanup (arg)
  2835. "Run `svn cleanup' on all selected files.
  2836. See `svn-status-marked-files' for what counts as selected.
  2837. When this function is called with a prefix argument, use the actual file instead."
  2838. (interactive "P")
  2839. (let ((file-names (svn-status-get-file-list-names (not arg))))
  2840. (if file-names
  2841. (progn
  2842. (message "svn-status-cleanup %S" file-names)
  2843. (svn-run t t 'cleanup (append (list "cleanup") file-names)))
  2844. (message "No valid file selected - No status cleanup possible"))))
  2845. (defun svn-status-resolved ()
  2846. "Run `svn resolved' on all selected files.
  2847. See `svn-status-marked-files' for what counts as selected."
  2848. (interactive)
  2849. (let* ((marked-files (svn-status-marked-files))
  2850. (num-of-files (length marked-files)))
  2851. (when (yes-or-no-p
  2852. (if (= 1 num-of-files)
  2853. (format "Resolve %s? " (svn-status-line-info->filename (car marked-files)))
  2854. (format "Resolve %d files? " num-of-files)))
  2855. (message "resolving: %S" (svn-status-marked-file-names))
  2856. (svn-status-create-arg-file svn-status-temp-arg-file "" (svn-status-marked-files) "")
  2857. (svn-run t t 'resolved "resolved" "--targets" svn-status-temp-arg-file))))
  2858. (defun svn-status-svnversion ()
  2859. "Run svnversion on the directory that contains the file at point."
  2860. (interactive)
  2861. (svn-status-ensure-cursor-on-file)
  2862. (let ((simple-path (svn-status-line-info->filename (svn-status-get-line-information)))
  2863. (full-path (svn-status-line-info->full-path (svn-status-get-line-information)))
  2864. (version))
  2865. (unless (file-directory-p simple-path)
  2866. (setq simple-path (or (file-name-directory simple-path) "."))
  2867. (setq full-path (file-name-directory full-path)))
  2868. (setq version (shell-command-to-string (concat "svnversion -n " full-path)))
  2869. (message "svnversion for '%s': %s" simple-path version)
  2870. version))
  2871. ;; --------------------------------------------------------------------------------
  2872. ;; Update the `svn-status-buffer-name' buffer, when a file is saved
  2873. ;; --------------------------------------------------------------------------------
  2874. (defvar svn-status-file-modified-after-save-flag ?m
  2875. "Flag shown whenever a file is modified and saved in Emacs.
  2876. The flag is shown in the `svn-status-buffer-name' buffer.
  2877. Recommended values are ?m or ?M.")
  2878. (defun svn-status-after-save-hook ()
  2879. "Set a modified indication, when a file is saved from a svn working copy."
  2880. (let* ((svn-dir (car-safe svn-status-directory-history))
  2881. (svn-dir (when svn-dir (expand-file-name svn-dir)))
  2882. (file-dir (file-name-directory (buffer-file-name)))
  2883. (svn-dir-len (length (or svn-dir "")))
  2884. (file-dir-len (length file-dir))
  2885. (file-name))
  2886. (when (and (get-buffer svn-status-buffer-name)
  2887. svn-dir
  2888. (>= file-dir-len svn-dir-len)
  2889. (string= (substring file-dir 0 svn-dir-len) svn-dir))
  2890. (setq file-name (substring (buffer-file-name) svn-dir-len))
  2891. ;;(message "In svn-status directory %S" file-name)
  2892. (let ((st-info svn-status-info)
  2893. (i-fname))
  2894. (while st-info
  2895. (setq i-fname (svn-status-line-info->filename (car st-info)))
  2896. ;;(message "i-fname=%S" i-fname)
  2897. (when (and (string= file-name i-fname)
  2898. (not (eq (svn-status-line-info->filemark (car st-info)) ??)))
  2899. (svn-status-line-info->set-filemark (car st-info)
  2900. svn-status-file-modified-after-save-flag)
  2901. (save-window-excursion
  2902. (set-buffer svn-status-buffer-name)
  2903. (save-excursion
  2904. (let ((buffer-read-only nil)
  2905. (pos (svn-status-get-file-name-buffer-position i-fname)))
  2906. (if pos
  2907. (progn
  2908. (goto-char pos)
  2909. (delete-region (svn-point-at-bol) (svn-point-at-eol))
  2910. (svn-insert-line-in-status-buffer (car st-info))
  2911. (delete-char 1))
  2912. (svn-status-message 3 "psvn: file %s not found, updating %s buffer content..."
  2913. i-fname svn-status-buffer-name)
  2914. (svn-status-update-buffer))))))
  2915. (setq st-info (cdr st-info))))))
  2916. nil)
  2917. (add-hook 'after-save-hook 'svn-status-after-save-hook)
  2918. ;; --------------------------------------------------------------------------------
  2919. ;; Getting older revisions
  2920. ;; --------------------------------------------------------------------------------
  2921. (defun svn-status-get-specific-revision (arg)
  2922. "Retrieve older revisions.
  2923. The older revisions are stored in backup files named F.~REVISION~.
  2924. When the function is called without a prefix argument: get all marked files.
  2925. With a prefix argument: get only the actual file."
  2926. (interactive "P")
  2927. (svn-status-get-specific-revision-internal
  2928. (svn-status-get-file-list (not arg))
  2929. :ask))
  2930. (defun svn-status-get-specific-revision-internal (line-infos revision)
  2931. "Retrieve older revisions of files.
  2932. LINE-INFOS is a list of line-info structures (see
  2933. `svn-status-get-line-information').
  2934. REVISION is one of:
  2935. - a string: whatever the -r option allows.
  2936. - `:ask': asks the user to specify the revision, which then becomes
  2937. saved in `minibuffer-history' rather than in `command-history'.
  2938. - `:auto': Use \"HEAD\" if an update is known to exist, \"BASE\" otherwise.
  2939. After the call, `svn-status-get-revision-file-info' will be an alist
  2940. \((WORKING-FILE-NAME . RETRIEVED-REVISION-FILE-NAME) ...). These file
  2941. names are relative to the directory where `svn-status' was run."
  2942. ;; In `svn-status-show-svn-diff-internal', there is a comment
  2943. ;; that REVISION `nil' might mean omitting the -r option entirely.
  2944. ;; That doesn't seem like a good idea with svn cat.
  2945. ;;
  2946. ;; TODO: Return the alist, instead of storing it in a variable.
  2947. (when (eq revision :ask)
  2948. (setq revision (svn-status-read-revision-string
  2949. "Get files for version: " "PREV")))
  2950. (let ((count (length line-infos)))
  2951. (if (= count 1)
  2952. (let ((line-info (car line-infos)))
  2953. (message "Getting revision %s of %s"
  2954. (if (eq revision :auto)
  2955. (if (svn-status-line-info->update-available line-info)
  2956. "HEAD" "BASE")
  2957. revision)
  2958. (svn-status-line-info->filename line-info)))
  2959. ;; We could compute "Getting HEAD of 8 files and BASE of 11 files"
  2960. ;; but that'd be more bloat than it's worth.
  2961. (message "Getting revision %s of %d files"
  2962. (if (eq revision :auto) "HEAD or BASE" revision)
  2963. count)))
  2964. (setq svn-status-get-specific-revision-file-info '())
  2965. (dolist (line-info line-infos)
  2966. (let* ((revision (if (eq revision :auto)
  2967. (if (svn-status-line-info->update-available line-info)
  2968. "HEAD" "BASE")
  2969. revision)) ;must be a string by this point
  2970. (file-name (svn-status-line-info->filename line-info))
  2971. ;; If REVISION is e.g. "HEAD", should we find out the actual
  2972. ;; revision number and save "foo.~123~" rather than "foo.~HEAD~"?
  2973. ;; OTOH, `auto-mode-alist' already ignores ".~HEAD~" suffixes,
  2974. ;; and if users often want to know the revision numbers of such
  2975. ;; files, they can use svn:keywords.
  2976. (file-name-with-revision (concat file-name ".~" revision "~")))
  2977. ;; `add-to-list' would unnecessarily check for duplicates.
  2978. (push (cons file-name file-name-with-revision)
  2979. svn-status-get-specific-revision-file-info)
  2980. (save-excursion
  2981. (let ((content
  2982. (with-temp-buffer
  2983. (if (string= revision "BASE")
  2984. (insert-file-contents (concat (file-name-directory file-name)
  2985. (svn-wc-adm-dir-name)
  2986. "/text-base/"
  2987. (file-name-nondirectory file-name)
  2988. ".svn-base"))
  2989. (progn
  2990. (svn-run nil t 'cat "cat" "-r" revision file-name)
  2991. ;;todo: error processing
  2992. ;;svn: Filesystem has no item
  2993. ;;svn: file not found: revision `15', path `/trunk/file.txt'
  2994. (insert-buffer-substring "*svn-process*")))
  2995. (buffer-string))))
  2996. (find-file file-name-with-revision)
  2997. (setq buffer-read-only nil)
  2998. (erase-buffer) ;Widen, because we'll save the whole buffer.
  2999. (insert content)
  3000. (save-buffer)))))
  3001. (setq svn-status-get-specific-revision-file-info
  3002. (nreverse svn-status-get-specific-revision-file-info))
  3003. (message "svn-status-get-specific-revision-file-info: %S"
  3004. svn-status-get-specific-revision-file-info))
  3005. (defun svn-status-ediff-with-revision (arg)
  3006. "Run ediff on the current file with a previous revision.
  3007. If ARG then prompt for revision to diff against."
  3008. (interactive "P")
  3009. (svn-status-get-specific-revision-internal
  3010. (list (svn-status-get-line-information))
  3011. (if arg :ask :auto))
  3012. (let* ((ediff-after-quit-destination-buffer (current-buffer))
  3013. (my-buffer (find-file-noselect (caar svn-status-get-specific-revision-file-info)))
  3014. (base-buff (find-file-noselect (cdar svn-status-get-specific-revision-file-info)))
  3015. (svn-transient-buffers (list base-buff ))
  3016. (startup-hook '(svn-ediff-startup-hook)))
  3017. (ediff-buffers base-buff my-buffer startup-hook)))
  3018. (defun svn-ediff-startup-hook ()
  3019. (add-hook 'ediff-after-quit-hook-internal
  3020. `(lambda ()
  3021. (svn-ediff-exit-hook
  3022. ',ediff-after-quit-destination-buffer ',svn-transient-buffers))
  3023. nil 'local))
  3024. (defun svn-ediff-exit-hook (svn-buf tmp-bufs)
  3025. ;; kill the temp buffers (and their associated windows)
  3026. (dolist (tb tmp-bufs)
  3027. (when (and tb (buffer-live-p tb) (not (buffer-modified-p tb)))
  3028. (let ((win (get-buffer-window tb t)))
  3029. (when win (delete-window win))
  3030. (kill-buffer tb))))
  3031. ;; switch back to the *svn* buffer
  3032. (when (and svn-buf (buffer-live-p svn-buf)
  3033. (not (get-buffer-window svn-buf t)))
  3034. (ignore-errors (switch-to-buffer svn-buf))))
  3035. (defun svn-status-read-revision-string (prompt &optional default-value)
  3036. "Prompt the user for a svn revision number."
  3037. (interactive)
  3038. (read-string prompt default-value))
  3039. ;; --------------------------------------------------------------------------------
  3040. ;; SVN process handling
  3041. ;; --------------------------------------------------------------------------------
  3042. (defun svn-process-kill ()
  3043. "Kill the current running svn process."
  3044. (interactive)
  3045. (let ((process (get-process "svn")))
  3046. (if process
  3047. (delete-process process)
  3048. (message "No running svn process"))))
  3049. (defun svn-process-send-string (string &optional send-passwd)
  3050. "Send a string to the running svn process.
  3051. This is useful, if the running svn process asks the user a question.
  3052. Note: use C-q C-j to send a line termination character."
  3053. (interactive "sSend string to svn process: ")
  3054. (save-excursion
  3055. (set-buffer "*svn-process*")
  3056. (goto-char (point-max))
  3057. (let ((buffer-read-only nil))
  3058. (insert (if send-passwd (make-string (length string) ?.) string)))
  3059. (set-marker (process-mark (get-process "svn")) (point)))
  3060. (process-send-string "svn" string))
  3061. ;; --------------------------------------------------------------------------------
  3062. ;; Property List stuff
  3063. ;; --------------------------------------------------------------------------------
  3064. (defun svn-status-property-list ()
  3065. (interactive)
  3066. (let ((file-names (svn-status-marked-file-names)))
  3067. (if file-names
  3068. (progn
  3069. (svn-run t t 'proplist (append (list "proplist" "-v") file-names)))
  3070. (message "No valid file selected - No property listing possible"))))
  3071. (defun svn-status-proplist-start ()
  3072. (svn-status-ensure-cursor-on-file)
  3073. (svn-run t t 'proplist-parse "proplist" (svn-status-line-info->filename
  3074. (svn-status-get-line-information))))
  3075. (defun svn-status-property-edit-one-entry (arg)
  3076. "Edit a property.
  3077. When called with a prefix argument, it is possible to enter a new property."
  3078. (interactive "P")
  3079. (setq svn-status-property-edit-must-match-flag (not arg))
  3080. (svn-status-proplist-start))
  3081. (defun svn-status-property-set ()
  3082. (interactive)
  3083. (setq svn-status-property-edit-must-match-flag nil)
  3084. (svn-status-proplist-start))
  3085. (defun svn-status-property-delete ()
  3086. (interactive)
  3087. (setq svn-status-property-edit-must-match-flag t)
  3088. (svn-status-proplist-start))
  3089. (defun svn-status-property-parse-property-names ()
  3090. ;(svn-status-show-process-buffer-internal t)
  3091. (message "svn-status-property-parse-property-names")
  3092. (let ((pl)
  3093. (prop-name)
  3094. (prop-value))
  3095. (save-excursion
  3096. (set-buffer "*svn-process*")
  3097. (goto-char (point-min))
  3098. (forward-line 1)
  3099. (while (looking-at " \\(.+\\)")
  3100. (setq pl (append pl (list (match-string 1))))
  3101. (forward-line 1)))
  3102. ;(cond last-command: svn-status-property-set, svn-status-property-edit-one-entry
  3103. (cond ((eq last-command 'svn-status-property-edit-one-entry)
  3104. ;;(message "svn-status-property-edit-one-entry")
  3105. (setq prop-name
  3106. (completing-read "Set Property - Name: " (mapcar 'list pl)
  3107. nil svn-status-property-edit-must-match-flag))
  3108. (unless (string= prop-name "")
  3109. (save-excursion
  3110. (set-buffer svn-status-buffer-name)
  3111. (svn-status-property-edit (list (svn-status-get-line-information))
  3112. prop-name))))
  3113. ((eq last-command 'svn-status-property-set)
  3114. (message "svn-status-property-set")
  3115. (setq prop-name
  3116. (completing-read "Set Property - Name: " (mapcar 'list pl) nil nil))
  3117. (setq prop-value (read-from-minibuffer "Property value: "))
  3118. (unless (string= prop-name "")
  3119. (save-excursion
  3120. (set-buffer svn-status-buffer-name)
  3121. (message "Setting property %s := %s for %S" prop-name prop-value
  3122. (svn-status-marked-file-names))
  3123. (let ((file-names (svn-status-marked-file-names)))
  3124. (when file-names
  3125. (svn-run nil t 'propset
  3126. (append (list "propset" prop-name prop-value) file-names))
  3127. )
  3128. )
  3129. (message "propset finished.")
  3130. )))
  3131. ((eq last-command 'svn-status-property-delete)
  3132. (setq prop-name
  3133. (completing-read "Delete Property - Name: " (mapcar 'list pl) nil t))
  3134. (unless (string= prop-name "")
  3135. (save-excursion
  3136. (set-buffer svn-status-buffer-name)
  3137. (let ((file-names (svn-status-marked-file-names)))
  3138. (when file-names
  3139. (message "Going to delete prop %s for %s" prop-name file-names)
  3140. (svn-run t t 'propdel
  3141. (append (list "propdel" prop-name) file-names))))))))))
  3142. (defun svn-status-property-edit (file-info-list prop-name &optional new-prop-value)
  3143. (let* ((commit-buffer (get-buffer-create "*svn-property-edit*"))
  3144. (dir default-directory)
  3145. ;; now only one file is implemented ...
  3146. (file-name (svn-status-line-info->filename (car file-info-list)))
  3147. (prop-value))
  3148. (message "Edit property %s for file %s" prop-name file-name)
  3149. (svn-run nil t 'propget-parse "propget" prop-name file-name)
  3150. (save-excursion
  3151. (set-buffer "*svn-process*")
  3152. (setq prop-value (if (> (point-max) 1)
  3153. (buffer-substring (point-min) (- (point-max) 1))
  3154. "")))
  3155. (setq svn-status-propedit-property-name prop-name)
  3156. (setq svn-status-propedit-file-list file-info-list)
  3157. (setq svn-status-pre-propedit-window-configuration (current-window-configuration))
  3158. (pop-to-buffer commit-buffer)
  3159. ;; If the buffer has been narrowed, `svn-prop-edit-done' will use
  3160. ;; only the accessible part. So we need not erase the rest here.
  3161. (delete-region (point-min) (point-max))
  3162. (setq default-directory dir)
  3163. (insert prop-value)
  3164. (svn-status-remove-control-M)
  3165. (when new-prop-value
  3166. (when (listp new-prop-value)
  3167. (message "Adding new prop values %S " new-prop-value)
  3168. (while new-prop-value
  3169. (goto-char (point-min))
  3170. (unless (re-search-forward
  3171. (concat "^" (regexp-quote (car new-prop-value)) "$") nil t)
  3172. (goto-char (point-max))
  3173. (when (> (current-column) 0) (insert "\n"))
  3174. (insert (car new-prop-value)))
  3175. (setq new-prop-value (cdr new-prop-value)))))
  3176. (svn-prop-edit-mode)))
  3177. (defun svn-status-property-set-property (file-info-list prop-name prop-value)
  3178. "Set a property on a given file list."
  3179. (save-excursion
  3180. (set-buffer (get-buffer-create "*svn-property-edit*"))
  3181. ;; If the buffer has been narrowed, `svn-prop-edit-do-it' will use
  3182. ;; only the accessible part. So we need not erase the rest here.
  3183. (delete-region (point-min) (point-max))
  3184. (insert prop-value))
  3185. (setq svn-status-propedit-file-list (svn-status-marked-files))
  3186. (setq svn-status-propedit-property-name prop-name)
  3187. (svn-prop-edit-do-it nil)
  3188. (svn-status-update))
  3189. (defun svn-status-get-directory (line-info)
  3190. (let* ((file-name (svn-status-line-info->filename line-info))
  3191. (file-dir (file-name-directory file-name)))
  3192. ;;(message "file-dir: %S" file-dir)
  3193. (if file-dir
  3194. (substring file-dir 0 (- (length file-dir) 1))
  3195. ".")))
  3196. (defun svn-status-get-file-list-per-directory (files)
  3197. ;;(message "%S" files)
  3198. (let ((dir-list nil)
  3199. (i files)
  3200. (j)
  3201. (dir))
  3202. (while i
  3203. (setq dir (svn-status-get-directory (car i)))
  3204. (setq j (assoc dir dir-list))
  3205. (if j
  3206. (progn
  3207. ;;(message "dir already present %S %s" j dir)
  3208. (setcdr j (append (cdr j) (list (car i)))))
  3209. (setq dir-list (append dir-list (list (list dir (car i))))))
  3210. (setq i (cdr i)))
  3211. ;;(message "svn-status-get-file-list-per-directory: %S" dir-list)
  3212. dir-list))
  3213. (defun svn-status-property-ignore-file ()
  3214. (interactive)
  3215. (let ((d-list (svn-status-get-file-list-per-directory (svn-status-marked-files)))
  3216. (dir)
  3217. (f-info)
  3218. (ext-list))
  3219. (while d-list
  3220. (setq dir (caar d-list))
  3221. (setq f-info (cdar d-list))
  3222. (setq ext-list (mapcar '(lambda (i)
  3223. (svn-status-line-info->filename-nondirectory i)) f-info))
  3224. ;;(message "ignore in dir %s: %S" dir f-info)
  3225. (save-window-excursion
  3226. (when (y-or-n-p (format "Ignore %S for %s? " ext-list dir))
  3227. (svn-status-property-edit
  3228. (list (svn-status-find-info-for-file-name dir)) "svn:ignore" ext-list)
  3229. (svn-prop-edit-do-it nil))) ; synchronous
  3230. (setq d-list (cdr d-list)))
  3231. (svn-status-update)))
  3232. (defun svn-status-property-ignore-file-extension ()
  3233. (interactive)
  3234. (let ((d-list (svn-status-get-file-list-per-directory (svn-status-marked-files)))
  3235. (dir)
  3236. (f-info)
  3237. (ext-list))
  3238. (while d-list
  3239. (setq dir (caar d-list))
  3240. (setq f-info (cdar d-list))
  3241. ;;(message "ignore in dir %s: %S" dir f-info)
  3242. (setq ext-list nil)
  3243. (while f-info
  3244. (add-to-list 'ext-list (concat "*."
  3245. (file-name-extension
  3246. (svn-status-line-info->filename (car f-info)))))
  3247. (setq f-info (cdr f-info)))
  3248. ;;(message "%S" ext-list)
  3249. (save-window-excursion
  3250. (when (y-or-n-p (format "Ignore %S for %s? " ext-list dir))
  3251. (svn-status-property-edit
  3252. (list (svn-status-find-info-for-file-name dir)) "svn:ignore"
  3253. ext-list)
  3254. (svn-prop-edit-do-it nil)))
  3255. (setq d-list (cdr d-list)))
  3256. (svn-status-update)))
  3257. (defun svn-status-property-edit-svn-ignore ()
  3258. (interactive)
  3259. (let* ((line-info (svn-status-get-line-information))
  3260. (dir (if (svn-status-line-info->directory-p line-info)
  3261. (svn-status-line-info->filename line-info)
  3262. (svn-status-get-directory line-info))))
  3263. (svn-status-property-edit
  3264. (list (svn-status-find-info-for-file-name dir)) "svn:ignore")
  3265. (message "Edit svn:ignore on %s" dir)))
  3266. (defun svn-status-property-set-keyword-list ()
  3267. "Edit the svn:keywords property on the marked files."
  3268. (interactive)
  3269. ;;(message "Set svn:keywords for %S" (svn-status-marked-file-names))
  3270. (svn-status-property-edit (svn-status-marked-files) "svn:keywords"))
  3271. (defun svn-status-property-set-eol-style ()
  3272. "Edit the svn:eol-style property on the marked files."
  3273. (interactive)
  3274. (svn-status-property-set-property
  3275. (svn-status-marked-files) "svn:eol-style"
  3276. (completing-read "Set svn:eol-style for the marked files: "
  3277. (mapcar 'list '("native" "CRLF" "LF" "CR"))
  3278. nil t)))
  3279. (defun svn-status-property-set-executable ()
  3280. "Set the svn:executable property on the marked files."
  3281. (interactive)
  3282. (svn-status-property-set-property (svn-status-marked-files) "svn:executable" "*"))
  3283. ;; --------------------------------------------------------------------------------
  3284. ;; svn-prop-edit-mode:
  3285. ;; --------------------------------------------------------------------------------
  3286. (defvar svn-prop-edit-mode-map () "Keymap used in `svn-prop-edit-mode' buffers.")
  3287. (put 'svn-prop-edit-mode-map 'risky-local-variable t) ;for Emacs 20.7
  3288. (when (not svn-prop-edit-mode-map)
  3289. (setq svn-prop-edit-mode-map (make-sparse-keymap))
  3290. (define-key svn-prop-edit-mode-map [(control ?c) (control ?c)] 'svn-prop-edit-done)
  3291. (define-key svn-prop-edit-mode-map [(control ?c) (control ?d)] 'svn-prop-edit-svn-diff)
  3292. (define-key svn-prop-edit-mode-map [(control ?c) (control ?s)] 'svn-prop-edit-svn-status)
  3293. (define-key svn-prop-edit-mode-map [(control ?c) (control ?l)] 'svn-prop-edit-svn-log)
  3294. (define-key svn-prop-edit-mode-map [(control ?c) (control ?q)] 'svn-prop-edit-abort))
  3295. (easy-menu-define svn-prop-edit-mode-menu svn-prop-edit-mode-map
  3296. "'svn-prop-edit-mode' menu"
  3297. '("SVN-PropEdit"
  3298. ["Commit" svn-prop-edit-done t]
  3299. ["Show Diff" svn-prop-edit-svn-diff t]
  3300. ["Show Status" svn-prop-edit-svn-status t]
  3301. ["Show Log" svn-prop-edit-svn-log t]
  3302. ["Abort" svn-prop-edit-abort t]))
  3303. (defun svn-prop-edit-mode ()
  3304. "Major Mode to edit file properties of files under svn control.
  3305. Commands:
  3306. \\{svn-prop-edit-mode-map}"
  3307. (interactive)
  3308. (kill-all-local-variables)
  3309. (use-local-map svn-prop-edit-mode-map)
  3310. (easy-menu-add svn-prop-edit-mode-menu)
  3311. (setq major-mode 'svn-prop-edit-mode)
  3312. (setq mode-name "svn-prop-edit"))
  3313. (defun svn-prop-edit-abort ()
  3314. (interactive)
  3315. (bury-buffer)
  3316. (set-window-configuration svn-status-pre-propedit-window-configuration))
  3317. (defun svn-prop-edit-done ()
  3318. (interactive)
  3319. (svn-prop-edit-do-it t))
  3320. (defun svn-prop-edit-do-it (async)
  3321. (message "svn propset %s on %s"
  3322. svn-status-propedit-property-name
  3323. (mapcar 'svn-status-line-info->filename svn-status-propedit-file-list))
  3324. (save-excursion
  3325. (set-buffer (get-buffer "*svn-property-edit*"))
  3326. (when (fboundp 'set-buffer-file-coding-system)
  3327. (set-buffer-file-coding-system 'undecided-unix nil))
  3328. (setq svn-status-temp-file-to-remove
  3329. (concat svn-status-temp-dir "svn-prop-edit.txt" svn-temp-suffix))
  3330. (write-region (point-min) (point-max) svn-status-temp-file-to-remove nil 1))
  3331. (when svn-status-propedit-file-list ; there are files to change properties
  3332. (svn-status-create-arg-file svn-status-temp-arg-file ""
  3333. svn-status-propedit-file-list "")
  3334. (setq svn-status-propedit-file-list nil)
  3335. (svn-run async t 'propset "propset"
  3336. svn-status-propedit-property-name
  3337. "--targets" svn-status-temp-arg-file
  3338. "-F" (concat svn-status-temp-dir "svn-prop-edit.txt" svn-temp-suffix))
  3339. (unless async (svn-status-remove-temp-file-maybe)))
  3340. (when svn-status-pre-propedit-window-configuration
  3341. (set-window-configuration svn-status-pre-propedit-window-configuration)))
  3342. (defun svn-prop-edit-svn-diff (arg)
  3343. (interactive "P")
  3344. (set-buffer svn-status-buffer-name)
  3345. ;; Because propedit is not recursive in our use, neither is this diff.
  3346. (svn-status-show-svn-diff-internal svn-status-propedit-file-list nil
  3347. (if arg :ask "BASE")))
  3348. (defun svn-prop-edit-svn-log (arg)
  3349. (interactive "P")
  3350. (set-buffer svn-status-buffer-name)
  3351. (svn-status-show-svn-log arg))
  3352. (defun svn-prop-edit-svn-status ()
  3353. (interactive)
  3354. (pop-to-buffer svn-status-buffer-name)
  3355. (other-window 1))
  3356. ;; --------------------------------------------------------------------------------
  3357. ;; svn-log-edit-mode:
  3358. ;; --------------------------------------------------------------------------------
  3359. (defvar svn-log-edit-mode-map () "Keymap used in `svn-log-edit-mode' buffers.")
  3360. (put 'svn-log-edit-mode-map 'risky-local-variable t) ;for Emacs 20.7
  3361. (defvar svn-log-edit-mode-menu) ;really defined with `easy-menu-define' below.
  3362. (if svn-log-edit-use-log-edit-mode
  3363. (define-derived-mode svn-log-edit-mode log-edit-mode "svn-log-edit"
  3364. "Wrapper around `log-edit-mode' for psvn.el"
  3365. (easy-menu-add svn-log-edit-mode-menu)
  3366. (setq svn-log-edit-update-log-entry nil)
  3367. (set (make-local-variable 'log-edit-callback) 'svn-log-edit-done)
  3368. (set (make-local-variable 'log-edit-listfun) 'svn-log-edit-files-to-commit)
  3369. (set (make-local-variable 'log-edit-initial-files) (log-edit-files))
  3370. (message "Press %s when you are done editing."
  3371. (substitute-command-keys "\\[log-edit-done]"))
  3372. )
  3373. (defun svn-log-edit-mode ()
  3374. "Major Mode to edit svn log messages.
  3375. Commands:
  3376. \\{svn-log-edit-mode-map}"
  3377. (interactive)
  3378. (kill-all-local-variables)
  3379. (use-local-map svn-log-edit-mode-map)
  3380. (easy-menu-add svn-log-edit-mode-menu)
  3381. (setq major-mode 'svn-log-edit-mode)
  3382. (setq mode-name "svn-log-edit")
  3383. (setq svn-log-edit-update-log-entry nil)
  3384. (run-hooks 'svn-log-edit-mode-hook)))
  3385. (when (not svn-log-edit-mode-map)
  3386. (setq svn-log-edit-mode-map (make-sparse-keymap))
  3387. (unless svn-log-edit-use-log-edit-mode
  3388. (define-key svn-log-edit-mode-map (kbd "C-c C-c") 'svn-log-edit-done))
  3389. (define-key svn-log-edit-mode-map (kbd "C-c C-d") 'svn-log-edit-svn-diff)
  3390. (define-key svn-log-edit-mode-map (kbd "C-c C-s") 'svn-log-edit-save-message)
  3391. (define-key svn-log-edit-mode-map (kbd "C-c C-i") 'svn-log-edit-svn-status)
  3392. (define-key svn-log-edit-mode-map (kbd "C-c C-l") 'svn-log-edit-svn-log)
  3393. (define-key svn-log-edit-mode-map (kbd "C-c C-?") 'svn-log-edit-show-files-to-commit)
  3394. (define-key svn-log-edit-mode-map (kbd "C-c C-z") 'svn-log-edit-erase-edit-buffer)
  3395. (define-key svn-log-edit-mode-map (kbd "C-c C-q") 'svn-log-edit-abort))
  3396. (easy-menu-define svn-log-edit-mode-menu svn-log-edit-mode-map
  3397. "'svn-log-edit-mode' menu"
  3398. '("SVN-Log"
  3399. ["Save to disk" svn-log-edit-save-message t]
  3400. ["Commit" svn-log-edit-done t]
  3401. ["Show Diff" svn-log-edit-svn-diff t]
  3402. ["Show Status" svn-log-edit-svn-status t]
  3403. ["Show Log" svn-log-edit-svn-log t]
  3404. ["Show files to commit" svn-log-edit-show-files-to-commit t]
  3405. ["Erase buffer" svn-log-edit-erase-edit-buffer]
  3406. ["Abort" svn-log-edit-abort t]))
  3407. (put 'svn-log-edit-mode-menu 'risky-local-variable t)
  3408. (defun svn-log-edit-abort ()
  3409. (interactive)
  3410. (bury-buffer)
  3411. (set-window-configuration svn-status-pre-commit-window-configuration))
  3412. (defun svn-log-edit-done ()
  3413. (interactive)
  3414. (svn-status-save-some-buffers)
  3415. (save-excursion
  3416. (set-buffer (get-buffer "*svn-log-edit*"))
  3417. (when svn-log-edit-insert-files-to-commit
  3418. (svn-log-edit-remove-comment-lines))
  3419. (when (fboundp 'set-buffer-file-coding-system)
  3420. (set-buffer-file-coding-system 'undecided-unix nil))
  3421. (when (or svn-log-edit-update-log-entry svn-status-files-to-commit)
  3422. (setq svn-status-temp-file-to-remove
  3423. (concat svn-status-temp-dir "svn-log-edit.txt" svn-temp-suffix))
  3424. (write-region (point-min) (point-max) svn-status-temp-file-to-remove nil 1))
  3425. (bury-buffer))
  3426. (if svn-log-edit-update-log-entry
  3427. (when (y-or-n-p "Update the log entry? ")
  3428. ;; svn propset svn:log --revprop -r11672 -F file
  3429. (svn-run nil t 'propset "propset" "svn:log" "--revprop"
  3430. (concat "-r" svn-log-edit-update-log-entry)
  3431. "-F" svn-status-temp-file-to-remove)
  3432. (save-excursion
  3433. (set-buffer "*svn-process*")
  3434. (message "%s" (buffer-substring (point-min) (- (point-max) 1)))))
  3435. (when svn-status-files-to-commit ; there are files to commit
  3436. (setq svn-status-operated-on-dot
  3437. (and (= 1 (length svn-status-files-to-commit))
  3438. (string= "." (svn-status-line-info->filename (car svn-status-files-to-commit)))))
  3439. (svn-status-create-arg-file svn-status-temp-arg-file ""
  3440. svn-status-files-to-commit "")
  3441. (svn-run t t 'commit "commit"
  3442. (unless svn-status-recursive-commit "--non-recursive")
  3443. "--targets" svn-status-temp-arg-file
  3444. "-F" svn-status-temp-file-to-remove
  3445. svn-status-default-commit-arguments))
  3446. (set-window-configuration svn-status-pre-commit-window-configuration)
  3447. (message "svn-log editing done")))
  3448. (defun svn-log-edit-svn-diff (arg)
  3449. "Show the diff we are about to commit.
  3450. If ARG then show diff between some other version of the selected files."
  3451. (interactive "P")
  3452. (set-buffer svn-status-buffer-name) ; TODO: is this necessary?
  3453. ;; This call is very much like `svn-status-show-svn-diff-for-marked-files'
  3454. ;; but uses commit-specific variables instead of the current marks.
  3455. (svn-status-show-svn-diff-internal svn-status-files-to-commit
  3456. svn-status-recursive-commit
  3457. (if arg :ask "BASE")))
  3458. (defun svn-log-edit-svn-log (arg)
  3459. (interactive "P")
  3460. (set-buffer svn-status-buffer-name)
  3461. (svn-status-show-svn-log arg))
  3462. (defun svn-log-edit-svn-status ()
  3463. (interactive)
  3464. (pop-to-buffer svn-status-buffer-name)
  3465. (other-window 1))
  3466. (defun svn-log-edit-files-to-commit ()
  3467. (mapcar 'svn-status-line-info->filename svn-status-files-to-commit))
  3468. (defun svn-log-edit-show-files-to-commit ()
  3469. (interactive)
  3470. (message "Files to commit%s: %S"
  3471. (if svn-status-recursive-commit " recursively" "")
  3472. (svn-log-edit-files-to-commit)))
  3473. (defun svn-log-edit-save-message ()
  3474. "Save the current log message to the file `svn-log-edit-file-name'."
  3475. (interactive)
  3476. (write-region (point-min) (point-max) svn-log-edit-file-name))
  3477. (defun svn-log-edit-erase-edit-buffer ()
  3478. "Delete everything in the *svn-log-edit* buffer."
  3479. (interactive)
  3480. (set-buffer "*svn-log-edit*")
  3481. (erase-buffer))
  3482. (defun svn-log-edit-insert-files-to-commit ()
  3483. (interactive)
  3484. (svn-log-edit-remove-comment-lines)
  3485. (let ((buf-size (- (point-max) (point-min))))
  3486. (save-excursion
  3487. (goto-char (point-min))
  3488. (insert "## Lines starting with '## ' will be removed from the log message.\n")
  3489. (insert "## File(s) to commit"
  3490. (if svn-status-recursive-commit " recursively" "") ":\n")
  3491. (let ((file-list svn-status-files-to-commit))
  3492. (while file-list
  3493. (insert (concat "## " (svn-status-line-info->filename (car file-list)) "\n"))
  3494. (setq file-list (cdr file-list)))))
  3495. (when (= 0 buf-size)
  3496. (goto-char (point-max)))))
  3497. (defun svn-log-edit-remove-comment-lines ()
  3498. (interactive)
  3499. (save-excursion
  3500. (goto-char (point-min))
  3501. (flush-lines "^## .*")))
  3502. ;; --------------------------------------------------------------------------------
  3503. ;; svn-log-view-mode:
  3504. ;; --------------------------------------------------------------------------------
  3505. (defvar svn-log-view-mode-map () "Keymap used in `svn-log-view-mode' buffers.")
  3506. (put 'svn-log-view-mode-map 'risky-local-variable t) ;for Emacs 20.7
  3507. (when (not svn-log-view-mode-map)
  3508. (setq svn-log-view-mode-map (make-sparse-keymap))
  3509. (suppress-keymap svn-log-view-mode-map)
  3510. (define-key svn-log-view-mode-map (kbd "p") 'svn-log-view-prev)
  3511. (define-key svn-log-view-mode-map (kbd "n") 'svn-log-view-next)
  3512. (define-key svn-log-view-mode-map (kbd "=") 'svn-log-view-diff)
  3513. (define-key svn-log-view-mode-map (kbd "e") 'svn-log-edit-log-entry)
  3514. (define-key svn-log-view-mode-map (kbd "q") 'bury-buffer))
  3515. (defvar svn-log-view-popup-menu-map ()
  3516. "Keymap used to show popup menu in `svn-log-view-mode' buffers.")
  3517. (put 'svn-log-view-popup-menu-map 'risky-local-variable t) ;for Emacs 20.7
  3518. (when (not svn-log-view-popup-menu-map)
  3519. (setq svn-log-view-popup-menu-map (make-sparse-keymap))
  3520. (suppress-keymap svn-log-view-popup-menu-map)
  3521. (define-key svn-log-view-popup-menu-map [down-mouse-3] 'svn-log-view-popup-menu))
  3522. (easy-menu-define svn-log-view-mode-menu svn-log-view-mode-map
  3523. "'svn-log-view-mode' menu"
  3524. '("SVN-LogView"
  3525. ["Show Changeset" svn-log-view-diff t]
  3526. ["Edit log message" svn-log-edit-log-entry t]))
  3527. (defun svn-log-view-popup-menu (event)
  3528. (interactive "e")
  3529. (mouse-set-point event)
  3530. (let* ((rev (svn-log-revision-at-point)))
  3531. (when rev
  3532. (svn-status-face-set-temporary-during-popup
  3533. 'svn-status-marked-popup-face (svn-point-at-bol) (svn-point-at-eol)
  3534. svn-log-view-mode-menu))))
  3535. (defvar svn-log-view-font-lock-keywords
  3536. '(("^r[0-9]+ .+" (0 `(face
  3537. font-lock-keyword-face
  3538. mouse-face
  3539. highlight
  3540. keymap ,svn-log-view-popup-menu-map))))
  3541. "Keywords in svn-log-view-mode.")
  3542. (put 'svn-log-view-font-lock-keywords 'risky-local-variable t) ;for Emacs 20.7
  3543. (define-derived-mode svn-log-view-mode fundamental-mode "svn-log-view"
  3544. "Major Mode to show the output from svn log.
  3545. Commands:
  3546. \\{svn-log-view-mode-map}
  3547. "
  3548. (use-local-map svn-log-view-mode-map)
  3549. (easy-menu-add svn-log-view-mode-menu)
  3550. (set (make-local-variable 'font-lock-defaults) '(svn-log-view-font-lock-keywords t)))
  3551. (defun svn-log-view-next ()
  3552. (interactive)
  3553. (when (re-search-forward "^r[0-9]+" nil t)
  3554. (beginning-of-line 3)))
  3555. (defun svn-log-view-prev ()
  3556. (interactive)
  3557. (when (re-search-backward "^r[0-9]+" nil t 2)
  3558. (beginning-of-line 3)))
  3559. (defun svn-log-revision-at-point ()
  3560. (save-excursion
  3561. (re-search-backward "^r\\([0-9]+\\)")
  3562. (svn-match-string-no-properties 1)))
  3563. (defun svn-log-view-diff (arg)
  3564. "Show the changeset for a given log entry.
  3565. When called with a prefix argument, ask the user for the revision."
  3566. (interactive "P")
  3567. (let* ((upper-rev (svn-log-revision-at-point))
  3568. (lower-rev (number-to-string (- (string-to-number upper-rev) 1)))
  3569. (rev-arg (concat lower-rev ":" upper-rev)))
  3570. (when arg
  3571. (setq rev-arg (read-string "Revision for changeset: " rev-arg)))
  3572. (svn-run nil t 'diff "diff" (concat "-r" rev-arg))
  3573. (svn-status-activate-diff-mode)))
  3574. (defun svn-log-edit-log-entry ()
  3575. "Edit the given log entry."
  3576. (interactive)
  3577. (let ((rev (svn-log-revision-at-point))
  3578. (log-message))
  3579. (svn-run nil t 'propget-parse "propget" "--revprop" (concat "-r" rev) "svn:log")
  3580. (save-excursion
  3581. (set-buffer "*svn-process*")
  3582. (setq log-message (if (> (point-max) 1)
  3583. (buffer-substring (point-min) (- (point-max) 1))
  3584. "")))
  3585. (svn-status-pop-to-commit-buffer)
  3586. ;; If the buffer has been narrowed, `svn-log-edit-done' will use
  3587. ;; only the accessible part. So we need not erase the rest here.
  3588. (delete-region (point-min) (point-max))
  3589. (insert log-message)
  3590. (goto-char (point-min))
  3591. (setq svn-log-edit-update-log-entry rev)))
  3592. ;; --------------------------------------------------------------------------------
  3593. ;; svn-info-mode
  3594. ;; --------------------------------------------------------------------------------
  3595. (defvar svn-info-mode-map () "Keymap used in `svn-info-mode' buffers.")
  3596. (put 'svn-info-mode-map 'risky-local-variable t) ;for Emacs 20.7
  3597. (when (not svn-info-mode-map)
  3598. (setq svn-info-mode-map (make-sparse-keymap))
  3599. (define-key svn-info-mode-map [?q] 'bury-buffer))
  3600. (defun svn-info-mode ()
  3601. "Major Mode to view informative output from svn."
  3602. (interactive)
  3603. (kill-all-local-variables)
  3604. (use-local-map svn-info-mode-map)
  3605. (setq major-mode 'svn-info-mode)
  3606. (setq mode-name "svn-info"))
  3607. ;; --------------------------------------------------------------------------------
  3608. ;; svn-process-mode
  3609. ;; --------------------------------------------------------------------------------
  3610. (defvar svn-process-mode-map () "Keymap used in `svn-process-mode' buffers.")
  3611. (put 'svn-process-mode-map 'risky-local-variable t) ;for Emacs 20.7
  3612. (when (not svn-process-mode-map)
  3613. (setq svn-process-mode-map (make-sparse-keymap))
  3614. (define-key svn-process-mode-map [?q] 'bury-buffer))
  3615. (defun svn-process-mode ()
  3616. "Major Mode to view process output from svn."
  3617. (interactive)
  3618. (kill-all-local-variables)
  3619. (use-local-map svn-process-mode-map)
  3620. (setq major-mode 'svn-process-mode)
  3621. (setq mode-name "svn-process"))
  3622. ;; --------------------------------------------------------------------------------
  3623. ;; svn status persistent options
  3624. ;; --------------------------------------------------------------------------------
  3625. (defun svn-status-base-dir (&optional start-directory)
  3626. "Find the svn root directory for the current working copy.
  3627. Return nil, if not in a svn working copy."
  3628. (let* ((base-dir (expand-file-name (or start-directory default-directory)))
  3629. (dot-svn-dir (concat base-dir (svn-wc-adm-dir-name)))
  3630. (in-tree (file-exists-p dot-svn-dir))
  3631. (dir-below (expand-file-name default-directory)))
  3632. (while (when (and dir-below (file-exists-p dot-svn-dir))
  3633. (setq base-dir (file-name-directory dot-svn-dir))
  3634. (string-match "\\(.+/\\).+/" dir-below)
  3635. (setq dir-below
  3636. (and (string-match "\(.*/\)[^/]+/" dir-below)
  3637. (match-string 1 dir-below)))
  3638. (setq dot-svn-dir (concat dir-below (svn-wc-adm-dir-name)))))
  3639. (and in-tree base-dir)))
  3640. (defun svn-status-save-state ()
  3641. "Save psvn persistent options for this working copy to a file."
  3642. (interactive)
  3643. (let ((buf (find-file (concat (svn-status-base-dir) "++psvn.state"))))
  3644. (erase-buffer) ;Widen, because we'll save the whole buffer.
  3645. (setq svn-status-options
  3646. (list
  3647. (list "svn-trac-project-root" svn-trac-project-root)
  3648. (list "sort-status-buffer" svn-status-sort-status-buffer)
  3649. (list "elide-list" svn-status-elided-list)
  3650. (list "module-name" svn-status-module-name)))
  3651. (insert (pp-to-string svn-status-options))
  3652. (save-buffer)
  3653. (kill-buffer buf)))
  3654. (defun svn-status-load-state (&optional no-error)
  3655. "Load psvn persistent options for this working copy from a file."
  3656. (interactive)
  3657. (let ((file (concat (svn-status-base-dir) "++psvn.state")))
  3658. (if (file-readable-p file)
  3659. (with-temp-buffer
  3660. (insert-file-contents file)
  3661. (setq svn-status-options (read (current-buffer)))
  3662. (setq svn-status-sort-status-buffer
  3663. (nth 1 (assoc "sort-status-buffer" svn-status-options)))
  3664. (setq svn-trac-project-root
  3665. (nth 1 (assoc "svn-trac-project-root" svn-status-options)))
  3666. (setq svn-status-elided-list
  3667. (nth 1 (assoc "elide-list" svn-status-options)))
  3668. (setq svn-status-module-name
  3669. (nth 1 (assoc "module-name" svn-status-options)))
  3670. (when (and (interactive-p) svn-status-elided-list (svn-status-apply-elide-list)))
  3671. (message "psvn.el: loaded %s" file))
  3672. (unless no-error (error "psvn.el: %s is not readable." file)))))
  3673. (defun svn-status-toggle-sort-status-buffer ()
  3674. "Toggle sorting of the *svn-status* buffer.
  3675. If you turn off sorting, you can speed up \[svn-status]. However,
  3676. the buffer is not correctly sorted then. This function will be
  3677. removed again, when a faster parsing and display routine for
  3678. `svn-status' is available."
  3679. (interactive)
  3680. (setq svn-status-sort-status-buffer (not svn-status-sort-status-buffer))
  3681. (message "The %s buffer will %sbe sorted." svn-status-buffer-name
  3682. (if svn-status-sort-status-buffer "" "not ")))
  3683. (defun svn-status-toggle-display-full-path ()
  3684. "Toggle displaying the full path in the `svn-status-buffer-name' buffer"
  3685. (interactive)
  3686. (setq svn-status-display-full-path (not svn-status-display-full-path))
  3687. (message "The %s buffer will%s use full path names." svn-status-buffer-name
  3688. (if svn-status-display-full-path "" " not"))
  3689. (svn-status-update))
  3690. (defun svn-status-set-trac-project-root ()
  3691. (interactive)
  3692. (setq svn-trac-project-root
  3693. (read-string "Trac project root (e.g.: http://projects.edgewall.com/trac/): "
  3694. svn-trac-project-root))
  3695. (when (yes-or-no-p "Save the new setting for svn-trac-project-root to disk? ")
  3696. (svn-status-save-state)))
  3697. (defun svn-status-set-module-name ()
  3698. "Interactively set svn-status-module-name."
  3699. (interactive)
  3700. (setq svn-status-module-name
  3701. (read-string "Short Unit Name (e.g.: MyProject): "
  3702. svn-status-module-name))
  3703. (when (yes-or-no-p "Save the new setting for svn-status-module-name to disk? ")
  3704. (svn-status-save-state)))
  3705. (defun svn-browse-url (url)
  3706. "Call `browse-url', using `svn-browse-url-function'."
  3707. (let ((browse-url-browser-function (or svn-browse-url-function
  3708. browse-url-browser-function)))
  3709. (browse-url url)))
  3710. ;; --------------------------------------------------------------------------------
  3711. ;; svn status trac integration
  3712. ;; --------------------------------------------------------------------------------
  3713. (defun svn-trac-browse-timeline ()
  3714. "Open the trac timeline view for the current svn repository."
  3715. (interactive)
  3716. (unless svn-trac-project-root
  3717. (svn-status-set-trac-project-root))
  3718. (svn-browse-url (concat svn-trac-project-root "timeline")))
  3719. (defun svn-trac-browse-changeset (changeset-nr)
  3720. "Show a changeset in the trac issue tracker."
  3721. (interactive (list (read-number "Browse changeset number: " (number-at-point))))
  3722. (unless svn-trac-project-root
  3723. (svn-status-set-trac-project-root))
  3724. (svn-browse-url (concat svn-trac-project-root "changeset/" (number-to-string changeset-nr))))
  3725. (defun svn-trac-browse-ticket (ticket-nr)
  3726. "Show a ticket in the trac issue tracker."
  3727. (interactive (list (read-number "Browse ticket number: " (number-at-point))))
  3728. (unless svn-trac-project-root
  3729. (svn-status-set-trac-project-root))
  3730. (svn-browse-url (concat svn-trac-project-root "ticket/" (number-to-string ticket-nr))))
  3731. ;;;------------------------------------------------------------
  3732. ;;; resolve conflicts using ediff
  3733. ;;;------------------------------------------------------------
  3734. (defun svn-resolve-conflicts-ediff (&optional name-A name-B)
  3735. "Invoke ediff to resolve conflicts in the current buffer.
  3736. The conflicts must be marked with rcsmerge conflict markers."
  3737. (interactive)
  3738. (let* ((found nil)
  3739. (file-name (file-name-nondirectory buffer-file-name))
  3740. (your-buffer (generate-new-buffer
  3741. (concat "*" file-name
  3742. " " (or name-A "WORKFILE") "*")))
  3743. (other-buffer (generate-new-buffer
  3744. (concat "*" file-name
  3745. " " (or name-B "CHECKED-IN") "*")))
  3746. (result-buffer (current-buffer)))
  3747. (save-excursion
  3748. (set-buffer your-buffer)
  3749. (erase-buffer)
  3750. (insert-buffer-substring result-buffer)
  3751. (goto-char (point-min))
  3752. (while (re-search-forward "^<<<<<<< .mine\n" nil t)
  3753. (setq found t)
  3754. (replace-match "")
  3755. (if (not (re-search-forward "^=======\n" nil t))
  3756. (error "Malformed conflict marker"))
  3757. (replace-match "")
  3758. (let ((start (point)))
  3759. (if (not (re-search-forward "^>>>>>>> .r[0-9]+\n" nil t))
  3760. (error "Malformed conflict marker"))
  3761. (delete-region start (point))))
  3762. (if (not found)
  3763. (progn
  3764. (kill-buffer your-buffer)
  3765. (kill-buffer other-buffer)
  3766. (error "No conflict markers found")))
  3767. (set-buffer other-buffer)
  3768. (erase-buffer)
  3769. (insert-buffer-substring result-buffer)
  3770. (goto-char (point-min))
  3771. (while (re-search-forward "^<<<<<<< .mine\n" nil t)
  3772. (let ((start (match-beginning 0)))
  3773. (if (not (re-search-forward "^=======\n" nil t))
  3774. (error "Malformed conflict marker"))
  3775. (delete-region start (point))
  3776. (if (not (re-search-forward "^>>>>>>> .r[0-9]+\n" nil t))
  3777. (error "Malformed conflict marker"))
  3778. (replace-match "")))
  3779. (let ((config (current-window-configuration))
  3780. (ediff-default-variant 'default-B))
  3781. ;; Fire up ediff.
  3782. (set-buffer (ediff-merge-buffers your-buffer other-buffer))
  3783. ;; Ediff is now set up, and we are in the control buffer.
  3784. ;; Do a few further adjustments and take precautions for exit.
  3785. (make-local-variable 'svn-ediff-windows)
  3786. (setq svn-ediff-windows config)
  3787. (make-local-variable 'svn-ediff-result)
  3788. (setq svn-ediff-result result-buffer)
  3789. (make-local-variable 'ediff-quit-hook)
  3790. (setq ediff-quit-hook
  3791. (lambda ()
  3792. (let ((buffer-A ediff-buffer-A)
  3793. (buffer-B ediff-buffer-B)
  3794. (buffer-C ediff-buffer-C)
  3795. (result svn-ediff-result)
  3796. (windows svn-ediff-windows))
  3797. (ediff-cleanup-mess)
  3798. (set-buffer result)
  3799. (erase-buffer)
  3800. (insert-buffer-substring buffer-C)
  3801. (kill-buffer buffer-A)
  3802. (kill-buffer buffer-B)
  3803. (kill-buffer buffer-C)
  3804. (set-window-configuration windows)
  3805. (message "Conflict resolution finished; you may save the buffer"))))
  3806. (message "Please resolve conflicts now; exit ediff when done")
  3807. nil))))
  3808. (defun svn-resolve-conflicts (filename)
  3809. (let ((buff (find-file-noselect filename)))
  3810. (if buff
  3811. (progn (switch-to-buffer buff)
  3812. (svn-resolve-conflicts-ediff))
  3813. (error "can not open file %s" filename))))
  3814. (defun svn-status-resolve-conflicts ()
  3815. "Resolve conflict in the selected file"
  3816. (interactive)
  3817. (let ((file-info (svn-status-get-line-information)))
  3818. (or (and file-info
  3819. (= ?C (svn-status-line-info->filemark file-info))
  3820. (svn-resolve-conflicts
  3821. (svn-status-line-info->full-path file-info)))
  3822. (error "can not resolve conflicts at this point"))))
  3823. ;; --------------------------------------------------------------------------------
  3824. ;; svn status profiling
  3825. ;; --------------------------------------------------------------------------------
  3826. ;;; Note about profiling psvn:
  3827. ;; (load-library "elp")
  3828. ;; M-x elp-reset-all
  3829. ;; (elp-instrument-package "svn-")
  3830. ;; M-x svn-status
  3831. ;; M-x elp-results
  3832. (defun svn-status-elp-init ()
  3833. (interactive)
  3834. (require 'elp)
  3835. (elp-reset-all)
  3836. (elp-instrument-package "svn-")
  3837. (message "Run the desired svn command (e.g. M-x svn-status), then use M-x elp-results."))
  3838. (provide 'psvn)
  3839. ;; Local Variables:
  3840. ;; indent-tabs-mode: nil
  3841. ;; End:
  3842. ;;; psvn.el ends here