Subject: Re: bug#37724: HTML Markdown and Emacs Outline Hash Links in DEMO not working

From: Robert Weiner <[email-masked]>
Date: Sun, 13 Oct 2019 12:59:52 -0400

On Sun, Oct 13, 2019 at 12:21 AM Kevin J. McCarthy <[email-masked]> wrote:
>
> I use:  Editor:      GNU Emacs 26.1 (build 2, x86_64-pc-linux-gnu, GTK+ Version 3.24.4)
>
>          Hyperbole:   7.0.7
>          Sys Type:    x86_64-pc-linux-gnu
>          OS Type:     gnu/linux
>          Window Sys:  x
>          News Reader: Gnus v5.13
>
> In the DEMO file under
> * Implicit Buttons
> ** Implicit Path Links
> *** HTML Markdown and Emacs Outline Hash Links
>
> The example "man/hyperbole.html#Smart-Keys" gives me an error message
>    (hpath:find): "man/hyperbole.html" does not exist
>
> The same for "README.md#why-was-hyperbole-developed":
>    (hpath:find): "README.md" does not exist

Another good catch.  There was a missing file-name-directory call
needed to remove the filename from the 'loc attribute of this type of
button in hpath:find.  Use the following replacement to fix it.

(defun hpath:find (filename &optional display-where noselect)
  "Edit file 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.

FILENAME may start with a special prefix character that is handled as follows:
  !filename  - execute as a non-windowed program within a shell;
  &filename  - execute as a windowed program;
  -filename  - load as an Emacs Lisp program.

If FILENAME does not start with a prefix character:

  it may be followed by a hash-style link reference to HTML, Markdown
  or Emacs outline headings of the form, <file>#<anchor-name>,
  e.g. \"~/.bashrc#Alias Section\";

  it may end with a line number and optional column number to which to go,
  of the form, :<line-number>[:<column-number>], e.g. \"~/.bashrc:20:5\";
  normally, this is an absolute line number (disabling buffer restriction),
  but if preceded by a hash-style link reference, it is relative to the
  location of the link anchor;

  if it matches a regular expression in the alist returned by
  \(hpath:get-external-display-alist), invoke the associated external
  display program

  if not, consult `hpath:internal-display-alist' for a specialized internal
  display function to use;

  if no matches are found there, consult `hpath:display-where-alist'
  using the optional second argument, DISPLAY-WHERE (a symbol);

  if that is nil, consult the value of `hpath:display-where', and use the
  matching display function.

Optional third argument, NOSELECT, means simply find the file and return its
buffer but don't display it."
  (interactive "FFind file: ")
  (let ((case-fold-search t)
        (default-directory default-directory)
        modifier loc anchor hash path line-num col-num)
    (setq loc (hattr:get 'hbut:current 'loc)
          default-directory (or (hattr:get 'hbut:current 'dir)
                                ;; Loc may be a buffer without a file
                                (if (stringp loc)
                                    (file-name-directory loc)
                                  default-directory)))
    (when (string-match hpath:prefix-regexp filename)
      (setq modifier (aref filename 0)
            filename (substring filename (match-end 0))))
    (setq path filename) ;; default
    (when (string-match hpath:line-and-column-regexp path)
      (setq line-num (string-to-number (match-string 1 path))
            col-num (when (match-string 3 path)
                      (string-to-number (match-string 3 path)))
            path (substring path 0 (match-beginning 0))))
    (when (string-match hpath:markup-link-anchor-regexp path)
      (setq hash t
            anchor (match-string 3 path)
            path (substring path 0 (match-end 1))))
    (setq path (hpath:substitute-value path)
          filename (hpath:absolute-to path default-directory))
    (if noselect
        (prog1 (find-file-noselect filename)
          (if (or hash anchor) (hpath:to-markup-anchor hash anchor)))
      (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))
        ;; 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)))
          (copy-file remote-filename
                     (setq path (concat hpath:tmp-prefix
                                        (file-name-nondirectory
remote-filename)))
                     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)))
                      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))
                          (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)))))))))

This issue is now resolved and will be closed.

Bob