I've always wanted a function for easily copying the values of record

The attached patch replaces the `bbdb-copy-records-as-kill' function
with a new function, `bbdb-copy-records-or-fields-as-kill'.

Basically it does what it says: if point is on a record name, the whole
record is copied, like before. If point is on a particular field, the
value (but not label) of that field is copied.

If the "*" prefix is given, the field value is copied from all records.
If point is on a field that has a label (ie phones or addresses), only
phones/addresses with the same label are copied from other records.

Lastly, a numeric prefix argument will select the corresponding item
from a field with a list value. If the field under point isn't a list,
the argument is ignored.

The implementation, while it seems to work just fine, is pretty ugly,
particularly working around the various types and labels. I would love
to know if this could be cleared up somehow.

Also I just realized I didn't make a ChangeLog note -- if this patch is
acceptable, I can send another version with the note included.


>From 195e25433ecc4c092f25b1f71c59d2749a954045 Mon Sep 17 00:00:00 2001
From: Eric Abrahamsen <e...@ericabrahamsen.net>
Date: Thu, 3 Sep 2015 14:25:30 +0800
Subject: [PATCH] New function for copying value of record fields

* lisp/bbdb-com.el (bbdb-copy-records-or-fields-as-kill): Replace old
  function `bbdb-copy-records-as-kill' with new function

* lisp/bbdb.el (bbdb-mode-map): Add new function to `bbdb-mode-map'.
 lisp/bbdb-com.el | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 lisp/bbdb.el     |  2 +-
 2 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/lisp/bbdb-com.el b/lisp/bbdb-com.el
index 6074bab..8137f22 100644
--- a/lisp/bbdb-com.el
+++ b/lisp/bbdb-com.el
@@ -2548,20 +2548,81 @@ Default is the first URL."
 ;;; Copy to kill ring
-(defun bbdb-copy-records-as-kill (records)
+(defun bbdb-copy-records-or-fields-as-kill (records &optional which)
   "Copy displayed RECORDS to kill ring.
+If point is on the record name, copy the whole record.  If point
+is on a particular field, copy only the value of that field.
 Interactively, use BBDB prefix \
-\\<bbdb-mode-map>\\[bbdb-do-all-records], see `bbdb-do-all-records'."
-  (interactive (list (bbdb-do-records t)))
-  (let (drec marker)
+\\<bbdb-mode-map>\\[bbdb-do-all-records], see
+`bbdb-do-all-records'.  If point is on a record name, all records
+will be copied.  If point is on a record field, the value of this
+field for all records will be copied.  If point is on a field
+with a label, only field values with the same label will be
+If a numeric prefix is given, and the field being copied has a
+list value, copy the list item at the index of the prefix
+  (interactive (list (bbdb-do-records t)
+		     (and current-prefix-arg
+                          (prefix-numeric-value current-prefix-arg))))
+  (let* ((field (bbdb-current-field))
+	 (field-name (car-safe field))
+	 (field-type (when field-name
+		       (cond
+			((eq 'xfields field-name)
+			 (caadr field))
+			((memq field-name '(phone address))
+			 (cons field-name (aref (cadr field) 0)))
+			(t field-name))))
+	 drec)
     (dolist (record (bbdb-record-list records t))
-      (push (buffer-substring (nth 2 record)
-                              (or (nth 2 (car (cdr (memq record bbdb-records))))
-                                  (point-max)))
-            drec))
+      (if (or (eq field-name 'name)
+	      (not field-name))
+	  ;; Copy the whole record.
+	  (push (buffer-substring (nth 2 record)
+				  (or (nth 2 (car (cdr (memq record bbdb-records))))
+				      (point-max)))
+		drec)
+	;; Or just the one field.
+	(let ((val (bbdb-record-field
+		    (car record)
+		    (cond ((symbolp field-type)
+			   field-type)
+			  ((consp field-type)
+			   (car field-type))))))
+	  (when (memq field-name '(phone address))
+	    (dolist (v val)
+	      ;; Only take phones and addresses with the proper label.
+	      (setq val
+		    (when (equal (aref v 0) (cdr field-type))
+		      v)))
+	    ;; Format phones and addresses properly.
+	    (when val
+	      (setq val
+		    (if (eq field-name 'phone)
+			(bbdb-phone-string val)
+		      (bbdb-format-address-default val)))))
+	  ;; Prefix arg `which' asks for a specific element from a
+	  ;; list value
+	  (when (and which
+		     (listp val))
+	    (setq val (nth which val)))
+	  (when val
+	    (push val drec)))))
     (kill-new (replace-regexp-in-string
                "[ \t\n]*\\'" "\n"
-               (mapconcat 'identity (nreverse drec) "")))))
+               (mapconcat (lambda (v)
+			    (if (stringp v)
+				v
+			      (mapconcat #'identity
+					 v
+					 (nth 1 (or (cdr (assq field bbdb-separator-alist))
+						    bbdb-default-separator)))))
+			  (nreverse drec) "\n")))
+    (message "Copied to kill ring")))
 ;;; Help and documentation
diff --git a/lisp/bbdb.el b/lisp/bbdb.el
index 514fb0d..f5976fc 100644
--- a/lisp/bbdb.el
+++ b/lisp/bbdb.el
@@ -1784,7 +1784,7 @@ if you want to call `bbdb-change-hook' and update the record unconditionally.")
     (define-key km "?"          'bbdb-help)
     ;; (define-key km "q"       'quit-window) ; part of `special-mode' bindings
     (define-key km "\C-x\C-t"   'bbdb-transpose-fields)
-    (define-key km "C"          'bbdb-copy-records-as-kill)
+    (define-key km "C"          'bbdb-copy-records-or-fields-as-kill)
     (define-key km "u"          'bbdb-browse-url)
     ;; (define-key km "P"       'bbdb-print)
     (define-key km "="          'delete-other-windows)

Monitor Your Dynamic Infrastructure at Any Scale With Datadog!
Get real-time metrics from all of your servers, apps and tools
in one place.
SourceForge users - Click here to start your Free Trial of Datadog now!
BBDB Home Page: http://bbdb.sourceforge.net/

Reply via email to