From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: file-name-shadow-mode Date: Wed, 23 Mar 2005 17:55:28 -0500 Message-ID: References: <200503180435.j2I4Z2R18621@raven.dms.auburn.edu> <87is3p5zp2.fsf-monnier+emacs@gnu.org> <200503191521.j2JFL8901509@raven.dms.auburn.edu> <87r7ibziw6.fsf-monnier+emacs@gnu.org> <200503200230.j2K2UvS03067@raven.dms.auburn.edu> <87is3lw2yk.fsf-monnier+emacs@gnu.org> NNTP-Posting-Host: main.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: sea.gmane.org 1111618903 17889 80.91.229.2 (23 Mar 2005 23:01:43 GMT) X-Complaints-To: usenet@sea.gmane.org NNTP-Posting-Date: Wed, 23 Mar 2005 23:01:43 +0000 (UTC) Cc: emacs-devel@gnu.org, snogglethorpe@gmail.com, teirllm@dms.auburn.edu, miles@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Thu Mar 24 00:01:41 2005 Original-Received: from lists.gnu.org ([199.232.76.165]) by ciao.gmane.org with esmtp (Exim 4.43) id 1DEEqu-0000pB-AZ for ged-emacs-devel@m.gmane.org; Thu, 24 Mar 2005 00:01:28 +0100 Original-Received: from localhost ([127.0.0.1] helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DEF8U-0000Ui-BL for ged-emacs-devel@m.gmane.org; Wed, 23 Mar 2005 18:19:38 -0500 Original-Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1DEF4V-0007RM-IU for emacs-devel@gnu.org; Wed, 23 Mar 2005 18:15:31 -0500 Original-Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1DEF4J-0007K9-4k for emacs-devel@gnu.org; Wed, 23 Mar 2005 18:15:19 -0500 Original-Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1DEF4I-0007Ij-QK for emacs-devel@gnu.org; Wed, 23 Mar 2005 18:15:18 -0500 Original-Received: from [132.204.24.67] (helo=mercure.iro.umontreal.ca) by monty-python.gnu.org with esmtp (Exim 4.34) id 1DEElB-0005lO-GJ; Wed, 23 Mar 2005 17:55:33 -0500 Original-Received: from hidalgo.iro.umontreal.ca (hidalgo.iro.umontreal.ca [132.204.27.50]) by mercure.iro.umontreal.ca (Postfix) with ESMTP id D6246340019; Wed, 23 Mar 2005 17:55:32 -0500 (EST) Original-Received: from asado.iro.umontreal.ca (asado.iro.umontreal.ca [132.204.24.84]) by hidalgo.iro.umontreal.ca (Postfix) with ESMTP id 5FE5E2CC025; Wed, 23 Mar 2005 17:55:28 -0500 (EST) Original-Received: by asado.iro.umontreal.ca (Postfix, from userid 20848) id 3A35E156065; Wed, 23 Mar 2005 17:55:28 -0500 (EST) Original-To: rms@gnu.org In-Reply-To: <87is3lw2yk.fsf-monnier+emacs@gnu.org> (Stefan Monnier's message of "Mon, 21 Mar 2005 08:24:38 -0500") User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) X-DIRO-MailScanner-Information: Please contact the ISP for more information X-DIRO-MailScanner: Found to be clean X-DIRO-MailScanner-SpamCheck: n'est pas un polluriel, SpamAssassin (score=-4.825, requis 5, autolearn=not spam, AWL 0.07, BAYES_00 -4.90) X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org X-MailScanner-To: ged-emacs-devel@m.gmane.org Xref: news.gmane.org gmane.emacs.devel:35070 X-Report-Spam: http://spam.gmane.org/gmane.emacs.devel:35070 > How 'bout the patch below which makes no assumption (that I know of) about > substitute-in-file-name, and will thus work correctly even with weird > magic file name handlers. Regarding performance of my code: I just bumped into a performance problem. The problem is that substitute-in-file-name can take a non-negligible amount of time to execute when there's a "~user" in the file name, because it calls getpwnam to figure out whether "user" actually exists or not. At least here with 8K users in our YP database, my code causes file-name-shadow-mode to take around 0.5-1s to refresh the screen after each key stroke if there's a ~user in the file name I'm editing. So I've tweaked my code to streamline the common case where the shadow doesn't need to be moved. I also fixed the problem where a file name like "/home/foo/bar/:toto//tata" was sometimes shadowed as "r/:toto//tata" instead of just "/tata". Stefan --- orig/lisp/rfn-eshadow.el +++ mod/lisp/rfn-eshadow.el @@ -97,7 +97,7 @@ '(face file-name-shadow field shadow) "Properties given to the `shadowed' part of a filename in the minibuffer. Only used when `file-name-shadow-mode' is active. -If emacs is not running under a window system, +If Emacs is not running under a window system, `file-name-shadow-tty-properties' is used instead." :type file-name-shadow-properties-custom-type :group 'minibuffer) @@ -123,20 +123,6 @@ ;;; Internal variables -;; Regexp to locate dividing point between shadow and real pathname -(defconst rfn-eshadow-regexp - (cond ((memq system-type '(ms-dos windows-nt)) - ;; This horrible regexp considers the following patterns as - ;; starting an absolute pathname, when following a `/' or an `\': - ;; L: / // ~ $ \\ \\\\ - "\\(.*[^/]+/+?\\|/*?\\|\\)\\(~\\|$[^$]\\|$\\'\\|[][\\^a-z]:\\|//?\\([^][\\^a-z/$~]\\|[^/$~][^:]\\|[^/$~]?\\'\\)\\)") - (t - ;; default is for unix-style filenames - "\\(.*/\\)\\([/~]\\|$[^$]\\|$\\'\\)")) - "Regular expression used to match shadowed filenames. -There should be at least one regexp group; the end of the first one -is used as the end of the shadowed portion of the filename.") - ;; A list of minibuffers to which we've added a post-command-hook. (defvar rfn-eshadow-frobbed-minibufs nil) @@ -170,31 +156,54 @@ (add-to-list 'rfn-eshadow-frobbed-minibufs (current-buffer)) (add-hook 'post-command-hook #'rfn-eshadow-update-overlay nil t))) +(defsubst rfn-eshadow-sifn-equal (goal pos) + (equal goal (buffer-substring-no-properties pos (point-max)))) + ;; post-command-hook to update overlay (defun rfn-eshadow-update-overlay () "Update `rfn-eshadow-overlay' to cover shadowed part of minibuffer input. This is intended to be used as a minibuffer post-command-hook for `file-name-shadow-mode'; the minibuffer should have already been set up by `rfn-eshadow-setup-minibuffer'." - ;; This is not really a correct implementation; it won't always do the - ;; right thing in the presence of environment variables that - ;; substitute-in-file-name would expand; currently it just assumes any - ;; environment variable contains an absolute filename. - (save-excursion - (let ((inhibit-point-motion-hooks t)) - (goto-char (minibuffer-prompt-end)) - ;; Update the overlay (which will evaporate if it's empty). - (move-overlay rfn-eshadow-overlay - (point) - (if (looking-at rfn-eshadow-regexp) - (match-end 1) - (point)))))) + ;; This code usually is instantaneous, but if the file name includes + ;; a "~", substitute-in-file-name will lookup your system's list of + ;; users to see whether "" is an actual user or not, and that + ;; can sometimes take a while, so we wrap this in `while-no-input'. + (while-no-input + (condition-case nil + (let ((goal (substitute-in-file-name (minibuffer-contents))) + (mid (overlay-end rfn-eshadow-overlay)) + (start (minibuffer-prompt-end)) + (end (point-max))) + (unless + ;; Catch the common case where the shadow does not need to move. + (and mid + (or (eq mid end) + (not (rfn-eshadow-sifn-equal goal (1+ mid)))) + (or (eq mid start) + (rfn-eshadow-sifn-equal goal mid))) + ;; Binary search for the greatest position still equivalent to + ;; the whole. + (while (or (< (1+ start) end) + (if (and (< (1+ end) (point-max)) + (rfn-eshadow-sifn-equal goal (1+ end))) + ;; (SIFN end) != goal, but (SIFN (1+end)) == goal, + ;; We've reached a discontinuity: this can happen + ;; e.g. if `end' point to "/:...". + (setq start (1+ end) end (point-max)))) + (setq mid (/ (+ start end) 2)) + (if (equal (condition-case nil + (rfn-eshadow-sifn-equal goal mid) + (error nil)) + goal) + (setq start mid) + (setq end mid))) + (move-overlay rfn-eshadow-overlay (minibuffer-prompt-end) start))) + ;; `substitute-in-file-name' can fail on partial input. + ;; (error nil) + ))) -;;; Note this definition must be at the end of the file, because -;;; `define-minor-mode' actually calls the mode-function if the -;;; associated variable is non-nil, which requires that all needed -;;; functions be already defined. [This is arguably a bug in d-m-m] ;;;###autoload (define-minor-mode file-name-shadow-mode "Toggle File-Name Shadow mode. @@ -222,5 +231,5 @@ (provide 'rfn-eshadow) -;;; arch-tag: dcf70a52-0115-4ec2-b1e3-4f8d3541a888 +;; arch-tag: dcf70a52-0115-4ec2-b1e3-4f8d3541a888 ;;; rfn-eshadow.el ends here