emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/hyperbole 1c222405e5 3/4: Fix and improve many issues w


From: ELPA Syncer
Subject: [elpa] externals/hyperbole 1c222405e5 3/4: Fix and improve many issues with path link and argument handling
Date: Sat, 1 Jan 2022 03:57:33 -0500 (EST)

branch: externals/hyperbole
commit 1c222405e54a57605ec1440f9639a2677c35a177
Author: Robert Weiner <rsw@gnu.org>
Commit: Robert Weiner <rsw@gnu.org>

    Fix and improve many issues with path link and argument handling
---
 ChangeLog      |  42 +++++-
 hactypes.el    |  21 +--
 hargs.el       |  30 ++--
 hload-path.el  |   7 +
 hmouse-info.el |   3 +-
 hpath.el       | 454 ++++++++++++++++++++++++++++++++++-----------------------
 hui.el         |   2 +-
 7 files changed, 350 insertions(+), 209 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4a6a975cf4..27119e84a2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2021-12-31  Bob Weiner  <rsw@gnu.org>
+
+* hui.el (hui:gbut-modify): Fix 'src-dir' to be dir of 'gbut:file' not 
default-directory.
+
+* hargs.el (hargs:defaults): Defined this variable.
+  hactypes.el (exec-shell-command, exec-window-command, link-to-file, 
link-to-ibut):
+    Change 'defaults' to 'hargs:defaults' and make that a global variable.
+
 * hyrolo.el (hyrolo-map-level-1): Fix sorting bug by adding 
outline-hide-subtree when
     on last buffer entry so its contents are kept together during hyrolo-sort.
 
@@ -8,6 +16,36 @@
     Add call to hpath:mswindows-to-posix or under WSL, absolute prefix may not 
match,
     e.g. one path starts with '/mnt/c' and another with '/c'.
 
+* hpath.el (hpath:remote-regexp, hpath:url-hostnames-regexp, hpath:remote-at-p,
+            hpath:remote-p, substitute-in-file-name, hpath:is-p):
+    Add sftp support.
+
+* hpath.el (hpath:call): Add 3rd arg non-exist to allow for return of 
non-existent
+    pathnames.
+
+* hpath.el (hpath:find): Include full path with prefix modifier and # anchor 
in error
+    messages and handle "#Section" links in buffers without attached files.
+           (hpath:display-buffer-other-frame):
+           (hpath:display-buffer-alist): Update new-frame function to copy 
current
+    frame parameters and to allow isearch to turn off.
+           (hpath:to-markup-anchor): When searching for anchors, treat all caps
+    filenames without suffix like outlines, e.g. README, INSTALL.
+
+2021-12-30  Bob Weiner  <rsw@gnu.org>
+
+* hload-path.el: Add "{hyperb:dir}/test" subdir to load-path so can link to its
+    files without giving any path.
+
+* hpath.el (hpath:expand-with-variable): Fix to handle Lisp symbol 
auto-variable-alist
+    entries properly.  For example, Elisp file names were not being expanded 
with
+    the load-path variable.  Also, don't expand URLs.
+        (hpath:expand): Fix to expand path only when not already absolute and 
a variable
+    matching the path suffix is found.  Any variable added is resolved only if 
the path
+    then points to an existing, readable file.
+        (hpath:absolute-to, hpath:call): Call hpath:expand to ensure 
hpath:auto-variable-alist
+    variables are utilized for absolute expansions.
+        (hpath:find): Add loose test that hpath:display-path-function 
successfully displayed link in a buffer.
+
 2021-12-26  Bob Weiner  <rsw@gnu.org>
 
 * kotl/kotl-mode.el (kotl-mode:exchange-cells): Signal error if invalid type 
or value
@@ -89,8 +127,8 @@
 * hargs.el (hargs:actype-get): Change to set 'modifying' to t if non-nil
     for lower-level function call conformance.
            (hargs:iform-read): Change 'modifying' param to 'defaults'.
-    If it is t, then get current Hyperbole button is being modified,
-    get defaults from it, otherwise, use the value as the defaults
+    If it is t, then current Hyperbole button is being modified,
+    get defaults from it; otherwise, use the value as a list of defaults
     when prompting for arguments.  Eliminate use of hargs:defaults
     dynamic variable.
 
diff --git a/hactypes.el b/hactypes.el
index 18a288eb9d..3a63afb727 100644
--- a/hactypes.el
+++ b/hactypes.el
@@ -126,9 +126,9 @@ Optional non-nil second argument INTERNAL-CMD inhibits 
display of the shell
 command line executed.  Optional non-nil third argument KILL-PREV means
 kill the last output to the shell buffer before executing SHELL-CMD."
   (interactive
-   (let ((default  (car defaults))
-        (default1 (nth 1 defaults))
-        (default2 (nth 2 defaults)))
+   (let ((default  (car hargs:defaults))
+        (default1 (nth 1 hargs:defaults))
+        (default2 (nth 2 hargs:defaults)))
      (list (hargs:read "Shell cmd: "
                       (lambda (cmd) (not (string-equal cmd "")))
                       default "Enter a shell command." 'string)
@@ -173,7 +173,7 @@ kill the last output to the shell buffer before executing 
SHELL-CMD."
 (defact exec-window-cmd (shell-cmd)
   "Asynchronously execute an external window-based SHELL-CMD string."
   (interactive
-   (let ((default  (car defaults)))
+   (let ((default  (car hargs:defaults)))
      (list (hargs:read "Shell cmd: "
                       (lambda (cmd) (not (string-equal cmd "")))
                       default "Enter a shell command." 'string))))
@@ -333,9 +333,12 @@ the window or as close as possible."
         (existing-buf t)
         path-buf)
      (unwind-protect
-        (let* ((default-directory (or (hattr:get 'hbut:current 'dir) 
default-directory))
-               (file-path (or (car defaults) default-directory))
-               (file-point (cadr defaults))
+        (let* ((default-directory (or (hattr:get 'hbut:current 'dir)
+                                      (file-name-directory
+                                       (or (hattr:get 'hbut:current 'loc) ""))
+                                      default-directory))
+               (file-path (or (car hargs:defaults) default-directory))
+               (file-point (cadr hargs:defaults))
                (hargs:reading-p 'file)
                ;; If reading interactive inputs from a key series
                ;; (puts key events into the unread queue), then don't
@@ -490,8 +493,8 @@ on the implicit button to which to link."
           ;; is in progress, so ignore this for now.  -- RSW, 01-25-2020
 
           ;; When not on an ibut and modifying the link, use existing arguments
-          ((and (bound-and-true-p defaults) (listp defaults) defaults)
-           defaults)
+          ((and (bound-and-true-p hargs:defaults) (listp hargs:defaults) 
hargs:defaults)
+           hargs:defaults)
           (t
            (hypb:error "(link-to-ibut): Point must be on an implicit button to 
create a link-to-ibut")))))
   (when (null key)
diff --git a/hargs.el b/hargs.el
index a0fb7792ff..12dbe163e8 100644
--- a/hargs.el
+++ b/hargs.el
@@ -1,4 +1,4 @@
-;;; hargs.el --- GNU Hyperbole user input functions
+;;; hargs.el --- GNU Hyperbole user input functions    -*- lexical-binding: t; 
-*-
 ;;
 ;; Author:       Bob Weiner
 ;;
@@ -33,6 +33,9 @@
 ;;; Public variables
 ;;; ************************************************************************
 
+(defvar hargs:defaults nil
+  "Default arguments read from an existing Hyperbole button when modifying 
it.")
+
 (defvar hargs:reading-p nil
   "Is either a symbol representing the type of object Hyperbole is prompting 
the user to input or nil.")
 
@@ -481,15 +484,15 @@ Insert in minibuffer if active or in other window if 
minibuffer is inactive."
            (delete-window))
          entry)))))
 
-(defun hargs:iform-read (iform &optional defaults)
+(defun hargs:iform-read (iform &optional default-args)
   "Read action arguments according to IFORM, a list with car = 'interactive.
-With optional DEFAULTS equal to t, the current button is being modified, so
+With optional DEFAULT-ARGS equal to t, the current button is being modified, so
 its attribute values should be presented as defaults.  Otherwise, use
-DEFAULTS as a list of defaults to present when reading arguments.
+DEFAULT-ARGS as a list of defaults to present when reading arguments.
 See also documentation for `interactive'."
   ;; This is mostly a translation of `call-interactively' to Lisp.
   ;;
-  ;; Save this now, since use of minibuffer will clobber it.
+  ;; Save the prefix arg now, since use of minibuffer will clobber it
   (setq prefix-arg current-prefix-arg)
   (if (not (and (listp iform) (eq (car iform) 'interactive)))
       (error "(hargs:iform-read): arg must be a list whose car = 'interactive")
@@ -498,8 +501,10 @@ See also documentation for `interactive'."
       (let ((prev-reading-p hargs:reading-p))
        (unwind-protect
            (progn
-             (when (eq defaults t)
-               (setq defaults (hattr:get 'hbut:current 'args)))
+             (when (eq default-args t)
+               (setq default-args (hattr:get 'hbut:current 'args)
+                     ;; Set hargs:defaults global used by "hactypes.el"
+                     hargs:defaults default-args))
              (setq hargs:reading-p t)
              (if (not (stringp iform))
                  (eval iform)
@@ -538,12 +543,12 @@ See also documentation for `interactive'."
                    (setq start (match-end 0)
                          ientry (substring iform i (match-beginning 0))
                          i start
-                         default (car defaults)
+                         default (car default-args)
                          default (if (or (null default) (stringp default))
                                      default
                                    (prin1-to-string default))
                          val (hargs:get ientry default (car results))
-                         defaults (cdr defaults)
+                         default-args (cdr default-args)
                          results (cond ((or (null val) (not (listp val)))
                                         (cons val results))
                                        ;; Is a list of args?
@@ -627,12 +632,12 @@ VAL-TYPE is a symbol indicating the type of value to be 
read."
        (select-window owind)
        (switch-to-buffer obuf)))))
 
-(defun hargs:select-p (&optional value assist-flag)
+(defun hargs:select-p (&optional value assist-bool)
   "Return optional VALUE or value selected at point if any, else nil.
 If value is the same as the contents of the minibuffer, it is used as
 the current minibuffer argument, otherwise, the minibuffer is erased
 and value is inserted there.
-Optional ASSIST-FLAG non-nil triggers display of Hyperbole menu item
+Optional ASSIST-BOOL non-nil triggers display of Hyperbole menu item
 help when appropriate."
     (when (and (> (minibuffer-depth) 0) (or value (setq value (hargs:at-p))))
       (let ((owind (selected-window)) (back-to)
@@ -647,7 +652,8 @@ help when appropriate."
               ;;
               ;; Selecting a menu item
               ((eq hargs:reading-p 'hmenu)
-               (if assist-flag (setq hargs:reading-p 'hmenu-help))
+               (when assist-bool
+                 (setq hargs:reading-p 'hmenu-help))
                (hui:menu-enter str-value))
               ;;
               ;; Enter existing value into the minibuffer as the desired 
parameter.
diff --git a/hload-path.el b/hload-path.el
index 1d946fb535..f0342ece37 100644
--- a/hload-path.el
+++ b/hload-path.el
@@ -42,6 +42,13 @@ It must end with a directory separator character.")
 ;; Also allow ".kot" for DOS and Windows users.
 (add-to-list 'auto-mode-alist '("\\.kotl?\\'" . kotl-mode))
 
+;;; ************************************************************************
+;;; Hyperbole test importation settings
+;;; ************************************************************************
+
+(add-to-list 'load-path (expand-file-name "test" hyperb:dir))
+
+
 ;; Ensure final name (after resolving all links) of hyperb:dir is
 ;; used after setting up load-path; otherwise, Hyperbole may fail
 ;; to substitute this as a variable into link path buttons.
diff --git a/hmouse-info.el b/hmouse-info.el
index 96f05f2675..ff58469dc4 100644
--- a/hmouse-info.el
+++ b/hmouse-info.el
@@ -73,7 +73,8 @@ or a Menu; otherwise returns nil."
     ;; If at end of node, go to next node
     ;;
     ((last-line-p)
-     (if (fboundp 'Info-global-next) (Info-global-next)
+     (if (fboundp 'Info-global-next)
+        (Info-global-next)
        (Info-next)))
     ((and (fboundp 'Info-mouse-follow-link)
          (mouse-event-p action-key-release-args)
diff --git a/hpath.el b/hpath.el
index f6b122052f..1f72847005 100644
--- a/hpath.el
+++ b/hpath.el
@@ -406,23 +406,27 @@ the function (hpath:get-external-display-alist) for 
external display program set
   (list
    (list 'this-window   #'switch-to-buffer)
    (list 'other-window  (lambda (b)
-                           (if (br-in-browser)
-                               (progn (br-to-view-window) (switch-to-buffer b))
-                             (switch-to-buffer-other-window b))))
+                         (if (br-in-browser)
+                             (progn (br-to-view-window)
+                                    (switch-to-buffer b))
+                           (switch-to-buffer-other-window b))))
    (list 'one-window    (lambda (b)
-                           (if (br-in-browser)
-                               (br-quit))
-                           (delete-other-windows)
-                           (switch-to-buffer b)))
+                         (when (br-in-browser)
+                           (br-quit))
+                         (delete-other-windows)
+                         (switch-to-buffer b)))
    (list 'new-frame     (lambda (b)
-                           (select-frame (make-frame))
-                           (switch-to-buffer b)))
+                         ;; Give temporary modes such as isearch a chance to 
turn off.
+                         (run-hooks 'mouse-leave-buffer-hook)
+                         (select-frame (make-frame (frame-parameters)))
+                         (switch-to-buffer b)))
    (list 'other-frame   #'hpath:display-buffer-other-frame)
    (list 'other-frame-one-window   (lambda (b)
-                                      (hpath:display-buffer-other-frame b)
-                                      (delete-other-windows))))
+                                    (hpath:display-buffer-other-frame b)
+                                    (delete-other-windows))))
   "*Alist of (DISPLAY-WHERE-SYMBOL  DISPLAY-BUFFER-FUNCTION) elements.
 This permits fine-grained control of where Hyperbole displays linked to 
buffers.
+
 The default value of DISPLAY-WHERE-SYMBOL is given by `hpath:display-where'.
 Valid DISPLAY-WHERE-SYMBOLs are:
     this-window             - display in the current window
@@ -440,22 +444,22 @@ See documentation of `hpath:display-where-alist' for 
valid values.")
   (list
    (list 'this-window  #'find-file)
    (list 'other-window (lambda (f)
-                          (if (br-in-browser)
-                              (progn (br-to-view-window)
-                                     (find-file f))
-                            (find-file-other-window f))))
+                        (if (br-in-browser)
+                            (progn (br-to-view-window)
+                                   (find-file f))
+                          (find-file-other-window f))))
    (list 'one-window   (lambda (f)
-                          (if (br-in-browser) (br-quit))
-                          (delete-other-windows)
-                          (find-file f)))
+                        (if (br-in-browser) (br-quit))
+                        (delete-other-windows)
+                        (find-file f)))
    (list 'new-frame    (lambda (f)
-                          (if (fboundp 'find-file-new-frame)
-                              (find-file-new-frame f)
-                            (hpath:find-other-frame f))))
+                        (if (fboundp 'find-file-new-frame)
+                            (find-file-new-frame f)
+                          (hpath:find-other-frame f))))
    (list 'other-frame  #'hpath:find-other-frame)
    (list 'other-frame-one-window (lambda (f)
-                                    (hpath:find-other-frame f)
-                                    (delete-other-windows))))
+                                  (hpath:find-other-frame f)
+                                  (delete-other-windows))))
   "*Alist of (DISPLAY-WHERE-SYMBOL DISPLAY-FILE-FUNCTION) elements.
 This permits fine-grained control of where Hyperbole displays linked to files.
 The default value of DISPLAY-WHERE-SYMBOL is given by `hpath:display-where'.
@@ -527,7 +531,7 @@ Its match groupings and their names are:
   7 = hpath:portnumber-grpn  = optional port number to use
   8 = hpath:pathname-grpn    = optional pathname to access.")
 
-(defvar hpath:url-hostnames-regexp  "\\(www\\|ftp\\|telnet\\|news\\|nntp\\)"
+(defvar hpath:url-hostnames-regexp  "\\(www\\|s?ftp\\|telnet\\|news\\|nntp\\)"
   "Grouped regexp alternatives of hostnames that automatically determine the 
Url access protocol to use.")
 
 (defvar hpath:url-regexp2
@@ -573,7 +577,7 @@ Its match groupings and their names are:
 (defconst hpath:sitename-grpn 5
   "URL site to connect to.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:hostname-grpn 6
-  "Hostname used to determine the access protocol, e.g. ftp.domain.com.
+  "Hostname used to determine the access protocol, e.g. sftp.domain.com.
 See doc for `hpath:url-regexp' and `hpath:url-regexp[2,3]'.")
 (defconst hpath:portnumber-grpn 7
   "Optional port number to use.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
@@ -622,7 +626,7 @@ These are used to indicate how to display or execute the 
pathname.
   & means run it under the current window system.")
 
 (defvar hpath:remote-regexp
-  "\\`/[^/:]+:\\|\\`ftp[:.]\\|\\`www\\.\\|\\`https?:"
+  "\\`/[^/:]+:\\|\\`s?ftp[:.]\\|\\`www\\.\\|\\`https?:"
   "Regexp matching remote pathnames and urls which invoke remote file 
handlers.")
 
 (defconst hpath:shell-modes '(sh-mode csh-mode shell-script:mode)
@@ -666,31 +670,39 @@ Other arguments are returned unchanged."
 
 (defun hpath:absolute-to (path &optional default-dirs)
   "Return PATH as an absolute path relative to one directory from optional 
DEFAULT-DIRS or `default-directory'.
-Return PATH unchanged when it is a buffer name or not a valid path or when 
DEFAULT-DIRS
-is invalid.  DEFAULT-DIRS when non-nil may be a single directory or a list of
-directories.  The first one in which PATH is found is used."
-  (cond ((not (and (stringp path)
-                  (not (get-buffer path))
-                  (not (hypb:object-p path))
-                   (hpath:is-p (hpath:trim path) nil t)))
-         path)
-        ((progn (setq path (hpath:trim path))
-                (not (cond ((null default-dirs)
-                            (setq default-dirs (cons default-directory nil)))
-                           ((stringp default-dirs)
-                            (setq default-dirs (cons default-dirs nil)))
-                           ((listp default-dirs))
-                           (t nil))))
-         path)
-        (t
-         (let ((rtn) dir)
-           (while (and default-dirs (null rtn))
-             (setq dir (expand-file-name
-                        (file-name-as-directory (car default-dirs)))
-                   rtn (expand-file-name path dir)
-                   default-dirs (cdr default-dirs))
-             (or (file-exists-p rtn) (setq rtn nil)))
-           (or rtn path)))))
+Return PATH unchanged when it is absolute, a buffer name, not a valid path,
+or when DEFAULT-DIRS is invalid.  DEFAULT-DIRS when non-nil may be a single
+directory or a list of directories.  The first one in which PATH is found is
+used."
+  (hpath:call
+   (lambda (path non-exist)
+     (when (stringp path)
+       (setq path (hpath:trim path)))
+     (cond ((not (and (stringp path)
+                     (not (hypb:object-p path))
+                     (setq path (hpath:expand path))
+                     (not (get-buffer path))
+                     (not (file-name-absolute-p path))
+                      (hpath:is-p path nil non-exist)))
+            path)
+           ((not (cond ((null default-dirs)
+                       (setq default-dirs (cons default-directory nil)))
+                       ((stringp default-dirs)
+                       (setq default-dirs (cons default-dirs nil)))
+                       ((listp default-dirs))
+                       (t nil)))
+            path)
+           (t
+            (let ((rtn) dir)
+              (while (and default-dirs (null rtn))
+               (setq dir (expand-file-name
+                           (file-name-as-directory (car default-dirs)))
+                      rtn (expand-file-name path dir)
+                      default-dirs (cdr default-dirs))
+               (unless (file-exists-p rtn)
+                 (setq rtn nil)))
+              (or rtn path)))))
+   path 'allow-spaces))
 
 (defun hpath:tramp-file-name-regexp ()
   "Return a modified `tramp-file-name-regexp' for matching to the beginning of 
a remote file name.
@@ -718,9 +730,9 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                     (looking-at (hpath:tramp-file-name-regexp)))
                (match-string-no-properties 0))
               ((looking-at hpath:url-regexp)
-               (if (string-equal (match-string-no-properties 
hpath:protocol-grpn) "ftp")
+               (if (string-match-p "\\`s?ftp\\'" (match-string-no-properties 
hpath:protocol-grpn))
                    (concat
-                    "/ftp:"
+                    (format "/%s:" (match-string-no-properties 
hpath:protocol-grpn))
                     ;; user
                     (if (match-beginning hpath:username-grpn)
                         (match-string-no-properties hpath:username-grpn)
@@ -736,9 +748,10 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                  ))
               ((or (looking-at hpath:url-regexp2)
                    (looking-at hpath:url-regexp3))
-               (if (string-equal (match-string-no-properties 
hpath:hostname-grpn) "ftp")
+               (if (string-match-p "\\`s?ftp\\'" (match-string-no-properties 
hpath:hostname-grpn))
                    (concat
-                    "/ftp:" user "@"
+                    (format "/%s:" (match-string-no-properties 
hpath:hostname-grpn))
+                    user "@"
                     ;; site
                     (hpath:delete-trailer
                      (match-string-no-properties hpath:sitename-grpn))
@@ -782,7 +795,7 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                ((eq remote-package 'tramp)
                 (if (tramp-tramp-file-p path) path))
                ((string-match hpath:string-url-regexp path)
-                (if (string-equal "ftp" (match-string-no-properties 
hpath:protocol-grpn path))
+                (if (string-match-p "\\`s?ftp\\'" (match-string-no-properties 
hpath:protocol-grpn path))
                     (concat
                      "/"
                      ;; user
@@ -800,7 +813,9 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                   ))
                ((or (string-match hpath:string-url-regexp2 path)
                     (string-match hpath:string-url-regexp3 path))
-                (if (string-equal "ftp" (match-string-no-properties 
hpath:hostname-grpn path))
+                (if (string-match-p "\\`s?ftp\\'"
+                                    (match-string-no-properties 
hpath:hostname-grpn path))
+                    
                     (concat
                      "/" user "@"
                      ;; site
@@ -871,11 +886,13 @@ paths are allowed.  Absolute pathnames must begin with a 
`/' or `~'."
          ((hpath:remote-at-p))
          ((hpath:www-at-p) nil))))
 
-(defun hpath:call (func path)
-  "Call FUNC with one argument, a PATH, stripped of any prefix operator and 
suffix location.
+(defun hpath:call (func path &optional non-exist)
+  "Call FUNC with a PATH, stripped of any prefix operator and suffix location, 
and optional NON-EXIST flag.
+NON-EXIST may be either t (path cannot contain whitespace) or 'allow-spaces to 
allow for whitespace.
+
 Return the result of calling FUNC, which must be either nil or the
 possibly modified path, but with the prefix and suffix reattached.
-Make any path within a file buffer absolute before returning. "
+Make any existing path within a file buffer absolute before returning."
   (unless (or (functionp func) (subrp func))
     (error "(hpath:call): Invalid function: %s" func))
   (unless (stringp path)
@@ -883,6 +900,7 @@ Make any path within a file buffer absolute before 
returning. "
   ;; Convert tabs and newlines to space.
   (setq path (hbut:key-to-label (hbut:label-to-key path)))
   (let* ((orig-path path)
+        (expanded-path)
         (prefix (car (delq nil (list (when (string-match hpath:prefix-regexp 
path)
                                        (prog1 (match-string 0 path)
                                          (setq path (substring path (match-end 
0)))))
@@ -905,32 +923,51 @@ Make any path within a file buffer absolute before 
returning. "
                                                   (when (string-match 
hpath:markup-link-anchor-regexp path)
                                                     (prog1 (concat "#" 
(match-string 3 path))
                                                       (setq path (substring 
path 0 (match-beginning 2)))))))))))
-    (setq path (funcall func path))
-    (when (or (and path (not (string-empty-p path)))
-             ;; If just a numeric suffix like ":40" by itself, ignore
-             ;; it, but if a markdown type suffix alone, like
-             ;; "#section", use it.
-             (and suffix (not (string-empty-p suffix))
-                  (= ?# (aref suffix 0))))
-      (setq path (concat prefix path suffix))
-      ;; If path is just a local reference that begins with #,
-      ;; in a file buffer, prepend the file name to it.  If an HTML
-      ;; file, prepend file:// to it.
-      (let ((mode-prefix (if (memq major-mode '(js2-mode js-mode js3-mode 
javascript-mode html-mode web-mode))
-                            "file://" "")))
-       (cond ((and buffer-file-name
-                   ;; ignore HTML color strings
-                   (not (string-match 
"\\`#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]\\'" 
path))
-                   ;; match to in-file HTML references
-                   (string-match "\\`#[^\'\"<>#]+\\'" path))
-              (setq path (concat mode-prefix buffer-file-name path)))
-             ((string-match "\\`[^#]+\\(#[^#]*\\)\\'" path)
-              ;; file and # reference
-              (if (memq (aref path 0) '(?/ ?~))
-                  ;; absolute
-                  (setq path (concat mode-prefix path))
-                (setq path (concat mode-prefix default-directory path))))
-             (t path))))))
+    (setq expanded-path (hpath:expand path)
+         path (funcall func expanded-path non-exist))
+    ;; If path is just a local reference that begins with #,
+    ;; in a file buffer, prepend the file name to it.  If an HTML
+    ;; file, prepend file:// to it.
+    (let ((mode-prefix (if (memq major-mode '(js2-mode js-mode js3-mode 
javascript-mode html-mode web-mode))
+                          "file://"
+                        "")))
+      (if (and path
+              (not (string-empty-p path))
+              ;; If just a numeric suffix like ":40" by itself, ignore
+              ;; it, but if a markdown type suffix alone, like
+              ;; "#section", use it.
+              (and suffix (not (string-empty-p suffix))
+                   (= ?# (aref suffix 0))))
+         (progn
+           (setq path (concat prefix path suffix))
+           (cond ((and buffer-file-name
+                       ;; ignore HTML color strings
+                       (not (string-match 
"\\`#[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]\\'" 
path))
+                       ;; match to in-file HTML references
+                       (string-match "\\`#[^\'\"<>#]+\\'" path))
+                  (setq path (concat mode-prefix buffer-file-name path)))
+                 ((string-match "\\`\\([^#]+\\)\\(#[^#]*\\)\\'" path)
+                  ;; file and # reference
+                  (setq suffix (match-string 2 path)
+                        path (match-string 1 path))
+                  (if (file-name-absolute-p path)
+                      ;; already absolute
+                      (setq path (concat mode-prefix path suffix))
+                    ;; make absolute
+                    (setq path (hpath:expand path))
+                    (unless (string-match "\\$@?\{\\([^\}]+\\)@?\}" path)
+                      (expand-file-name path))
+                    (setq path (concat mode-prefix path suffix))))
+                 (t path)))
+
+       (when (or (and (stringp suffix) (not (string-empty-p suffix))
+                      (= ?# (aref suffix 0)))
+                 (and (stringp expanded-path)
+                      (or non-exist
+                          (file-name-absolute-p expanded-path) ;; absolute path
+                          (string-match "\\$@?\{[^\}]+@?\}" expanded-path) ;; 
path with var
+                          (string-match "\\`([^\):]+)" expanded-path)))) ;; 
Info node
+         (concat prefix mode-prefix expanded-path suffix))))))
 
 (defun hpath:is-path-variable-p (path-var)
   "Return the value of a colon or semicolon-delimited set in PATH-VAR or nil 
if not a match."
@@ -1005,7 +1042,7 @@ is displayed or nil if not displayed because BUFFER is 
invalid."
   (interactive "bDisplay buffer: ")
   (if (stringp buffer) (setq buffer (get-buffer buffer)))
   (when buffer
-    ;; BW 4/30/2016 - Commented out in case interferes with Smart Key
+    ;; RSW 4/30/2016 - Commented out in case interferes with Smart Key
     ;; selection and yanking of the region via drags.
     ;; (hpath:push-tag-mark)
     (funcall (hpath:display-buffer-function display-where) buffer)
@@ -1019,6 +1056,8 @@ May create a new frame, or reuse an existing one.  See the
 documentation of `hpath:display-buffer' for details.  Return the
 window in which the buffer is displayed."
   (interactive "bDisplay buffer in other frame: ")
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
   ;; BW 4/30/2016 - Commented out in case interferes with Smart Key
   ;; selection and yanking or the region via drags.
   ;; (hpath:push-tag-mark)
@@ -1039,19 +1078,22 @@ window in which the buffer is displayed."
   (hpath:display-where-function display-where hpath:display-where-alist))
 
 (defun hpath:expand (path)
-  "Expand relative PATH using the load variable from the first file matching 
regexp in `hpath:auto-variable-alist'."
-  (unless (file-name-absolute-p path)
-    (let ((substituted-path (hpath:substitute-value
-                            (if (string-match "\\`[\\/~.]" path)
-                                (expand-file-name path)
-                              (hpath:expand-with-variable path)))))
-      (unless (string-match "\\$@?\{\\([^\}]+\\)@?\}" substituted-path)
-         ;; When no valid variable substitution was found after
-         ;; potentially adding a variable to the path, use
-         ;; unchanged path.
-       (setq path substituted-path))))
-  ;; For compressed Elisp libraries, add any found compressed suffix to the 
path.
-  (or (locate-library path t) path))
+  "Expand relative PATH using the path variable from the first file matching 
regexp in `hpath:auto-variable-alist'.
+Return any absolute PATH unchanged."
+  (when (stringp path)
+    (let (variable-path
+         substituted-path)
+      (setq variable-path (hpath:expand-with-variable path)
+           substituted-path (hpath:substitute-value variable-path)
+           path substituted-path)
+      (if (and (string-match "\\$@?\{\\([^\}]+\\)@?\}" variable-path)
+              (string-match "\\$@?\{\\([^\}]+\\)@?\}" substituted-path))
+         ;; If a path is invalid, then a variable may have been prepended but
+         ;; it will remain unresolved in 'substituted-path', in which case we
+         ;; want to return 'path' without any further changes.
+         path
+       ;; For compressed Elisp libraries, add any found compressed suffix to 
the path.
+       (or (locate-library path t) path)))))
 
 (defun hpath:prepend-ls-directory ()
   "When in a shell buffer and on a filename result of an 'ls *' or recursive 
'ls', prepend the subdir to the filename and return it, else nil."
@@ -1072,26 +1114,33 @@ window in which the buffer is displayed."
    "Regexp of compressed file name suffixes.")
 
 (defun hpath:expand-with-variable (path)
-  "Assume PATH is relative and prepend to it the ${load variable name} from 
the first file matching regexp in `hpath:auto-variable-alist' sans any 
compression suffix in `hpath:compressed-suffix-regexp'."
-  (let ((auto-variable-alist hpath:auto-variable-alist)
-       (compression-suffix (when (string-match hpath:compressed-suffix-regexp 
path)
-                             (prog1 (match-string 0 path)
-                               (setq path (substring path 0 (match-beginning 
0))))))
-       regexp
-       variable)
-    (while auto-variable-alist
-      (setq regexp (caar auto-variable-alist)
-           variable (cdar auto-variable-alist)
-           auto-variable-alist (cdr auto-variable-alist))
-      (when (and variable (symbolp variable))
-       (setq variable (symbol-name variable)))
-      (when (and path variable (string-match regexp path))
-       (when (and (not (string-match (regexp-quote variable) path))
-                  (or (and (stringp variable) (getenv variable))
-                      (and (symbolp variable) (boundp variable))))
-         (setq path (format "${%s}/%s" variable path)))
-       (setq auto-variable-alist nil)))
-    (concat path compression-suffix)))
+  "When PATH is relative, prepend to it the ${load variable name} from the 
first file matching regexp in `hpath:auto-variable-alist' sans any compression 
suffix in `hpath:compressed-suffix-regexp'.
+If PATH is absolute, return it unchanged."
+  (when (stringp path)
+    (let ((auto-variable-alist hpath:auto-variable-alist)
+         (compression-suffix (when (string-match 
hpath:compressed-suffix-regexp path)
+                               (prog1 (match-string 0 path)
+                                 (setq path (substring path 0 (match-beginning 
0))))))
+         regexp
+         variable
+         variable-name)
+      (unless (or (file-name-absolute-p path)
+                 (hpath:url-p path)
+                 (string-match "\\`\\$@?\{\\([^\}]+\\)@?\}" path))
+       (while auto-variable-alist
+         (setq regexp (caar auto-variable-alist)
+               variable (cdar auto-variable-alist)
+               auto-variable-alist (cdr auto-variable-alist)
+               variable-name (if (and variable (symbolp variable))
+                                 (symbol-name variable)
+                               variable))
+         (when (and path variable (string-match regexp path))
+           (when (and (not (string-match (regexp-quote variable-name) path))
+                      (or (and (stringp variable) (getenv variable))
+                          (and (symbolp variable) (boundp variable))))
+             (setq path (format "${%s}/%s" variable path)))
+           (setq auto-variable-alist nil))))
+      (concat path compression-suffix))))
 
 (defun hpath:file-line-and-column (path-line-and-col)
   "Given a `path-line-and-col' string of format: path:line:col, return a list 
with the parts parsed out, else nil."
@@ -1120,8 +1169,8 @@ See `hpath:find' documentation for acceptable formats of 
FILENAME."
 
 (defun hpath:find (filename &optional display-where noselect)
   "Edit FILENAME using user customizable settings of display program and 
location.
-Return the current buffer iff file is displayed within a buffer (not with an 
external
-program), else nil.
+Return the current buffer iff file is read into a buffer (not displayed with
+an external program), else nil.
 
 FILENAME may contain references to Emacs Lisp variables or shell
 environment variables using the syntax, \"${variable-name}\".
@@ -1189,18 +1238,20 @@ buffer but don't display it."
              filename "")
       (setq path (hpath:expand path)
            filename (hpath:absolute-to path default-directory)))
-    (if noselect
-       (let ((buf (find-file-noselect filename)))
-         (with-current-buffer buf
-           (when (or hash anchor) (hpath:to-markup-anchor hash anchor))
-           buf))
-      (let ((remote-filename (hpath:remote-p path)))
-       (or modifier remote-filename
-           (file-exists-p filename)
-           (error "(hpath:find): \"%s\" does not exist" filename))
-       (or modifier remote-filename
-           (file-readable-p filename)
-           (error "(hpath:find): \"%s\" is not readable" filename))
+    (let ((remote-filename (hpath:remote-p path)))
+      (or modifier remote-filename
+         (file-exists-p filename)
+         (error "(hpath:find): \"%s\" does not exist"
+                (concat modifier filename (when hash "#") anchor)))
+      (or modifier remote-filename
+         (file-readable-p filename)
+         (error "(hpath:find): \"%s\" is not readable"
+                (concat modifier filename (when hash "#") anchor)))
+      (if noselect
+         (let ((buf (find-file-noselect filename)))
+           (with-current-buffer buf
+             (when (or hash anchor) (hpath:to-markup-anchor hash anchor))
+             buf))
        ;; If filename is a remote file (not a directory), we have to copy it to
        ;; a temporary local file and then display that.
        (when (and remote-filename (not (file-directory-p remote-filename)))
@@ -1210,38 +1261,64 @@ buffer but don't display it."
                     t t)
          (setq filename (cond (anchor (concat remote-filename "#" anchor))
                               (hash   (concat remote-filename "#"))
-                              (t path)))))
-      (cond (modifier (cond ((= modifier ?!)
-                            (hact 'exec-shell-cmd filename))
-                           ((= modifier ?&)
-                            (hact 'exec-window-cmd filename))
-                           ((= modifier ?-)
-                            (hact 'load filename)))
+                              (t path))))))
+    (cond (modifier (cond ((= modifier ?!)
+                          (hact 'exec-shell-cmd filename))
+                         ((= modifier ?&)
+                          (hact 'exec-window-cmd filename))
+                         ((= modifier ?-)
+                          (hact 'load filename)))
+                   nil)
+
+         ;; If no path, e.g. just an anchor link in a non-file buffer,
+         ;; then must display within Emacs, ignoring any external programs.
+         ((string-empty-p path)
+          (hpath:display-buffer (current-buffer) display-where)
+          (when (or hash anchor)
+            (hpath:to-markup-anchor hash anchor))
+          (when line-num
+            ;; With an anchor, goto line relative to anchor
+            ;; location, otherwise use absolute line number
+            ;; within the visible buffer portion.
+            (if (or hash anchor)
+                (forward-line line-num)
+              (hpath:to-line line-num)))
+          (when col-num (move-to-column col-num))
+          (current-buffer))
+
+         ;; Display paths either internally or externally.
+         (t (let ((display-executables (hpath:find-program path))
+                  executable)
+              (cond ((stringp display-executables)
+                     (hact 'exec-window-cmd
+                           (hpath:command-string display-executables filename))
                      nil)
-           (t (let ((display-executables (hpath:find-program path))
-                    executable)
-                (cond ((stringp display-executables)
-                       (hact 'exec-window-cmd
-                             (hpath:command-string display-executables 
filename))
-                       nil)
-                      ((functionp display-executables)
-                       (funcall display-executables filename)
-                       (current-buffer))
-                      ((and (listp display-executables) display-executables)
-                       (setq executable (hpath:find-executable 
display-executables))
-                       (if executable
-                           (hact 'exec-window-cmd
-                                 (hpath:command-string executable filename))
-                         (error "(hpath:find): No available executable from: 
%s"
-                                display-executables)))
-                      (t (setq path (hpath:validate path))
-                         (funcall (hpath:display-path-function display-where) 
path)
-                         (when (or hash anchor) (hpath:to-markup-anchor hash 
anchor))
+                    ((functionp display-executables)
+                     (funcall display-executables filename)
+                     (current-buffer))
+                    ((and (listp display-executables) display-executables)
+                     (setq executable (hpath:find-executable 
display-executables))
+                     (if executable
+                         (hact 'exec-window-cmd
+                               (hpath:command-string executable filename))
+                       (error "(hpath:find): No available executable from: %s"
+                              display-executables)))
+                    (t (setq path (hpath:validate path))
+                       (funcall (hpath:display-path-function display-where) 
path)
+                       ;; Perform a loose test that the current buffer
+                       ;; file name matches the path file name since exact
+                       ;; matching of path is likely to be wrong in
+                       ;; certain cases, e.g. with mount point or os path
+                       ;; alterations.
+                       (when (and buffer-file-name
+                                  (equal (file-name-nondirectory path)
+                                         (file-name-nondirectory 
buffer-file-name)))
+                         (when (or hash anchor)
+                           (hpath:to-markup-anchor hash anchor))
                          (when line-num
-                           ;; With an anchor, goto line relative to
-                           ;; anchor location, otherwise use absolute
-                           ;; line number within the visible buffer
-                           ;; portion.
+                           ;; With an anchor, goto line relative to anchor
+                           ;; location, otherwise use absolute line number
+                           ;; within the visible buffer portion.
                            (if (or hash anchor)
                                (forward-line line-num)
                              (hpath:to-line line-num)))
@@ -1279,7 +1356,10 @@ buffer but don't display it."
                                      (subst-char-in-string ?- ?\  anchor))))
                  (goto-char (point-min))
                  (if (re-search-forward (format
-                                         (cond ((derived-mode-p 'outline-mode) 
;; Includes Org mode
+                                         (cond ((or (derived-mode-p 
'outline-mode) ;; Includes Org mode
+                                                    ;; Treat all caps 
filenames without suffix like outlines, e.g. README, INSTALL.
+                                                    (and buffer-file-name
+                                                         (string-match-p 
"\\`[A-Z][A-Z0-9]+\\'" buffer-file-name)))
                                                 hpath:outline-section-pattern)
                                                (prog-mode
                                                 "%s")
@@ -1382,17 +1462,19 @@ See also `hpath:internal-display-alist' for internal, 
`window-system' independen
   "Return normalized PATH if PATH is a Posix or MSWindows path, else nil.
 If optional TYPE is the symbol 'file or 'directory, then only that path type
 is accepted as a match.  The existence of the path is checked only for
-locally reachable paths (Info paths are not checked).  With optional NON-EXIST,
-nonexistent local paths are allowed.  Single spaces are permitted in the middle
-of existing pathnames, but not at the start or end.
-
-Before the pathname is checked for existence, tabs and newlines
-are converted to a single space, `hpath:prefix-regexp' matches at
-the start are temporarily stripped, \"file://\" prefixes are
-stripped, link anchors at the end following a # or , character
-are temporarily stripped, and path variables are expanded with
-`hpath:substitute-value'.  This normalized path form is what is
-returned for PATH."
+locally reachable paths (Info paths are not checked).
+
+Single spaces are permitted in the middle of existing pathnames, but not at
+the start or end.  With optional NON-EXIST equal to t, nonexistent local
+paths without spaces are allowed.  Set NON-EXIST to 'allow-spaces to allow
+spaces in non-existent paths.
+
+Before the pathname is checked for existence, sequences of tabs and newlines
+are converted to a single space, `hpath:prefix-regexp' matches at the start
+are temporarily stripped, \"file://\" prefixes are stripped, link anchors at
+the end following a # or , character are temporarily stripped, and path
+variables are expanded with `hpath:substitute-value'.  This normalized path
+form is what is returned for PATH."
   (when (and (stringp path) (not (string-match 
hpath:path-variable-value-regexp path))
             ;; If a single character in length, must be a word or symbol 
character
             (or (/= (length path) 1) (and (string-match "\\sw\\|\\s_" path)
@@ -1400,7 +1482,7 @@ returned for PATH."
     (setq path (hpath:mswindows-to-posix path))
     (unless (string-match "\\`[.~/]\\'" path)
       (setq path (hpath:call
-                 (lambda (path)
+                 (lambda (path non-exist)
                    (let (modifier
                          suffix)
                      (and (not (or (string-equal path "")
@@ -1411,12 +1493,15 @@ returned for PATH."
                           (or (when (string-match "\\$@?\{[^\}]+@?\}" path)
                                 ;; Path may be a link reference with embedded
                                 ;; variables that must be expanded.
-                                (setq path (hpath:substitute-value path)))
+                                (setq path (hpath:substitute-value path)
+                                      non-exist t ;; Ensure non-existent path 
links handled as pathnames.
+                                      ))
                               t)
                           (not (string-match "[\t\n\r\"`'|{}\\]" path))
                           (let ((rtn-path (concat path "%s")))
                             (and (or (not (hpath:www-p path))
-                                     (string-match "\\`ftp[:.]" path))
+                                     (string-match "\\`s?
+ftp[:.]" path))
                                  (let ((remote-path (string-match 
"\\(@.+:\\|^/.+:\\|..+:/\\).*[^:0-9/]" path)))
                                    (when (cond (remote-path
                                                 (cond ((eq type 'file)
@@ -1430,9 +1515,10 @@ returned for PATH."
                                                           (string-match "[()]" 
path)
                                                           (hpath:remote-p path)
                                                           (setq suffix 
(hpath:exists-p path t))
-                                                          ;; Don't allow 
spaces in non-existent
-                                                          ;; pathnames.
-                                                          (not (string-match " 
" path))))
+                                                          ;; Don't allow 
spaces in non-existent pathnames
+                                                          ;; unless 
'non-exist' equals 'allow-spaces.
+                                                          (eq non-exist 
'allow-spaces)
+                                                          (not (string-match 
"\\s-" path))))
                                                     (setq suffix 
(hpath:exists-p path t)))
                                                 (cond ((eq type 'file)
                                                        (not (file-directory-p 
path)))
@@ -1459,7 +1545,7 @@ returned for PATH."
                                            ;; add suffix
                                            (concat modifier (format rtn-path 
suffix)))
                                        (concat modifier (format rtn-path 
""))))))))))
-                 path)))
+                 path non-exist)))
      (unless (or (null path)
                 (string-empty-p path)
                 (string-match "#['`\"]" path)
@@ -1762,7 +1848,7 @@ with a character not a letter, digit or underscore; 
otherwise, enclose
 the entire variable name in braces.
 If `/~' appears, all of FILENAME through that `/' is discarded."
   (if (string-match
-       "\\(/\\|[^a-zA-Z0-9]\\)?\\(https?\\|ftp\\|telnet\\|news\\|nntp\\):[/~]"
+       
"\\(/\\|[^a-zA-Z0-9]\\)?\\(https?\\|s?ftp\\|telnet\\|news\\|nntp\\):[/~]"
        filename)
       (substring filename (match-beginning 2))
     (hyperb:substitute-in-file-name filename)))))))
diff --git a/hui.el b/hui.el
index c3843c21ef..837d39f863 100644
--- a/hui.el
+++ b/hui.el
@@ -394,8 +394,8 @@ modification   Signal an error when no such button is 
found."
                                          nil t nil 'gbut)))))
   (let ((lbl (hbut:key-to-label lbl-key))
         (interactive-flag (called-interactively-p 'interactive))
-       (src-dir default-directory)
        (but-buf (find-file-noselect gbut:file))
+       (src-dir (file-name-directory gbut:file))
        actype but new-lbl)
     (save-excursion
       (unless interactive-flag



reply via email to

[Prev in Thread] Current Thread [Next in Thread]