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

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

[elpa] externals/hyperbole 5d6b9cd 05/53: 2017-09-10 Bob Weiner <address


From: Robert Weiner
Subject: [elpa] externals/hyperbole 5d6b9cd 05/53: 2017-09-10 Bob Weiner <address@hidden>
Date: Wed, 15 Nov 2017 22:46:58 -0500 (EST)

branch: externals/hyperbole
commit 5d6b9cda72d432fb0f49715e63638d33afe5cc72
Author: Bob Weiner <address@hidden>
Commit: Bob Weiner <address@hidden>

    2017-09-10  Bob Weiner  <address@hidden>
    
    * hui-mouse.el (smart-helm, smart-helm-assist, smart-helm-line-has-action):
      hsettings.el (helm-allow-mouse): Set to t.
        New helm completion activation support.
        Added to allow mouse direct selection of helm completion items.  The
        smart-helm function behaves similarly to the {C-j} and {C-z} key 
bindings
        that helm mode provides when a helm completion is active but the Smart
        Keys work in the completions buffer regardless of whether a helm
        completion is active or not.
    
    * hsys-www.el (www-url): Added Action and Assist Key support for browsing
        links in eww (the Emacs web browser) and for activating history links
        in the eww history buffer.
    
    2017-09-08  Bob Weiner  <address@hidden>
    
    * hpath.el (hpath:url-regexp3): Added a third pattern match for URLs,
       allowing for partial http urls with non-www site names preceded by the
       literal url or URL followed by a : or =.  For example:
       url:photos.google.com or url=calendar.google.com
    
    2017-09-07  Bob Weiner  <address@hidden>
    
    * hui-menu.el (hui-menu-browser): Changed the Default setting to always
        use the current setting of browse-url-default-browser since that is the
        default in browse-url (eliminated use of browse-url-generic).
    
    * hypb.el (hypb:decode-url): Added.
      hpath.el (hpath:is-p): Fixed to handle and decode encoded URL paths before
        returning the path.
    
    2017-09-06  Bob Weiner  <address@hidden>
    
    * hui-mouse.el (hkey-alist): Changed Python predicate to match more
    broadly, namely in any non-file buffer whose name includes Pydoc: or
    Python (case-sensitive).
    
    * hmouse-tag.el (smart-python-at-tag-p): Expanded to handle tags with
       periods embedded such as `sys.path'.
    
    2017-09-04  Bob Weiner  <address@hidden>
    
    * hibtypes.el (debugger-source): Added support for Python pdb stack trace 
lines.
    
    2017-08-31  Bob Weiner  <address@hidden>
    
    * hibtypes.el (pathname): Wrapped mode-name reference in format-mode-line
        call since mode-name is not always a string.
    
    * hui-em-but.el (hproperty:but-highlight-p): Added to allow disabling of 
explicit button highlighting.
                    (hproperty:but-create-all):  Used this new flag.
      hui-xe-but.el (hproperty:but-highlight-p): Added to allow disabling of 
explicit button highlighting.
                    (hproperty:but-create-all):  Used this new flag.
    
    * hbut.el (ebut:map): Changed to ignore explicit button matches in
        programming languages when outside of a comment.  For example, syntax 
like
        this in a Rust buffer had been improperly matched: fn parse_kv(kv_list:
        Vec<(syn::Ident, syn::StrLit)>, function: &Function) -> LispFnArgs
    
    2017-08-25  Bob Weiner  <address@hidden>
    
    * hui-mouse.el (smart-ibuffer-menu): Ibuffer calling conventions have
        changed across time (as of Emacs25) to allow for regional arguments;
        updated to account for these.
    
    * hpath.el (hpath:remote-at-p): For Emacs 26 where
        tramp-file-name-structure is now a function instead of a variable, call
        the function.
    
    * hyrolo.el (hyrolo-kill): Triggered error if FILE contains a '*' character,
        mainly in case a buffer name is passed as an argument.
                (hyrolo-file-list-initialize): Added this function so can
        re-initialize the hyrolo-file-list later if BBDB or Google Contacts
        support is loaded after the Hyperbole Rolo is initialized.
    
    * hbut.el (hbut:source): Allowed for spaces in buffer names.
    
    * hyrolo.el (hyrolo-edit-entry): Avoided error if bbdb-file is nil.
    
    * hbut.el (ebut:label-p): Added one-line-flag to constrain label search to 
a single line.
      hibtypes.el (Info-node): Constrained Info-node hyper-button matches to a 
single line.
    
    * hyrolo.el: Added support for Google Contacts when the google-contacts
        package is in use and a public key package is available for Google
        authorization.
    
    2016-09-08  Bob Weiner  <address@hidden>
    
    * man/hyperbole.texi: Documented Pages Directory Listing handling.
    
    * kotl/klink.el: (require 'hbut): Added to define defib when compiled.
    
    2016-08-26  Bob Weiner  <address@hidden>
    
    * hui-mouse.el (hkey-alist): Added Smart Key jump to associated page in 
pages-directory-mode (page-ext.el).
      man/hkey-help.txt: Documented Pages Directory Listing and Imenu 
Programming Identifier handling.
---
 Changes       |  87 ++++++++++++++++++++-
 HY-NEWS       |   2 +-
 MANIFEST      |   1 -
 hbut.el       |  39 ++++++----
 hibtypes.el   | 158 ++++++++++++++++++++------------------
 hmouse-tag.el |  27 +++++--
 hpath.el      | 139 +++++++++++++++++++++-------------
 hsettings.el  |  10 ++-
 hsys-www.el   |  49 +++++++++---
 hui-em-but.el |  12 ++-
 hui-menu.el   |   5 +-
 hui-mouse.el  |  94 +++++++++++++++++------
 hui-xe-but.el |  14 +++-
 hypb.el       |  25 ++++++
 hyperbole.el  |  22 +++---
 hyrolo.el     | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 16 files changed, 701 insertions(+), 221 deletions(-)

diff --git a/Changes b/Changes
index 94bd0bc..d84e6c2 100644
--- a/Changes
+++ b/Changes
@@ -1,4 +1,89 @@
--- Almost all changes listed herein are new as of 2016. --
+2017-09-10  Bob Weiner  <address@hidden>
+
+* hui-mouse.el (smart-helm, smart-helm-assist, smart-helm-line-has-action):
+  hsettings.el (helm-allow-mouse): Set to t.
+    New helm completion activation support.
+    Added to allow mouse direct selection of helm completion items.  The
+    smart-helm function behaves similarly to the {C-j} and {C-z} key bindings
+    that helm mode provides when a helm completion is active but the Smart
+    Keys work in the completions buffer regardless of whether a helm
+    completion is active or not.
+
+* hsys-www.el (www-url): Added Action and Assist Key support for browsing
+    links in eww (the Emacs web browser) and for activating history links
+    in the eww history buffer.
+
+2017-09-08  Bob Weiner  <address@hidden>
+
+* hpath.el (hpath:url-regexp3): Added a third pattern match for URLs,
+   allowing for partial http urls with non-www site names preceded by the
+   literal url or URL followed by a : or =.  For example:
+   url:photos.google.com or url=calendar.google.com
+
+2017-09-07  Bob Weiner  <address@hidden>
+
+* hui-menu.el (hui-menu-browser): Changed the Default setting to always
+    use the current setting of browse-url-default-browser since that is the
+    default in browse-url (eliminated use of browse-url-generic).
+
+* hypb.el (hypb:decode-url): Added.
+  hpath.el (hpath:is-p): Fixed to handle and decode encoded URL paths before
+    returning the path.
+
+2017-09-06  Bob Weiner  <address@hidden>
+
+* hui-mouse.el (hkey-alist): Changed Python predicate to match more
+broadly, namely in any non-file buffer whose name includes Pydoc: or
+Python (case-sensitive).
+
+* hmouse-tag.el (smart-python-at-tag-p): Expanded to handle tags with
+   periods embedded such as `sys.path'.
+
+2017-09-04  Bob Weiner  <address@hidden>
+
+* hibtypes.el (debugger-source): Added support for Python pdb stack trace 
lines.
+
+2017-08-31  Bob Weiner  <address@hidden>
+
+* hibtypes.el (pathname): Wrapped mode-name reference in format-mode-line
+    call since mode-name is not always a string.
+
+* hui-em-but.el (hproperty:but-highlight-p): Added to allow disabling of 
explicit button highlighting.
+                (hproperty:but-create-all):  Used this new flag.
+  hui-xe-but.el (hproperty:but-highlight-p): Added to allow disabling of 
explicit button highlighting.
+                (hproperty:but-create-all):  Used this new flag.
+
+* hbut.el (ebut:map): Changed to ignore explicit button matches in
+    programming languages when outside of a comment.  For example, syntax like
+    this in a Rust buffer had been improperly matched: fn parse_kv(kv_list:
+    Vec<(syn::Ident, syn::StrLit)>, function: &Function) -> LispFnArgs 
+
+2017-08-25  Bob Weiner  <address@hidden>
+
+* hui-mouse.el (smart-ibuffer-menu): Ibuffer calling conventions have
+    changed across time (as of Emacs25) to allow for regional arguments;
+    updated to account for these.
+
+* hpath.el (hpath:remote-at-p): For Emacs 26 where
+    tramp-file-name-structure is now a function instead of a variable, call
+    the function. 
+
+* hyrolo.el (hyrolo-kill): Triggered error if FILE contains a '*' character,
+    mainly in case a buffer name is passed as an argument.
+            (hyrolo-file-list-initialize): Added this function so can
+    re-initialize the hyrolo-file-list later if BBDB or Google Contacts
+    support is loaded after the Hyperbole Rolo is initialized. 
+
+* hbut.el (hbut:source): Allowed for spaces in buffer names.
+
+* hyrolo.el (hyrolo-edit-entry): Avoided error if bbdb-file is nil.
+
+* hbut.el (ebut:label-p): Added one-line-flag to constrain label search to a 
single line.
+  hibtypes.el (Info-node): Constrained Info-node hyper-button matches to a 
single line.
+
+* hyrolo.el: Added support for Google Contacts when the google-contacts
+    package is in use and a public key package is available for Google
+    authorization.
 
 2016-09-08  Bob Weiner  <address@hidden>
 
diff --git a/HY-NEWS b/HY-NEWS
index e9ad7ce..877abe3 100644
--- a/HY-NEWS
+++ b/HY-NEWS
@@ -1,7 +1,7 @@
                          What's New in GNU Hyperbole
                                 by Bob Weiner
 
-          (See "ChangeLog" for more complete details of changes.)
+          (See "Changes" for more complete details of changes.)
 
 ===========================================================================
 *                                  V6.0.2
diff --git a/MANIFEST b/MANIFEST
index 7727f20..6810811 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -58,7 +58,6 @@ hyrolo-logic.el     - Logic functions for GNU Hyperbole Rolo 
files
 hywconfig.el        - Save ring of window configurations
 set.el              - General mathematical operators for unordered sets
 
-
 --- MAIL SYSTEM SUPPORT ---
 hmh.el              - GNU Hyperbole buttons in mail reader:   Mh
 hrmail.el           - GNU Hyperbole buttons in mail reader:   Rmail
diff --git a/hbut.el b/hbut.el
index a2c1807..deb3856 100644
--- a/hbut.el
+++ b/hbut.el
@@ -255,19 +255,21 @@ represent the output of particular document formatters."
                pos (1+ pos)))
        lbl)))
 
-(defun    ebut:label-p (&optional as-label start-delim end-delim pos-flag)
+(defun    ebut:label-p (&optional as-label start-delim end-delim pos-flag 
one-line-flag)
   "Returns key for Hyperbole button label that point is within.
-Returns nil if not within a label.
-Assumes point is within first line of button label, if at all.
-If optional AS-LABEL is non-nil, label is returned rather than the key
-derived from the label.  Optional START-DELIM and END-DELIM are strings
-that override default button delimiters.  With optional POS-FLAG non-nil,
-returns list of label-or-key, but-start-position, but-end-position.
-Positions include delimiters."
+Returns nil if not within a label.  Assumes point is within first line
+  of button label, if at all.
+All following arguments are optional.  If AS-LABEL is non-nil, label
+is returned rather than the key derived from the label.  START-DELIM
+and END-DELIM are strings that override default button delimiters.
+With POS-FLAG non-nil, returns list of label-or-key,
+but-start-position, but-end-position.  Positions include delimiters.
+With ONE-LINE-FLAG non-nil, constrains label search to a single line."
   (let ((opoint (point))
        (npoint)
        (quoted "\\(^\\|[^\\{]\\)")
        (start)
+       (ebut:max-len ebut:max-len)
        lbl-key end but-start but-end)
     (or start-delim (setq start-delim ebut:start))
     (or end-delim (setq end-delim ebut:end))
@@ -295,6 +297,10 @@ Positions include delimiters."
                  (forward-char -2))
              (error (goto-char (1- opoint))))
          (goto-char (1- opoint)))
+       (if one-line-flag
+           (save-excursion
+             (end-of-line)
+             (setq ebut:max-len (- (point) start))))
        (and (< (point) (+ start ebut:max-len))
             (re-search-forward (concat quoted (regexp-quote end-delim))
                                (+ start ebut:max-len) t)
@@ -386,7 +392,7 @@ expression which matches an entire button string."
   (let* ((regexp (symbolp end-delim))
         (end-sym (or regexp (substring end-delim -1)))
         (rtn)
-        (quoted)
+        (ignore)
         start end but lbl)
     (save-excursion
       (goto-char (point-min))
@@ -400,13 +406,16 @@ expression which matches an entire button string."
        (setq start (match-beginning include-delims)
              end (match-end include-delims)
              but (buffer-substring (match-beginning 0) (match-end 0))
-             lbl (buffer-substring (match-beginning 1) (match-end 1)))
+             lbl (buffer-substring (match-beginning 1) (match-end 1))
+             ;; If within a programming language buffer, ignore matches 
outside comments.
+             ignore (and (derived-mode-p 'prog-mode)
+                         ;; Match is outside of a programming language comment
+                         (not (nth 4 (syntax-ppss)))))
        (save-excursion
          (goto-char start)
-         (if (or (eq (preceding-char) ?\\) (eq (preceding-char) ?\{))
-             ;; Ignore matches with quoted delimiters.
-             (setq quoted t)))
-       (cond (quoted (setq quoted nil))
+         ;; Ignore matches with quoted delimiters.
+         (or ignore (setq ignore (memq (preceding-char) '(?\\ ?\{)))))
+       (cond (ignore (setq ignore nil))
              ((or (not regexp-match)
                   (string-match regexp-match but))
               (setq rtn (cons (funcall but-func lbl start end) rtn))))))
@@ -993,7 +1002,7 @@ Returns number of buttons reported on or nil if none."
   "Returns Hyperbole source buffer or file given at point.
 If a file, always returns a full path if optional FULL is non-nil."
   (goto-char (match-end 0))
-  (cond ((looking-at "#<buffer \"?\\([^ \n\"]+\\)\"?>")
+  (cond ((looking-at "#<buffer \"?\\([^\n\"]+\\)\"?>")
         (get-buffer (buffer-substring (match-beginning 1)
                                       (match-end 1))))
        ((looking-at "\".+\"")
diff --git a/hibtypes.el b/hibtypes.el
index 41ab6b0..33acc24 100644
--- a/hibtypes.el
+++ b/hibtypes.el
@@ -86,8 +86,9 @@ removed from pathname when searching for a valid match.
 See `hpath:find' function documentation for special file display options."
   ;;
   ;; Ignore paths in Buffer menu and dired modes.
-  (unless (delq nil (mapcar (lambda (substring) (string-match substring 
mode-name))
-                    '("Buffer Menu" "IBuffer" "Dired")))
+  (unless (delq nil (mapcar (lambda (substring) (string-match
+                                                substring (format-mode-line 
mode-name)))
+                           '("Buffer Menu" "IBuffer" "Dired")))
     (let ((path (hpath:at-p))
          full-path)
       (if path
@@ -605,74 +606,89 @@ Messages are recognized in any buffer."
 
 (defib debugger-source ()
   "Jumps to source line associated with stack frame or breakpoint lines.
-This works with JavaScript traces, gdb, dbx, and xdb.  Such lines are 
recognized in any buffer."
+This works with JavaScript and Python tracebacks, gdb, dbx, and xdb.  Such 
lines are recognized in any buffer."
   (save-excursion
     (beginning-of-line)
-    (cond  ((or (looking-at "[a-zA-Z0-9-:.()? ]+? +at \\([^() \t]+\\) (\\([^:, 
\t()]+\\):\\([0-9]+\\):\\([0-9]+\\))$")
-               (looking-at "[a-zA-Z0-9-:.()? ]+? +at\\( \\)\\([^:, 
\t()]+\\):\\([0-9]+\\):\\([0-9]+\\)$")
-               (looking-at "[a-zA-Z0-9-:.()? ]+?\\( \\)\\([^:, 
\t()]+\\):\\([0-9]+\\)\\(\\)$"))
-          ;; JavaScript traceback
-          (let* ((file (match-string-no-properties 2))
-                 (line-num (match-string-no-properties 3))
-                 (col-num (match-string-no-properties 4))
-                 but-label)
-
-            ;; For Meteor app errors, remove the "app/" prefix which
-            ;; is part of the build subdirectory and not part of the
-            ;; source tree.
-            (if (and (not (eq col-num "")) (string-match "^app/" file))
-                (setq file (substring file (match-end 0))))
-
-            (setq but-label (concat file ":" line-num)
-                  line-num (string-to-number line-num))
-            (ibut:label-set but-label)
-            (hact 'link-to-file-line file line-num)))
-          ((looking-at
-            ".+ \\(at\\|file\\) \\([^ :,]+\\)\\(:\\|, line 
\\)\\([0-9]+\\)\\.?$")
-          ;; GDB or WDB
-          (let* ((file (match-string-no-properties 2))
-                 (line-num (match-string-no-properties 4))
-                 (but-label (concat file ":" line-num))
-                 (gdb-last-file (or (and (boundp 'gud-last-frame)
-                                         (stringp (car gud-last-frame))
-                                         (car gud-last-frame))
-                                    (and (boundp 'gdb-last-frame)
-                                         (stringp (car gdb-last-frame))
-                                         (car gdb-last-frame)))))
-            (setq line-num (string-to-number line-num))
-            ;; The `file' typically has no directory component and so may
-            ;; not be resolvable.  `gdb-last-file' is the last file
-            ;; displayed by gdb.  Use its directory if available as a best
-            ;; guess.
-            (if gdb-last-file
-                (setq file (expand-file-name
-                            file (file-name-directory gdb-last-file))))
-            (ibut:label-set but-label)
-            (hact 'link-to-file-line file line-num)))
-          ((looking-at ".+ (file=[^\"\n\r]+\"\\([^\"\n\r]+\\)\", 
line=\\([0-9]+\\),")
-          ;; XEmacs assertion failure
-          (let* ((file (match-string-no-properties 1))
-                 (line-num (match-string-no-properties 2))
-                 (but-label (concat file ":" line-num)))
-            (setq line-num (string-to-number line-num))
-            (ibut:label-set but-label)
-            (hact 'link-to-file-line file line-num)))
-         ((looking-at ".+ line \\([0-9]+\\) in \"\\([^\"]+\\)\"$")
-          ;; New DBX
-          (let* ((file (match-string-no-properties 2))
-                 (line-num (match-string-no-properties 1))
-                 (but-label (concat file ":" line-num)))
-            (setq line-num (string-to-number line-num))
-            (ibut:label-set but-label)
-            (hact 'link-to-file-line file line-num)))
-         ((or (looking-at ".+ \\[\"\\([^\"]+\\)\":\\([0-9]+\\),") ;; Old DBX
-              (looking-at ".+ \\[\\([^: ]+\\): \\([0-9]+\\)\\]")) ;; HP-UX xdb
-          (let* ((file (match-string-no-properties 1))
-                 (line-num (match-string-no-properties 2))
-                 (but-label (concat file ":" line-num)))
-            (setq line-num (string-to-number line-num))
-            (ibut:label-set but-label)
-            (hact 'link-to-file-line file line-num))))))
+    (cond
+     ;; Python pdb
+     ((looking-at ".+ File \"\\([^\"\n\r]+\\)\", line \\([0-9]+\\)")
+      (let* ((file (match-string-no-properties 1))
+            (line-num (match-string-no-properties 2))
+            (but-label (concat file ":" line-num)))
+       (setq line-num (string-to-number line-num))
+       (ibut:label-set but-label (match-beginning 1) (match-end 1))
+       (hact 'link-to-file-line file line-num)))
+
+     ;; JavaScript traceback
+     ((or (looking-at "[a-zA-Z0-9-:.()? ]+? +at \\([^() \t]+\\) (\\([^:, 
\t()]+\\):\\([0-9]+\\):\\([0-9]+\\))$")
+         (looking-at "[a-zA-Z0-9-:.()? ]+? +at\\( \\)\\([^:, 
\t()]+\\):\\([0-9]+\\):\\([0-9]+\\)$")
+         (looking-at "[a-zA-Z0-9-:.()? ]+?\\( \\)\\([^:, 
\t()]+\\):\\([0-9]+\\)\\(\\)$"))
+      (let* ((file (match-string-no-properties 2))
+            (line-num (match-string-no-properties 3))
+            (col-num (match-string-no-properties 4))
+            but-label)
+
+       ;; For Meteor app errors, remove the "app/" prefix which
+       ;; is part of the build subdirectory and not part of the
+       ;; source tree.
+       (if (and (not (eq col-num "")) (string-match "^app/" file))
+           (setq file (substring file (match-end 0))))
+
+       (setq but-label (concat file ":" line-num)
+             line-num (string-to-number line-num))
+       (ibut:label-set but-label)
+       (hact 'link-to-file-line file line-num)))
+
+     ;; GDB or WDB
+     ((looking-at
+       ".+ \\(at\\|file\\) \\([^ :,]+\\)\\(:\\|, line \\)\\([0-9]+\\)\\.?$")
+      (let* ((file (match-string-no-properties 2))
+            (line-num (match-string-no-properties 4))
+            (but-label (concat file ":" line-num))
+            (gdb-last-file (or (and (boundp 'gud-last-frame)
+                                    (stringp (car gud-last-frame))
+                                    (car gud-last-frame))
+                               (and (boundp 'gdb-last-frame)
+                                    (stringp (car gdb-last-frame))
+                                    (car gdb-last-frame)))))
+       (setq line-num (string-to-number line-num))
+       ;; The `file' typically has no directory component and so may
+       ;; not be resolvable.  `gdb-last-file' is the last file
+       ;; displayed by gdb.  Use its directory if available as a best
+       ;; guess.
+       (if gdb-last-file
+           (setq file (expand-file-name
+                       file (file-name-directory gdb-last-file))))
+       (ibut:label-set but-label)
+       (hact 'link-to-file-line file line-num)))
+
+     ;; XEmacs assertion failure
+     ((looking-at ".+ (file=[^\"\n\r]+\"\\([^\"\n\r]+\\)\", 
line=\\([0-9]+\\),")
+      (let* ((file (match-string-no-properties 1))
+            (line-num (match-string-no-properties 2))
+            (but-label (concat file ":" line-num)))
+       (setq line-num (string-to-number line-num))
+       (ibut:label-set but-label)
+       (hact 'link-to-file-line file line-num)))
+
+     ;; New DBX
+     ((looking-at ".+ line \\([0-9]+\\) in \"\\([^\"]+\\)\"$")
+      (let* ((file (match-string-no-properties 2))
+            (line-num (match-string-no-properties 1))
+            (but-label (concat file ":" line-num)))
+       (setq line-num (string-to-number line-num))
+       (ibut:label-set but-label)
+       (hact 'link-to-file-line file line-num)))
+
+     ;; Old DBX and HP-UX xdb
+     ((or (looking-at ".+ \\[\"\\([^\"]+\\)\":\\([0-9]+\\),") ;; Old DBX
+         (looking-at ".+ \\[\\([^: ]+\\): \\([0-9]+\\)\\]")) ;; HP-UX xdb
+      (let* ((file (match-string-no-properties 1))
+            (line-num (match-string-no-properties 2))
+            (but-label (concat file ":" line-num)))
+       (setq line-num (string-to-number line-num))
+       (ibut:label-set but-label)
+       (hact 'link-to-file-line file line-num))))))
 
 ;;; ========================================================================
 ;;; Jumps to source of Emacs Lisp byte-compiler error messages.
@@ -903,13 +919,13 @@ GNUS is a news and mail reader."
 (defib Info-node ()
   "Makes \"(filename)nodename\" buttons display the associated Info node.
 Also makes \"(filename)itemname\" buttons display the associated Info index 
item."
-  (let* ((node-ref-and-pos (or (hbut:label-p t "\"" "\"" t)
+  (let* ((node-ref-and-pos (or (hbut:label-p t "\"" "\"" t t)
                               ;; Typical GNU Info references; note
                               ;; these are special quote marks, not the
                               ;; standard ASCII characters.
-                              (hbut:label-p t "‘" "’" t)
+                              (hbut:label-p t "‘" "’" t t)
                               ;; Regular open and close quotes
-                              (hbut:label-p t "`" "'" t)))
+                              (hbut:label-p t "`" "'" t t)))
         (node-ref (hpath:is-p (car node-ref-and-pos) nil t)))
     (and node-ref (string-match "\\`([^\):]+)" node-ref)
         (ibut:label-set node-ref-and-pos)
diff --git a/hmouse-tag.el b/hmouse-tag.el
index e41497e..830e991 100644
--- a/hmouse-tag.el
+++ b/hmouse-tag.el
@@ -795,16 +795,29 @@ If key is pressed:
 (defun smart-python-at-tag-p (&optional no-flash)
   "Return Python tag name that point is within, else nil."
   (let* ((identifier-chars "a-zA-Z0-9_")
-        (identifier (concat "[a-zA-Z_][" identifier-chars "]*")))
+        (identifier-fragment (concat "[a-zA-Z_][" identifier-chars "]*"))
+        (identifier (concat identifier-fragment "\\(\\."
+                            identifier-fragment "\\)*"))
+        start end tag)
     (save-excursion
-      (skip-chars-backward identifier-chars)
+      ;; Allow for name1.name2.module tags.
+      (while (and (/= (skip-chars-backward identifier-chars) 0)
+                 (/= (skip-chars-backward "\.") 0)))
+      (when (= (following-char) ?.)
+       (forward-char 1))
+      (setq start (point))
+      (while (and (/= (skip-chars-forward identifier-chars) 0)
+                 (/= (skip-chars-forward "\.") 0)))
+      (when (= (preceding-char) ?.)
+       (backward-char 1))
+      (setq end (point))
+      (goto-char start)
+      (setq tag (buffer-substring-no-properties start end))
       (if (and (looking-at identifier)
-              (not (member (downcase (match-string 0)) smart-python-keywords)))
+              (not (member (downcase tag) smart-python-keywords)))
          (if no-flash
-             (buffer-substring-no-properties (point) (match-end 0))
-           (smart-flash-tag
-            (buffer-substring-no-properties (point) (match-end 0))
-            (point) (match-end 0)))))))
+             tag
+           (smart-flash-tag tag start end))))))
 
 ;;; ************************************************************************
 ;;; Private functions
diff --git a/hpath.el b/hpath.el
index 2718b80..7e9a270 100644
--- a/hpath.el
+++ b/hpath.el
@@ -229,6 +229,7 @@ to create a path to the RFC document for `rfc-num'.")
 
 ;; WWW URL format:  [URL[:=]]<protocol>:/[<user>@]<domain>[:<port>][/<path>]
 ;;             or   [URL[:=]]<protocol>://[<user>@]<domain>[:<port>][<path>]
+;;             or   URL[:=][<user>@]<domain>[:<port>][<path>]  (no protocol 
specified)
 ;; Avoid [a-z]:/path patterns since these may be disk paths on OS/2, DOS or
 ;; Windows.
 (defvar hpath:url-regexp 
"<?\\(URL[:=]\\)?\\(\\([a-zA-Z][a-zA-Z]+\\)://?/?\\([^/:@ 
\t\n\r\"`'|address@hidden)?\\([^/:@ 
\t\n\r\"`'|]+\\)\\(\\)\\(:[0-9]+\\)?\\([/~]\\([^\]\[@ 
\t\n\r\"`'|(){}<>]+[^\]\[@ \t\n\r\"`'|(){}<>.,?#!*]\\)*\\)?\\)>?"
@@ -262,23 +263,39 @@ 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-regexp3
+  (concat
+   "<?\\(URL[:=]\\)\\(\\(\\)\\(\\)"
+   "\\([a-zA-Z0-9][^/:@ \t\n\r\"`'|]*\\.[^/:@ \t\n\r\"`'|]+\\)"
+   ":?\\([0-9]+\\)?\\([/~]\\([^\]\[@ \t\n\r\"`'|(){}<>]+[^\]\[@ 
\t\n\r\"`'|(){}<>.,?#!*]\\)*\\)?\\)>?")
+  "Regular expression which matches a Url in a string or buffer.
+  Its match groupings and their names are:
+  1 = hpath:url-keyword-grpn = required `URL:' or `URL=' literal
+  2 = hpath:url-grpn         = the whole URL
+  3 = unused                 = for compatibility with hpath:url-regexp
+  4 = unused                 = for compatibility with hpath:url-regexp
+  5 = hpath:sitename-grpn    = URL site to connect to
+  6 = hpath:hostname-grpn    = hostname used to determine the access protocol, 
e.g. ftp.domain.com
+  7 = hpath:portnumber-grpn  = optional port number to use
+  8 = hpath:pathname-grpn    = optional pathname to access.")
+
 (defconst hpath:url-keyword-grpn 1
-  "Optional `URL:' or `URL=' literal.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp2'.")
+  "Optional `URL:' or `URL=' literal.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:url-grpn 2
-  "The whole URL.  See doc for `hpath:url-regexp' and `hpath:url-regexp2'.")
+  "The whole URL.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:protocol-grpn 3
-  "Access protocol.  See doc for `hpath:url-regexp' and `hpath:url-regexp2'.")
+  "Access protocol.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:username-grpn 4
-  "Optional username.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp2'.")
+  "Optional username.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:sitename-grpn 5
-  "URL site to connect to.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp2'.")
+  "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.
-See doc for `hpath:url-regexp' and `hpath:url-regexp2'.")
+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-regexp2'.")
+  "Optional port number to use.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 (defconst hpath:pathname-grpn 8
-  "Optional pathname to access.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp2'.")
+  "Optional pathname to access.  See doc for `hpath:url-regexp' and 
`hpath:url-regexp[2,3]'.")
 
 (defvar hpath:string-url-regexp (concat "\\`" hpath:url-regexp "\\'")
   "Regular expression that matches to a string that contains a possibly 
delimited Url and nothing else.
@@ -290,6 +307,11 @@ use with string-match.")
 See the documentation for `hpath:url-regexp' for match groupings to
 use with string-match.")
 
+(defvar hpath:string-url-regexp3 (concat "\\`" hpath:url-regexp3 "\\'")
+  "Regular expression that matches to a string that contains a possibly 
delimited terse Url and nothing else.
+See the documentation for `hpath:url-regexp' for match groupings to
+use with string-match.")
+
 ;;; ************************************************************************
 ;;; Private variables
 ;;; ************************************************************************
@@ -307,7 +329,7 @@ use with string-match.")
   "Regexp that matches to a Markdown file suffix.")
 
 (defconst hpath:markup-link-anchor-regexp
- (concat "\\`\\(#?[^#]+\\)\\(#\\)\\([^\]\[#^{}<>\"`'\\\n\t\f\r]*\\)")
+  (concat "\\`\\(#?[^#]+\\)\\(#\\)\\([^\]\[#^{}<>\"`'\\\n\t\f\r]*\\)")
   "Regexp that matches an markup filename followed by a hash (#) and an 
optional in-file anchor name.")
 
 (defconst hpath:outline-section-pattern "^\*+[ \t]+%s\\([ \t[:punct:]]*\\)$"
@@ -365,7 +387,9 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
              (cond
               ((and (eq remote-package 'tramp)
                     ;; Remove match to bol in this regexp before testing.
-                    (looking-at (substring-no-properties (car 
tramp-file-name-structure) 1)))
+                    (looking-at (substring-no-properties (car (if (fboundp 
'tramp-file-name-structure)
+                                                                  
(tramp-file-name-structure)
+                                                                
tramp-file-name-structure)) 1)))
                (match-string-no-properties 0))
               ((looking-at hpath:url-regexp)
                (if (string-equal (match-string-no-properties 
hpath:protocol-grpn) "ftp")
@@ -384,7 +408,8 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                         (match-string-no-properties hpath:pathname-grpn)))
                  ;; else ignore this other type of WWW path
                  ))
-              ((looking-at hpath:url-regexp2)
+              ((or (looking-at hpath:url-regexp2)
+                   (looking-at hpath:url-regexp3))
                (if (string-equal (match-string-no-properties 
hpath:hostname-grpn) "ftp")
                    (concat
                     "/" user "@"
@@ -446,7 +471,8 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                          (match-string-no-properties hpath:pathname-grpn 
path)))
                   ;; else ignore this other type of WWW path
                   ))
-               ((string-match hpath:string-url-regexp2 path)
+               ((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))
                     (concat
                      "/" user "@"
@@ -459,30 +485,30 @@ Always returns nil if (hpath:remote-available-p) returns 
nil."
                          (match-string-no-properties hpath:pathname-grpn 
path)))
                   ;; else ignore this other type of WWW path
                   ))
-                ;; user, site and path
-                ((string-match "/?[^/:@ \t\n\r\"`'|address@hidden/:@ 
\t\n\r\"`'|]+:[^]@ \t\n\r\"`'|\)\}]*"
-                               path)
-                 (match-string-no-properties 0 path))
-                ;; @site and path
-                ((string-match "@[^/:@ \t\n\r\"`'|]+:[^]@ \t\n\r\"`'|\)\}]*"
-                               path)
-                 (concat "/" user (match-string-no-properties 0 path)))
-                ;; site and path
-                ((and (string-match
-                        "/?\\(\\([^/:@ \t\n\r\"`'|]+\\):[^]@:, 
\t\n\r\"`'|\)\}]*\\)"
-                        path)
-                      (setq result (match-string-no-properties 1 path))
-                      (string-match "[^.]\\.[^.]"
-                                    (match-string-no-properties 2 path)))
-                 (concat "/" user "@" result))
-                ;; host and path
-                ((and (string-match
-                        "/\\([^/:@ \t\n\r\"`'|]+:[^]@:, \t\n\r\"`'|\)\}]*\\)"
-                        path)
-                      (setq result (match-string-no-properties 1 path)))
-                 (concat "/" user "@" result))
-                ))
-       (hpath:delete-trailer result))))
+               ;; user, site and path
+               ((string-match "/?[^/:@ \t\n\r\"`'|address@hidden/:@ 
\t\n\r\"`'|]+:[^]@ \t\n\r\"`'|\)\}]*"
+                              path)
+                (match-string-no-properties 0 path))
+               ;; @site and path
+               ((string-match "@[^/:@ \t\n\r\"`'|]+:[^]@ \t\n\r\"`'|\)\}]*"
+                              path)
+                (concat "/" user (match-string-no-properties 0 path)))
+               ;; site and path
+               ((and (string-match
+                      "/?\\(\\([^/:@ \t\n\r\"`'|]+\\):[^]@:, 
\t\n\r\"`'|\)\}]*\\)"
+                      path)
+                     (setq result (match-string-no-properties 1 path))
+                     (string-match "[^.]\\.[^.]"
+                                   (match-string-no-properties 2 path)))
+                (concat "/" user "@" result))
+               ;; host and path
+               ((and (string-match
+                      "/\\([^/:@ \t\n\r\"`'|]+:[^]@:, \t\n\r\"`'|\)\}]*\\)"
+                      path)
+                     (setq result (match-string-no-properties 1 path)))
+                (concat "/" user "@" result))
+               ))
+        (hpath:delete-trailer result))))
 
 (defun hpath:at-p (&optional type non-exist)
   "Returns delimited path or non-delimited remote path at point, if any.
@@ -792,7 +818,7 @@ nonexistent local paths are allowed."
         ;; strip them, if any, before checking path.
         (if (string-match "\\`[^#][^#,]*\\([ \t\n\r]*[#,]\\)" path)
             (setq rtn-path (concat (substring path 0 (match-beginning 1))
-                                    "%s" (substring path (match-beginning 1)))
+                                   "%s" (substring path (match-beginning 1)))
                   path (substring path 0 (match-beginning 1)))
           (setq rtn-path (concat rtn-path "%s")))
         ;; If path is just a local reference that begins with #,
@@ -851,6 +877,12 @@ nonexistent local paths are allowed."
                             (file-directory-p path))
                            (t))))
               (progn
+                ;; Might be an encoded URL with % characters, so
+                ;; decode it before calling format below.
+                (when (string-match "%" rtn-path)
+                  (let (decoded-path)
+                    (while (not (equal rtn-path (setq decoded-path 
(hypb:decode-url rtn-path))))
+                      (setq rtn-path decoded-path))))
                 ;; Quote any %s except for one at the end of the path
                 ;; part of rtn-path (immediately preceding a # or ,
                 ;; character or the end of string).
@@ -866,19 +898,19 @@ nonexistent local paths are allowed."
                       (format rtn-path suffix))
                   (format rtn-path ""))))))))
 
-(defun hpath:push-tag-mark ()
-  "Add a tag return marker at point if within a programming language file 
buffer.
+        (defun hpath:push-tag-mark ()
+          "Add a tag return marker at point if within a programming language 
file buffer.
 Is a no-op if the function `push-tag-mark' is not available."
-  (and buffer-file-name
-       comment-start
-       (not (memq last-command
-                 '(xref-find-definitions find-tag find-tag-other-window 
tags-loop-continue)))
-       (or (and (fboundp 'xref-push-marker-stack)
-               ;; push old position
-               (xref-push-marker-stack))
-          (and (fboundp 'push-tag-mark)
-               ;; push old position
-               (push-tag-mark)))))
+          (and buffer-file-name
+               comment-start
+               (not (memq last-command
+                          '(xref-find-definitions find-tag 
find-tag-other-window tags-loop-continue)))
+               (or (and (fboundp 'xref-push-marker-stack)
+                        ;; push old position
+                        (xref-push-marker-stack))
+                   (and (fboundp 'push-tag-mark)
+                        ;; push old position
+                        (push-tag-mark)))))
 
 (defun hpath:relative-to (path &optional default-dir)
   "Returns PATH relative to optional DEFAULT-DIR or `default-directory'.
@@ -1148,7 +1180,8 @@ off otherwise."
 (defun hpath:url-at-p ()
   "Return world-wide-web universal resource locator (url) that point 
immediately precedes or nil.
 See the documentation for `hpath:url-regexp' for match-string groupings."
-  (if (or (looking-at hpath:url-regexp) (looking-at hpath:url-regexp2))
+  (if (or (looking-at hpath:url-regexp) (looking-at hpath:url-regexp2)
+         (looking-at hpath:url-regexp3))
       (save-excursion
        (goto-char (match-end hpath:url-grpn))
        (skip-chars-backward ".,?#!*()")
@@ -1160,7 +1193,8 @@ See the documentation for `hpath:url-regexp' for match 
groupings to
 use with string-match."
   (and (stringp obj)
        (or (string-match hpath:string-url-regexp obj)
-          (string-match hpath:string-url-regexp2 obj))
+          (string-match hpath:string-url-regexp2 obj)
+          (string-match hpath:string-url-regexp3 obj))
        t))
 
 (defun hpath:www-at-p (&optional include-start-and-end-p)
@@ -1171,7 +1205,8 @@ With optional INCLUDE-START-AND-END-P non-nil, returns 
list of:
     (skip-chars-backward "^\[ \t\n\r\f\"`'|\(\{<")
     (cond ((not include-start-and-end-p)
           (hpath:url-at-p))
-         ((or (looking-at hpath:url-regexp) (looking-at hpath:url-regexp2))
+         ((or (looking-at hpath:url-regexp) (looking-at hpath:url-regexp2)
+              (looking-at hpath:url-regexp3))
           (goto-char (match-end hpath:url-grpn))
           (skip-chars-backward ".,?#!*()")
           (list (buffer-substring-no-properties (match-beginning 
hpath:url-grpn) (point))
diff --git a/hsettings.el b/hsettings.el
index 37a26cc..eb462c8 100644
--- a/hsettings.el
+++ b/hsettings.el
@@ -56,9 +56,17 @@
       ))
 
 ;;; ************************************************************************
-;;; SMART SETTINGS
+;;; SMART SETTINGS FOR THE ACTION AND ASSIST KEYS AND SMART MENUS
 ;;; ************************************************************************
 
+;; The following setting allows direct selection of Helm completion
+;; entries with the Smart Mouse Keys.  Otherwise, by default, helm
+;; disables all mouse keys while completing.  If you change this
+;; setting (simply comment it out), you must restart Emacs for it to
+;; take full effect.  Setting this to 't' or 'nil' will not provide
+;; Hyperbole support.
+(eval-after-load "helm" '(setq helm-allow-mouse 'no-mode-bindings))
+
 ;; The Smart Menu system is an attractive in-buffer menu system that
 ;; predates Emacs menu systems; it is included in InfoDock.
 (defvar hkey-always-display-menu nil
diff --git a/hsys-www.el b/hsys-www.el
index 7f36bf0..38e3557 100644
--- a/hsys-www.el
+++ b/hsys-www.el
@@ -35,17 +35,49 @@
 ;;; Public functions and types
 ;;; ************************************************************************
 
+;; eww-mode should define these next functions but presently does not,
+;; so define them here when needed.
+(unless (fboundp 'eww-at-link)
+  (defun eww-at-link ()
+    "Return any eww web page hyperlink url at point or nil if none."
+    (get-text-property (point) 'shr-url))
+  (defun eww-bookmark-property (property)
+    "Return the value of PROPERTY, a symbol, for the current eww bookmark line 
or nil."
+    (if (eq major-mode 'eww-bookmark-mode)
+       (plist-get (get-text-property (line-beginning-position) 'eww-bookmark) 
property)))
+  (defun eww-history-property (property)
+    "Return the value of PROPERTY, a symbol, for the current eww history line 
or nil."
+    (if (eq major-mode 'eww-history-mode)
+       (plist-get (get-text-property (line-beginning-position) 'eww-history) 
property))))
+
 (defib www-url ()
   "Follow any non-ftp url (link) at point.
 The variable, `browse-url-browser-function', customizes the url browser that
 is used.
 Valid values of this variable include `browse-url-default-browser' and
 `browse-url-generic'."
-  (let ((link-and-pos (hpath:www-at-p t)))
-    ;; Skip ftp URLs which are handled elsewhere.
-    (if (and link-and-pos (not (hpath:remote-at-p)))
-       (progn (ibut:label-set link-and-pos)
-              (hact 'www-url (car link-and-pos))))))
+  (cond ((looking-at "\\s-*\\'")
+        ;; Don't match if at the end of the buffer; end of line is
+        ;; handled elsewhere.
+        nil)
+       ((and (eq major-mode 'eww-mode) (eww-at-link))
+        (ibut:label-set (eww-at-link))
+        (hact 'eww-follow-link))
+       ((eq major-mode 'eww-bookmark-mode)
+        (ibut:label-set (concat (eww-bookmark-property :title)
+                                (if (eww-bookmark-property :url)
+                                    (concat " <" (eww-bookmark-property :url) 
">"))))
+        (hact 'eww-bookmark-browse))
+       ((eq major-mode 'eww-history-mode)
+        (ibut:label-set (concat (eww-history-property :title)
+                                (if (eww-history-property :url)
+                                    (concat " <" (eww-history-property :url) 
">"))))
+        (hact 'eww-history-browse))
+       (t (let ((link-and-pos (hpath:www-at-p t)))
+            ;; Skip ftp URLs which are handled elsewhere.
+            (if (and link-and-pos (not (hpath:remote-at-p)))
+                (progn (ibut:label-set link-and-pos)
+                       (hact 'www-url (car link-and-pos))))))))
 
 (defact www-url (url)
   "Follow a link given by URL.
@@ -56,13 +88,12 @@ is used.  Valid values of this variable include 
`browse-url-default-browser' and
   (or (stringp url)
       (error "(www-url): URL = `%s' but must be a string" url))
   (if (or (functionp browse-url-browser-function)
-          ;; May be a predicate alist of functions from which to select
-          (consp browse-url-browser-function))
+         ;; May be a predicate alist of functions from which to select
+         (consp browse-url-browser-function))
       (let (browse-function-name
            browser)
        (if (symbolp browse-url-browser-function)
-           (setq browse-function-name
-                 (symbol-name browse-url-browser-function)
+           (setq browse-function-name (symbol-name browse-url-browser-function)
                  browser (and (string-match
                                "-\\([^-]+\\)\\'"
                                browse-function-name)
diff --git a/hui-em-but.el b/hui-em-but.el
index fe1a9ba..2608445 100644
--- a/hui-em-but.el
+++ b/hui-em-but.el
@@ -46,6 +46,11 @@
 ;;; Public variables
 ;;; ************************************************************************
 
+(defcustom hproperty:but-highlight-p t
+  "*Non-nil (default value) means highlight all explict buttons with 
`hproperty:but-face'."
+  :type 'boolean
+  :group 'hyperbole-buttons)
+
 (defcustom hproperty:but-emphasize-p nil
   "*Non-nil means visually emphasize that button under mouse cursor is 
selectable."
   :type 'boolean
@@ -118,9 +123,10 @@ If END-DELIM is a symbol, e.g. t, then START-DELIM is 
taken as a regular
 expression which matches an entire button string.
 If REGEXP-MATCH is non-nil, only buttons matching this argument are
 highlighted."
-  (ebut:map (lambda (lbl start end)
-             (hproperty:but-add start end hproperty:but-face))
-           start-delim end-delim regexp-match 'include-delims))
+  (when hproperty:but-highlight-p
+    (ebut:map (lambda (lbl start end)
+               (hproperty:but-add start end hproperty:but-face))
+             start-delim end-delim regexp-match 'include-delims)))
               
 (defun hproperty:but-delete (&optional pos)
   (let ((but (hproperty:but-get pos)))
diff --git a/hui-menu.el b/hui-menu.el
index 930e4b8..16b387c 100644
--- a/hui-menu.el
+++ b/hui-menu.el
@@ -35,10 +35,7 @@
           :style radio
           :selected (eq ,browser-option #'browse-url-chromium)]
          ["Default (System wide)"
-          (setq ,browser-option
-               (if (and (boundp 'browse-url-generic-program) (stringp 
browse-url-generic-program))
-                   #'browse-url-generic
-                 #'browse-url-default-browser))
+          (setq ,browser-option #'browse-url-default-browser)
           :style radio
           :selected (eq ,browser-option #'browse-url-default-browser)]
          ["EWW (Emacs)"
diff --git a/hui-mouse.el b/hui-mouse.el
index 705c367..186fb4b 100644
--- a/hui-mouse.el
+++ b/hui-mouse.el
@@ -88,6 +88,10 @@ Its default value is #'smart-scroll-down."
     ((and (fboundp 'button-at) (button-at (point))) .
      ((push-button) . (smart-push-button-help)))
     ;;
+    ;; Direct access selection of helm-major-mode completions
+    ((and (eq major-mode 'helm-major-mode) (smart-helm-line-has-action)) .
+     ((smart-helm) . (smart-helm-assist)))
+    ;;
     ;; If click in the minibuffer and reading an argument,
     ;; accept argument or give completion help.
     ((and (> (minibuffer-depth) 0)
@@ -118,9 +122,9 @@ Its default value is #'smart-scroll-down."
      ((xref-goto-xref) . (xref-show-location-at-point)))
     ;;
     ((if (eq major-mode 'kotl-mode)
-       (and (not (kotl-mode:eobp)) (kotl-mode:eolp))
-      (and (not (eobp)) (or (eolp) (and selective-display (eq (following-char) 
?\r))))) .
-     ((funcall action-key-eol-function) . (funcall assist-key-eol-function)))
+        (and (not (kotl-mode:eobp)) (kotl-mode:eolp))
+       (and (not (eobp)) (or (eolp) (and selective-display (eq 
(following-char) ?\r))))) .
+       ((funcall action-key-eol-function) . (funcall assist-key-eol-function)))
     ;;
     ;; The Smart Menu system provides menus within Emacs on a dumb terminal.
     ;; It is a part of InfoDock, but may also be obtained as a separate
@@ -244,17 +248,18 @@ Its default value is #'smart-scroll-down."
          (smart-javascript-at-tag-p)) .
      ((smart-javascript) . (smart-javascript nil 'next-tag)))
     ;;
-    ((and (eq major-mode 'python-mode) buffer-file-name
+    ((and (or (and (eq major-mode 'python-mode) buffer-file-name)
+             (string-match "^Pydoc:\\|\\*?Python" (buffer-name)))
          (smart-python-at-tag-p)) .
-         ((smart-python) . (smart-python nil 'next-tag)))
+     ((smart-python) . (smart-python nil 'next-tag)))
     ;;
     ((and (eq major-mode 'objc-mode) buffer-file-name
          (smart-objc-at-tag-p)) .
-         ((smart-objc) . (smart-objc nil 'next-tag)))
+     ((smart-objc) . (smart-objc nil 'next-tag)))
     ;;
     ((and (memq major-mode '(fortran-mode f90-mode))
          buffer-file-name (smart-fortran-at-tag-p)) .
-         ((smart-fortran) . (smart-fortran nil 'next-tag)))
+     ((smart-fortran) . (smart-fortran nil 'next-tag)))
     ;;
     ((eq major-mode 'occur-mode) .
      ((occur-mode-goto-occurrence) . (occur-mode-goto-occurrence)))
@@ -279,7 +284,7 @@ Its default value is #'smart-scroll-down."
     ((if (boundp 'hmail:reader)
         (or (eq major-mode hmail:reader)
             (eq major-mode hmail:lister))) .
-            ((smart-hmail) . (smart-hmail-assist)))
+     ((smart-hmail) . (smart-hmail-assist)))
     ;;
     ((eq major-mode 'gnus-group-mode)
      (smart-gnus-group) . (smart-gnus-group-assist))
@@ -301,15 +306,13 @@ Its default value is #'smart-scroll-down."
     ;;
     ;; Follow references in man pages.
     ((setq hkey-value (smart-man-entry-ref)) .
-     ((smart-man-display hkey-value) .
-      (smart-man-display hkey-value)))
+     ((smart-man-display hkey-value) . (smart-man-display hkey-value)))
     ;;
     ((eq major-mode 'w3-mode) . 
      ((w3-follow-link) . (w3-goto-last-buffer)))
     ;;
-    ((if (boundp 'hyrolo-display-buffer)
-        (equal (buffer-name) hyrolo-display-buffer)) .
-        ((smart-hyrolo) . (smart-hyrolo-assist)))
+    ((and (boundp 'hyrolo-display-buffer) (equal (buffer-name) 
hyrolo-display-buffer)) .
+     ((smart-hyrolo) . (smart-hyrolo-assist)))
     ;;
     ;; Gomoku game
     ((eq major-mode 'gomoku-mode) . 
@@ -325,10 +328,13 @@ Its default value is #'smart-scroll-down."
     ((and (boundp 'outline-minor-mode) outline-minor-mode) .
      ((smart-outline) . (smart-outline-assist)))
     )
-  "Alist of predicates and form-conses for Action and Assist Keys.
+  "Alist of predicates and form-conses for the Action and Assist Keyboard Keys.
 Each element is: (predicate-form . (action-key-form . assist-key-form)).
 When the Action or Assist Key is pressed, the first or second form,
-respectively, associated with the first non-nil predicate is evaluated.")
+respectively, associated with the first non-nil predicate is evaluated.
+
+See also `hmouse-alist' for a superset of this list utilized by the
+Action and Assist Mouse Keys.")
 
 ;;; ************************************************************************
 ;;; driver code
@@ -341,10 +347,13 @@ respectively, associated with the first non-nil predicate 
is evaluated.")
 (require 'hargs)
 (require 'hmouse-key)
 (defvar hmouse-alist hkey-alist
-  "Alist of predicates and form-conses for context-sensitive smart key mouse 
actions.
-When the action-key or the assist-key is pressed, the first or second
+  "Alist of predicates and form-conses for the Action and Assist Mouse Keys.
+When the Action Mouse Key or Assist Mouse Key is pressed, the first or second
 form, respectively, associated with the first non-nil predicate is
-evaluated.")
+evaluated.
+
+The `hkey-alist' variable is the subset of this alist used by the
+smart keyboard keys.")
 (load "hui-window")
 
 ;;; ************************************************************************
@@ -385,6 +394,43 @@ evaluated.")
       ref)))
 
 ;;; ************************************************************************
+;;; smart-helm functions
+;;; ************************************************************************
+
+(defun smart-helm-line-has-action ()
+  "Return the current helm selection item or nil if line lacks an associated 
action.
+Assume Hyperbole has already checked that point is in a helm completion 
buffer."
+  (let* ((helm-buffer (buffer-name))
+        (selection (helm-get-selection)))
+    (and (listp selection) selection)))
+
+(defun smart-helm()
+  "Selects and executes the helm line at point."
+  (let ((helm-buffer (buffer-name))
+       (helm-alive-p t))
+    (with-helm-window
+      (setq cursor-type t)
+      (helm-mark-current-line)
+      ;; Hyperbole has checked that this line has an action prior
+      ;; to invoking this function.
+      (helm-execute-persistent-action))
+    (if (> (minibuffer-depth) 0)
+       (select-window (minibuffer-window)))))
+
+(defun smart-helm-assist()
+  "Displays the selected item (including its action for the helm line at 
point."
+  (let* ((helm-buffer (buffer-name))
+        (selection (helm-get-selection)))
+    (with-helm-window
+      (setq cursor-type t)
+      (helm-mark-current-line)
+      (with-help-window "*Helm Help*"
+       (princ "The current helm selection item is:\n")
+       (print selection)))
+    (if (> (minibuffer-depth) 0)
+       (select-window (minibuffer-window)))))
+
+;;; ************************************************************************
 ;;; smart-buffer-menu functions
 ;;; ************************************************************************
 
@@ -410,7 +456,7 @@ If key is pressed:
   (cond ((last-line-p) (Buffer-menu-execute))
        ((bolp) (Buffer-menu-mark))
         ((save-excursion
-             (goto-char (1- (point)))
+            (goto-char (1- (point)))
             (bolp))
         (Buffer-menu-save))
        ((br-in-browser) (br-buffer-menu-select))
@@ -466,7 +512,7 @@ If key is pressed:
        ((or (bolp) (save-excursion
                      (goto-char (1- (point)))
                      (bolp)))
-        (ibuffer-mark-forward 1))
+        (ibuffer-mark-forward nil nil 1))
        ((br-in-browser) (br-buffer-menu-select))  
        (t (ibuffer-do-view))))
 
@@ -487,12 +533,14 @@ If assist-key is pressed:
 
   (interactive)
   (cond ((or (first-line-p) (last-line-p))
-        (ibuffer-unmark-all 0))
+        (if (fboundp 'ibuffer-unmark-all-marks)
+            (ibuffer-unmark-all-marks)
+          (ibuffer-unmark-all 0)))
        ((or (bolp) (save-excursion
                      (goto-char (1- (point)))
                      (bolp)))
-        (ibuffer-unmark-forward 1))
-       (t (ibuffer-mark-for-delete 1))))
+        (ibuffer-unmark-forward nil nil 1))
+       (t (ibuffer-mark-for-delete nil nil 1))))
 
 ;;; ************************************************************************
 ;;; smart-calendar functions
diff --git a/hui-xe-but.el b/hui-xe-but.el
index 35501f9..dcde64a 100644
--- a/hui-xe-but.el
+++ b/hui-xe-but.el
@@ -44,6 +44,11 @@
 ;;; Public variables
 ;;; ************************************************************************
 
+(defcustom hproperty:but-highlight-p t
+  "*Non-nil (default value) means highlight all explict buttons with 
`hproperty:but-face'."
+  :type 'boolean
+  :group 'hyperbole-buttons)
+
 (defcustom hproperty:but-emphasize-p nil
   "*Non-nil means visually emphasize that button under mouse cursor is 
selectable."
   :type 'boolean
@@ -107,10 +112,11 @@ If END-DELIM is a symbol, e.g. t, then START-DELIM is 
taken as a regular
 expression which matches an entire button string.
 If REGEXP-MATCH is non-nil, only buttons matching this argument are
 highlighted."
-  (ebut:map (lambda (lbl start end)
-             (hproperty:but-add start end hproperty:but-face))
-           start-delim end-delim regexp-match 'include-delims))
-              
+  (when hproperty:but-highlight-p
+    (ebut:map (lambda (lbl start end)
+               (hproperty:but-add start end hproperty:but-face))
+             start-delim end-delim regexp-match 'include-delims)))
+
 (defun hproperty:but-delete (&optional pos)
   (let ((extent (extent-at (or pos (point)))))
     (if extent (delete-extent extent))))
diff --git a/hypb.el b/hypb.el
index 466fc72..0244267 100644
--- a/hypb.el
+++ b/hypb.el
@@ -155,6 +155,31 @@ Global keymap is used unless optional KEYMAP is given."
       (load "hbut.el"))
   (setq debug-on-error t))
 
+;; Copied from eww.el so as to not require that package.
+(defun hypb:decode-url (string)
+  (let* ((binary (url-unhex-string string))
+         (decoded
+          (decode-coding-string
+           binary
+           ;; Possibly set by `universal-coding-system-argument'.
+           (or coding-system-for-read
+               ;; RFC 3986 says that %AB stuff is utf-8.
+               (if (equal (decode-coding-string binary 'utf-8)
+                          '(unicode))
+                   'utf-8
+                 ;; But perhaps not.
+                 (car (detect-coding-string binary))))))
+         (encodes (find-coding-systems-string decoded)))
+    (if (or (equal encodes '(undecided))
+            (memq (coding-system-base (or file-name-coding-system
+                                          default-file-name-coding-system))
+                  encodes))
+        decoded
+      ;; If we can't encode the decoded file name (due to language
+      ;; environment settings), then we return the original, hexified
+      ;; string.
+      string)))
+
 (defun hypb:domain-name ()
   "Returns current Internet domain name with '@' prepended or nil if none."
   (let* ((dname-cmd (or (file-exists-p "/usr/bin/domainname")
diff --git a/hyperbole.el b/hyperbole.el
index 09afda4..5ac5f6a 100644
--- a/hyperbole.el
+++ b/hyperbole.el
@@ -346,7 +346,7 @@ bindings after load)."
              (add-to-list 'Info-directory-list info-dir)))))
 
 ;;; ************************************************************************
-;;; Prevent local key maps from hiding the Action Key (overriding it)
+;;; Prevent local key maps from hiding/overriding the Action and Assist Keys
 ;;; ************************************************************************
 
 ;; (defun hkey-read-only-bindings ()
@@ -377,16 +377,16 @@ bindings after load)."
     (if hkey-init-override-local-keys
        (let (hkey
              binding)
-        (mapc (lambda (descrip-key-cmd)
-                (and (setq hkey (cadr descrip-key-cmd))
-                     ;; To see the key name, use: (key-description hkey)
-                     (setq binding (local-key-binding hkey))
-                     ;; A number indicates an invalid key prefix, so
-                     ;; there is not actually a local binding for
-                     ;; this key sequence.
-                     (not (numberp binding))
-                     (local-unset-key hkey)))
-              hkey-previous-bindings)))))
+         (mapc (lambda (descrip-key-cmd)
+                 (and (setq hkey (cadr descrip-key-cmd))
+                      ;; To see the key name, use: (key-description hkey)
+                      (setq binding (local-key-binding hkey))
+                      ;; A number indicates an invalid key prefix, so
+                      ;; there is not actually a local binding for
+                      ;; this key sequence.
+                      (not (numberp binding))
+                      (local-unset-key hkey)))
+               hkey-previous-bindings)))))
 
 (defun hkey-install-override-local-bindings ()
   ;; Run after any major-mode change within any buffer.
diff --git a/hyrolo.el b/hyrolo.el
index 57711df..acc5057 100644
--- a/hyrolo.el
+++ b/hyrolo.el
@@ -24,6 +24,8 @@
 (eval-when-compile
   (unless (require 'bbdb nil t)
     (defvar bbdb-file nil))
+  (unless (require 'google-contacts nil t)
+    (defvar google-contacts-buffer-name nil))
   (defvar next-entry-exists nil))
 
 ;;; ************************************************************************
@@ -40,7 +42,10 @@ See documentation of the function `format-time-string' for 
format options."
   :type 'string
   :group 'hyperbole-rolo)
 
-(defvar hyrolo-display-format-function 'identity
+(defvar hyrolo-display-format-function
+  ;; Set trailing newlines to exactly two.
+  (lambda (entry)
+    (concat (replace-in-string entry "[ \t\n\r]+\\'" "") "\n\n"))
   "*Function of one argument, a rolo entry string, which modifies the string 
for display.")
 
 (defcustom hyrolo-email-format "%s\t\t<%s>"
@@ -50,12 +55,31 @@ It must contain a %s indicating where to put the entry name 
and a second
   :type 'string
   :group 'hyperbole-rolo)
 
-(defvar hyrolo-file-list
-  (if (and (boundp 'bbdb-file) (stringp bbdb-file))
-      (if hyperb:microcruft-os-p
-         (list "c:/_rolo.otl" bbdb-file)
-       (list  "~/.rolo.otl" bbdb-file))
-    (if hyperb:microcruft-os-p '("c:/_rolo.otl") '("~/.rolo.otl")))
+(defcustom hyrolo-google-contacts-flag t
+  "*Non-nil means search Google Contacts on each hyrolo query.
+The google-contact package must be loaded and a gpg encryption
+executable must be found as well (for Oauth security)."
+  :type 'boolean
+  :group 'hyperbole-rolo)
+
+(defun hyrolo-google-contacts-p ()
+  "Return non-nil if google-contacts package and gpg executables are available 
for use."
+  (and hyrolo-google-contacts-flag
+       (featurep 'google-contacts) 
+       ;; If no gpg encryption executable, Oauth login to Google will fail.
+       (or (executable-find "gpg2") (executable-find "gpg"))))
+
+(defun hyrolo-file-list-initialize ()
+  (let ((gcontacts (if (hyrolo-google-contacts-p) google-contacts-buffer-name))
+       (ms "c:/_rolo.otl")
+       (unix "~/.rolo.otl"))
+    (delq nil (if (and (boundp 'bbdb-file) (stringp bbdb-file))
+                 (if hyperb:microcruft-os-p
+                     (list ms bbdb-file gcontacts)
+                   (list  "~/.rolo.otl" bbdb-file gcontacts))
+               (if hyperb:microcruft-os-p (list ms gcontacts) (list unix 
gcontacts))))))
+
+(defvar hyrolo-file-list (hyrolo-file-list-initialize)
   "*List of files containing rolo entries.
 The first file should be a user-specific rolo file, typically in the home
 directory.
@@ -310,11 +334,14 @@ Returns entry name if found, else nil."
        src)
     (if name
        (progn (setq src (hbut:key-src))
-              (if (and (boundp 'bbdb-file) (equal src (expand-file-name 
bbdb-file)))
-                  ;; For now, can't edit the bbdb database, signal an error.
-                  (error "(hyrolo-edit-entry): BBDB entries are not editable.")
-                (hyrolo-edit name src)
-                name))
+              (cond ((and (boundp 'bbdb-file) (stringp bbdb-file) (equal src 
(expand-file-name bbdb-file)))
+                     ;; For now, can't edit an entry from the bbdb database, 
signal an error.
+                     (error "(hyrolo-edit-entry): BBDB entries are not 
editable."))
+                    ((and (featurep 'google-contacts) (equal src (get-buffer 
google-contacts-buffer-name)))
+                     ;; For now, can't edit an entry from Google Contacts, 
signal an error.
+                     (error "(hyrolo-edit-entry): Google Contacts entries are 
not editable."))
+                    (t (hyrolo-edit name src)
+                       name)))
       (error "(hyrolo-edit-entry): Move to an entry to edit it."))))
 
 ;;;###autoload
@@ -384,9 +411,12 @@ hyrolo-file-list."
                (or (not (integerp max-matches))
                    (< total-matches (max max-matches (- max-matches)))))
       (setq hyrolo-file-list (cdr hyrolo-file-list)
-           num-matched (if (and (featurep 'bbdb) (equal file bbdb-file))
-                           (hyrolo-bbdb-grep-file file regexp max-matches 
count-only)
-                         (hyrolo-grep-file file regexp max-matches count-only))
+           num-matched (cond ((and (featurep 'bbdb) (equal file bbdb-file))
+                              (hyrolo-bbdb-grep-file file regexp max-matches 
count-only))
+                             ((and (hyrolo-google-contacts-p) (equal file 
google-contacts-buffer-name))
+                              (hyrolo-retrieve-google-contacts (regexp-quote 
regexp))
+                              (hyrolo-google-contacts-grep-file file regexp 
max-matches count-only))
+                             (t (hyrolo-grep-file file regexp max-matches 
count-only)))
            total-matches (+ total-matches num-matched))
       (if (integerp max-matches)
          (setq max-matches
@@ -440,7 +470,7 @@ NAME may be of the form: parent/child to kill child below a 
parent entry
 which begins with the parent string.
 Returns t if entry is killed, nil otherwise."
   (interactive "sKill rolo entry named: \nP")
-  (if (or (not (stringp name)) (string= name ""))
+  (if (or (not (stringp name)) (string= name "") (string-match "\\*" name))
       (error "(hyrolo-kill): Invalid name: `%s'" name))
   (if (and (called-interactively-p 'interactive) current-prefix-arg)
       (setq file (completing-read "Entry's File: "
@@ -751,14 +781,14 @@ of a string."
 
 ;;;###autoload
 (defun hyrolo-bbdb-fgrep (&optional arg)
-  "Fgrep over a BBDB database and format the results as rolo entries.
+  "Fgrep over a bbdb database and format the results as rolo entries.
 With optional prefix ARG, do a grep regexp match instead of a string match."
   (interactive "P")
   (hyrolo-bbdb-grep (not arg)))
 
 ;;;###autoload
 (defun hyrolo-bbdb-grep (&optional arg)
-  "Grep over a BBDB database and format the results as rolo entries.
+  "Grep over a bbdb database and format the results as rolo entries.
 With optional prefix ARG, do an fgrep string match instead of a regexp match.
 
 Output looks like so:
@@ -803,6 +833,178 @@ Returns number of matching entries found."
     (format "* %s: %s: <%s>\n" (elt v 1) (elt v 0) (car (elt v 7)))))
 
 ;;; ************************************************************************
+;;; Google Contacts Integration
+;;; ************************************************************************
+
+;;;###autoload
+(defun hyrolo-google-contacts-fgrep (&optional arg)
+  "Fgrep over a buffer of Google Contacts and format the results as rolo 
entries.
+With optional prefix ARG, do a grep regexp match instead of a string match."
+  (interactive "P")
+  (hyrolo-google-contacts-grep (not arg)))
+
+;;;###autoload
+(defun hyrolo-google-contacts-grep (&optional arg)
+  "Grep over a buffer of Google Contacts and format the results as rolo 
entries.
+With optional prefix ARG, do an fgrep string match instead of a regexp match.
+
+Output looks like so:
+======================================================================
address@hidden> <buffer *Google Contacts*>
+======================================================================
+* Jones     Tom
+* Sera      Kate
+* Yako      Maso"
+  (interactive "P")
+  (require 'google-contacts)
+  (let ((hyrolo-file-list (list google-contacts-buffer-name))
+       ;; Kill the google-contacts buffer after use if it is not already in 
use.
+       (hyrolo-kill-buffers-after-use (not (get-buffer 
google-contacts-buffer-name))))
+    (call-interactively (if arg 'hyrolo-fgrep 'hyrolo-grep))
+    (read-only-mode 0)
+    (re-search-forward rolo-entry-regexp nil t)
+    (beginning-of-line)
+    (set-buffer-modified-p nil)
+    (read-only-mode 1)))
+
+(defun hyrolo-google-contacts-grep-file (hyrolo-file-or-buf regexp &optional 
max-matches count-only)
+  "Retrieve entries in google-contacts HYROLO-FILE-OR-BUF matching REGEXP to a 
maximum of optional MAX-MATCHES.
+Nil value of MAX-MATCHES means find all matches, t value means find all matches
+but omit file headers, negative values mean find up to the inverse of that
+number of entries and omit file headers.  Optional COUNT-ONLY non-nil
+means don't retrieve matching entries.
+Returns number of matching entries found."
+  ;; Kill the google-contacts buffer after use if it is not already in use.
+  (let ((hyrolo-kill-buffers-after-use (not (get-buffer 
google-contacts-buffer-name))))
+    (hyrolo-grep-file hyrolo-file-or-buf regexp max-matches count-only)))
+
+;; Derived from google-contacts.el.
+(defun hyrolo-google-contacts-insert-data (contacts token 
contact-prefix-string)
+  (if (not contacts)
+      ;; No contacts, insert a string and return nil
+      (insert "No result.")
+    (print contacts (get-buffer-create "*contacts-data*"))
+    (dolist (contact contacts)
+      (let* ((name-value (nth 0 (xml-get-children contact 'gd:name)))
+             (fullname (xml-node-child-string (nth 0 (xml-get-children 
name-value 'gd:fullName))))
+             (givenname (xml-node-child-string (nth 0 (xml-get-children 
name-value 'gd:givenName))))
+             (familyname (xml-node-child-string (nth 0 (xml-get-children 
name-value 'gd:familyName))))
+
+             (nickname (xml-node-child-string (nth 0 (xml-get-children contact 
'gContact:nickname))))
+             (birthday (xml-get-attribute-or-nil (nth 0 (xml-get-children 
contact 'gContact:birthday)) 'when))
+
+             (organization-value (nth 0 (xml-get-children contact 
'gd:organization)))
+             (organization-name (xml-node-child-string (nth 0 
(xml-get-children organization-value 'gd:orgName))))
+             (organization-title (xml-node-child-string (nth 0 
(xml-get-children organization-value 'gd:orgTitle))))
+
+             (notes (xml-node-child-string (nth 0 (xml-get-children contact 
'content))))
+             ;; Links
+             (links (xml-get-children contact 'link))
+
+             ;; Multiple values
+             ;; Format is ((rel-type . data) (rel-type . data) … )
+             (events (google-contacts-build-node-list contact 'gContact:event
+                                                      (xml-get-attribute (nth 
0 (xml-get-children child 'gd:when)) 'startTime)))
+             (emails (google-contacts-build-node-list contact 'gd:email
+                                                      (xml-get-attribute child 
'address)))
+             (phones (google-contacts-build-node-list contact 'gd:phoneNumber))
+             (websites (google-contacts-build-node-list contact 
'gContact:website
+                                                        (xml-get-attribute 
child 'href)))
+             (relations (google-contacts-build-node-list contact 
'gContact:relation))
+             (postal-addresses (google-contacts-build-node-list contact 
'gd:structuredPostalAddress
+                                                                
(xml-node-child-string
+                                                                 (nth 0 
(xml-get-children child 'gd:formattedAddress)))))
+             (instant-messaging (google-contacts-build-node-list contact 'gd:im
+                                                                 (cons
+                                                                  
(xml-node-get-attribute-type child 'protocol)
+                                                                  (cdr (assoc 
'address (xml-node-attributes child))))))
+             (beg (point)))
+        (unless (and (string= familyname "") (string= givenname "") (string= 
nickname ""))
+         (insert contact-prefix-string familyname (if (or (string= familyname 
"")
+                                                          (string= givenname 
"")) "" ", ")
+                 givenname
+                 (if (string= nickname "")
+                     ""
+                   (format " (%s)" nickname))
+                 "\n"))
+
+        (unless (and (string= organization-name "")
+                     (string= organization-title ""))
+         (insert (google-contacts-margin-element))
+         (if (string= organization-title "")
+             (insert organization-name "\n")
+           (insert organization-title " @ " organization-name "\n")))
+
+        (hyrolo-google-contacts-insert-generic-list emails "E-mails")
+        (hyrolo-google-contacts-insert-generic-list phones "Phones")
+        (hyrolo-google-contacts-insert-generic-list postal-addresses 
"Addresses"
+                                             (lambda (address)
+                                               
(google-contacts-add-margin-to-text (cdr address)
+                                                                               
    (+ 4 (length (car address))))))
+        (hyrolo-google-contacts-insert-generic-list websites "Websites"
+                                             (lambda (website) (cdr website)))
+        (hyrolo-google-contacts-insert-generic-list events "Events")
+        (hyrolo-google-contacts-insert-generic-list relations "Relations"
+                                             (lambda (relation)
+                                               (widget-create 'link
+                                                              :button-prefix 
"" :button-suffix ""
+                                                              :action (lambda 
(widget &optional _event)
+                                                                        
(google-contacts (widget-value widget)))
+                                                              (cdr relation))
+                                               ""))
+        (hyrolo-google-contacts-insert-generic-list instant-messaging "Instant 
messaging"
+                                             (lambda (im)
+                                               (concat (cddr im) " (" (cadr 
im) ")")))
+
+        (when birthday
+          (insert "\n" (google-contacts-margin-element) "Birthday: " birthday 
"\n"))
+
+        (unless (string= notes "")
+          (insert "\n" (google-contacts-margin-element) "Notes:  "
+                  (google-contacts-add-margin-to-text notes 8)
+                  "\n"))
+
+        ;; Insert properties
+        (put-text-property beg (1+ beg) 'google-contacts t)
+        (when emails
+          (put-text-property beg (point)
+                             'google-contacts-email (concat fullname " <" (cdr 
(nth 0 emails)) ">")))))
+    (goto-char (point-min)))
+  ;; Return contacts
+  contacts)
+
+;; Derived from google-contacts.el.
+(defun hyrolo-google-contacts-insert-generic-list (items title &optional 
get-value)
+  "Insert a text for rendering ITEMS with TITLE.
+Use GET-VALUE to get the value from the cdr of the item,
+otherwise just put the cdr of item."
+  (when items
+    (insert "\n" (google-contacts-margin-element) (concat title ":\n"))
+    (dolist (item items)
+      (insert (google-contacts-margin-element) "  "
+              (concat (car item) ":") " "
+             (if get-value
+                  (funcall get-value item)
+                (cdr item))
+              "\n"))))
+
+;; Derived from google-contacts.el.
+(defun hyrolo-retrieve-google-contacts (&optional query-string force-refresh)
+  (interactive
+   (list (read-string "Look for: " (car google-contacts-history)
+                      'google-contacts-history)
+         current-prefix-arg))
+  (let ((buffer (google-contacts-make-buffer))
+        (token (google-contacts-oauth-token))
+        (google-contacts-expire-time (if force-refresh 0 
google-contacts-expire-time))
+        (inhibit-read-only t))
+    (with-current-buffer buffer
+      (setq google-contacts-query-string query-string)
+      (hyrolo-google-contacts-insert-data (xml-get-children 
(google-contacts-data query-string token)
+                                                           'entry)
+                                         token "* "))))
+
+;;; ************************************************************************
 ;;; Public functions
 ;;; ************************************************************************
 



reply via email to

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