From 4fb25acadedc81a6d654bed89e816906aff07178 Mon Sep 17 00:00:00 2001 From: Wolfgang Scherer Date: Thu, 29 Aug 2019 17:49:54 +0200 Subject: [PATCH] Provide vc-hg-ignore to make vc-ignore work correctly * lisp/vc/vc-hg.el: (vc-hg-ignore) Ignore file of directory. Add filepath relative to directory of Mercurial .hgignore file. The filepath is quoted according to the active ignore syntax (Bug#37189). (vc-hg--py-regexp-quote) Quote string as regexp to match exactly string. --- lisp/vc/vc-hg.el | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el index f287adf..9cbd9d4 100644 --- a/lisp/vc/vc-hg.el +++ b/lisp/vc/vc-hg.el @@ -1153,6 +1153,50 @@ REV is ignored." (expand-file-name ".hgignore" (vc-hg-root file))) +(defvar vc-hg-ignore-detect-wildcard "[*^$]" + "Regular expresssion to detect wildcards in an ignored file + specification.") + +(defun vc-hg-ignore (file &optional directory remove) + "Ignore FILE of DIRECTORY (default is `default-directory'). +If FILE matches the regular expression +`vc-hg-ignore-detect-wildcard', it is appended to .hgignore +unmodified. +Otherwise, FILE is either relative to DIRECTORY or absolute. FILE +is converted to a path relative to the project root of DIRECTORY. +It is then further escaped/expanded according to the active +syntax in .hgignore. If the syntax is `regexp', FILE is quoted +as anchored literal Python regexp and if FILE is a directory, the +trailing `$' is omitted. Otherwise, if the syntax is `glob', +FILE is used unquoted and if FILE is a directory, a `*' is +appended. +If REMOVE is non-nil, remove the pattern derived from FILE from +ignored files." + (let ((ignore (vc-hg-find-ignore-file (or directory default-directory))) + (pattern file) + root-dir file-path syntax) + (unless (string-match vc-hg-ignore-detect-wildcard pattern) + (setq file-path (expand-file-name file directory)) + (setq root-dir (file-name-directory ignore)) + (when (not (string= (substring file-path 0 (length root-dir)) root-dir)) + (error "Ignore spec %s is not below project root %s" file-path root-dir)) + (setq pattern (substring file-path (length root-dir))) + (save-match-data + (with-current-buffer (find-file-noselect ignore) + (goto-char (point-max)) + (setq syntax + (if (re-search-backward "^ *syntax: *\\(regexp\\|glob\\)$" nil t) + (match-string 1) + "regexp"))) + (setq pattern + (if (string= syntax "regexp") + (concat "^" (vc-hg--py-regexp-quote pattern) + (and (not (file-directory-p file-path)) "$")) + (concat pattern (and (file-directory-p file-path) "*")))))) + (if remove + (vc--remove-regexp (concat "^" (regexp-quote pattern ) "\\(\n\\|$\\)") ignore) + (vc--add-line pattern ignore)))) + ;; Modeled after the similar function in vc-bzr.el (defun vc-hg-checkout (file &optional rev) "Retrieve a revision of FILE. @@ -1451,6 +1495,24 @@ This function differs from vc-do-command in that it invokes (defun vc-hg-root (file) (vc-find-root file ".hg")) +(defvar vc-hg--py-regexp-special-chars + (mapcar + (function + (lambda (_c) + (cons _c (concat "\\" (char-to-string _c))))) + (append "()[]{}?*+-|^$\\.&~# \t\n\r\v\f" nil)) + "Characters that have special meaning in Python regular expressions.") + +(defun vc-hg--py-regexp-quote (string) + "Return a Python regexp string which matches exactly STRING and nothing else. +Ported from Python v3.7" + (mapconcat + (function + (lambda (_c) + (or (cdr (assq _c vc-hg--py-regexp-special-chars)) + (char-to-string _c)))) + string "")) + (provide 'vc-hg) ;;; vc-hg.el ends here -- 2.7.4