branch: externals/ebdb commit 8b565ca16753359671a187a821868d37e05baae5 Author: Eric Abrahamsen <e...@ericabrahamsen.net> Commit: Eric Abrahamsen <e...@ericabrahamsen.net>
Prompt for label after other field values Fixes #61 * ebdb.el (ebdb-read): The ebdb-field-labeled method is still an :around method, but the work is now done after the field itself is read. There were two issues: one, entering an empty string for the label prompted to create the empty string as a label -- nonsensical. Two, the label was required: if the user canceled label input, the whole field creation process was cancelled. Now we allow null labels. (ebdb-read-string): Use string-empty-p. * ebdb.org: Tweak docs accordingly. --- ebdb.el | 32 ++++++++-------- ebdb.info | 129 +++++++++++++++++++++++++++++++------------------------------- ebdb.org | 9 +++-- ebdb.texi | 51 +++++++++++++------------ 4 files changed, 113 insertions(+), 108 deletions(-) diff --git a/ebdb.el b/ebdb.el index e5f379a..137b582 100644 --- a/ebdb.el +++ b/ebdb.el @@ -1015,21 +1015,23 @@ an empty string as a label, which allows interruption of the read process." ;; This is an :around method so the field label can be prompted for ;; before the value. - (let* ((labels (symbol-value (oref-default class label-list))) + (let* ((field (cl-call-next-method class slots obj)) + (labels (symbol-value (oref-default class label-list))) (human-readable (ebdb-field-readable-name class)) - (label (plist-get slots :object-name))) - (unless label - (setq label (ebdb-read-string - (if (stringp human-readable) - (format "%s label: " (capitalize human-readable)) - "Label: ") - (and obj (slot-value obj 'object-name)) - labels nil) - slots (plist-put slots :object-name label))) - (if (or (member label labels) - (yes-or-no-p (format "%s is not a known label, define it? " label))) - (cl-call-next-method class slots obj) - (signal 'ebdb-empty (list class))))) + (label (slot-value field 'object-name))) + (setq label (ebdb-with-exit + (ebdb-read-string + (if (stringp human-readable) + (format "%s label: " (capitalize human-readable)) + "Label: ") + label labels nil))) + (when (and label + (or + (member label labels) + (yes-or-no-p + (format "%s is not a known label, define it? " label)))) + (setf (slot-value field 'object-name) label)) + field)) (cl-defmethod ebdb-init-field ((field ebdb-field-labeled) &optional _record) (let ((label-var (slot-value field 'label-list))) @@ -4438,7 +4440,7 @@ COLLECTION and REQUIRE-MATCH have the same meaning as in `completing-read'." map))) (completing-read prompt collection nil require-match init)) (let ((string (read-string prompt init))) - (if (string= "" string) + (if (string-empty-p string) (signal 'ebdb-empty (list prompt)) string))))) diff --git a/ebdb.info b/ebdb.info index ecf15f8..0d0f1e8 100644 --- a/ebdb.info +++ b/ebdb.info @@ -458,10 +458,11 @@ labeled “birthday” or “wedding”, and URL fields might be labeled “homepage” or “file-sharing”. In the case of fields with labels, you’ll first choose the general -field (“anniversary”) and then be prompted to choose the label -(“birthday”). Again, if you choose a label that hasn’t been seen +field (“anniversary”), then enter the field data, and lastly choose a +label (“birthday”). Again, if you choose a label that hasn’t been seen before, EBDB will first prompt for confirmation, then define the label -for future use. +for future use. You can also enter an empty string or hit ‘C-g’ to omit +the label altogether. Loading secondary libraries may make more field types available. @@ -1429,11 +1430,11 @@ the class type. As an example: :initform unknown :type symbol :custom (choice - (const :tag "Female" female) - (const :tag "Male" male) - (const :tag "Other" other) - (const :tag "Unknown" unknown) - (const :tag "None/Not Applicable" none)))) + (const :tag "Female" female) + (const :tag "Male" male) + (const :tag "Other" other) + (const :tag "Unknown" unknown) + (const :tag "None/Not Applicable" none)))) :human-readable "gender" :documentation "A field holding gender information about this record.") @@ -1453,19 +1454,19 @@ present, is an existing field instance that can be used to provide default values for the new object. (cl-defmethod ebdb-read ((class (subclass ebdb-field-gender)) - &optional slots obj) + &optional slots obj) (unless (plist-get slots :gender) (let ((gender (intern (completing-read - "Gender: " '(female male other unknown none) - nil t - (when obj (symbol-name (slot-value obj :gender))))))) + "Gender: " '(female male other unknown none) + nil t + (when obj (symbol-name (slot-value obj :gender))))))) (setq slots (plist-put slots :gender gender)))) (cl-call-next-method class slots obj)) (cl-defmethod ebdb-parse ((class (subclass ebdb-field-gender)) - str &optional slots) + str &optional slots) (when (and (null (plist-get slots :gender)) - (member str '("female" "male" "other" "unknown" "none"))) + (member str '("female" "male" "other" "unknown" "none"))) (setq slots (plist-put slots :gender (intern str))) (cl-call-next-method class str slots)) @@ -1612,14 +1613,14 @@ search methods for the ‘ebdb-field-tags’ class. "Search for tags (eg +tag1-tag2|tag3): ")))) (cl-defmethod ebdb-field-search ((field ebdb-field-tags) - func) + func) (when (functionp func) (funcall func t (slot-value field 'tags) 1))) (cl-defmethod ebdb-field-search ((field ebdb-field-tags) - (tag string)) + (tag string)) (seq-find (lambda (tg) (string-match-p tag tg)) - (slot-value field 'tags))) + (slot-value field 'tags))) The ‘ebdb-search-read’ method returns a lambda (the ‘cdr’ of the return value of ‘org-make-tags-matcher’. The first ‘ebdb-field-search’ @@ -1694,9 +1695,9 @@ of the street addresses, plus the city, plus the country. You could achieve that by overriding the ‘collapse’ style like so: (cl-defmethod ebdb-fmt-field ((_fmt ebdb-formatter) - (field ebdb-field-address) - (_style (eql collapse)) - (_record ebdb-record)) + (field ebdb-field-address) + (_style (eql collapse)) + (_record ebdb-record)) "Give address fields a special 'collapse formatting." (with-slots (streets locality country) field (format "%s (%s, %s)" (car streets) locality country))) @@ -1768,7 +1769,7 @@ and the country-code spec—and needs to specialize on both arguments. The method signature will look like this: (cl-defmethod ebdb-string-i18n ((phone ebdb-field-phone) - (_cc (eql 33)))) + (_cc (eql 33)))) See the manual on generic functions for details; suffice it to say that this method will only run when the first argument is an instance of @@ -1779,14 +1780,14 @@ the ‘ebdb-field-phone’ class (or a subclass), and the second argument is we can format the number correctly: (cl-defmethod ebdb-string-i18n ((phone ebdb-field-phone) - (_cc (eql 33))) + (_cc (eql 33))) (with-slots (area-code number extension) phone (concat "+33 " (when area-code (format "%02d" area-code)) (format "%s%s %s%s %s%s %s%s" - (split-string number "" t)) + (split-string number "" t)) (when extension (format "X%d" extension))))) @@ -1832,7 +1833,7 @@ the responsibility of the MUA to implement this function, and return the contents of the appropriate header. For instance, in Gnus: (cl-defmethod ebdb-mua-message-header ((header string) - &context (major-mode gnus-summary-mode)) + &context (major-mode gnus-summary-mode)) "Return value of HEADER for current Gnus message." (set-buffer gnus-article-buffer) (gnus-fetch-original-field header)) @@ -2232,46 +2233,46 @@ Node: Inserting New Fields11683 Node: Editing Existing Fields12479 Node: Deleting Records and Fields13079 Node: Field Types13475 -Node: Role fields15666 -Node: Tag field17354 -Node: Mail folder field17998 -Node: MUA Interaction18326 -Node: Loading MUA Code18850 -Node: Display and Updating19563 -Node: Pop-up Buffers20329 -Node: Auto-Updating Records21167 -Node: Noticing and Automatic Rules23567 -Node: Interactive Commands24900 -Node: EBDB and MUA summary buffers27375 -Node: Sender name display27861 -Node: Summary buffer marks29088 -Node: EBDB Buffers30267 -Node: Searching31449 -Node: Changing Search Behavior33111 -Node: The Basics of ebdb-mode34358 -Node: Marking37959 -Node: Exporting/Formatting38383 -Node: Completion39332 -Node: Snarfing40530 -Node: Internationalization42531 -Node: Diary Integration45230 -Node: Mail Aliases46095 -Node: vCard Support46809 -Node: Org Integration47308 -Node: Citing Records49206 -Node: Hacking EBDB49964 -Node: Field Classes52283 -Node: Init and Delete Methods55267 -Node: The Labeled Field Class56774 -Node: The Singleton Field Class57628 -Node: Actions58066 -Node: Custom Field Searching58738 -Node: Fast Lookups61542 -Node: Formatting in the EBDB Buffer63352 -Node: Writing Internationalization Libraries65365 -Node: Writing Integration For New MUAs69716 -Node: Article snarfing73135 -Node: Index73853 +Node: Role fields15762 +Node: Tag field17450 +Node: Mail folder field18094 +Node: MUA Interaction18422 +Node: Loading MUA Code18946 +Node: Display and Updating19659 +Node: Pop-up Buffers20425 +Node: Auto-Updating Records21263 +Node: Noticing and Automatic Rules23663 +Node: Interactive Commands24996 +Node: EBDB and MUA summary buffers27471 +Node: Sender name display27957 +Node: Summary buffer marks29184 +Node: EBDB Buffers30363 +Node: Searching31545 +Node: Changing Search Behavior33207 +Node: The Basics of ebdb-mode34454 +Node: Marking38055 +Node: Exporting/Formatting38479 +Node: Completion39428 +Node: Snarfing40626 +Node: Internationalization42627 +Node: Diary Integration45326 +Node: Mail Aliases46191 +Node: vCard Support46905 +Node: Org Integration47404 +Node: Citing Records49302 +Node: Hacking EBDB50060 +Node: Field Classes52379 +Node: Init and Delete Methods55510 +Node: The Labeled Field Class57017 +Node: The Singleton Field Class57871 +Node: Actions58309 +Node: Custom Field Searching58981 +Node: Fast Lookups61848 +Node: Formatting in the EBDB Buffer63658 +Node: Writing Internationalization Libraries65734 +Node: Writing Integration For New MUAs70148 +Node: Article snarfing73595 +Node: Index74313 End Tag Table diff --git a/ebdb.org b/ebdb.org index 67c36b3..ca7279b 100644 --- a/ebdb.org +++ b/ebdb.org @@ -321,10 +321,11 @@ labeled "birthday" or "wedding", and URL fields might be labeled "homepage" or "file-sharing". In the case of fields with labels, you'll first choose the general -field ("anniversary") and then be prompted to choose the label -("birthday"). Again, if you choose a label that hasn't been seen -before, EBDB will first prompt for confirmation, then define the label -for future use. +field ("anniversary"), then enter the field data, and lastly choose a +label ("birthday"). Again, if you choose a label that hasn't been +seen before, EBDB will first prompt for confirmation, then define the +label for future use. You can also enter an empty string or hit +{{{kbd(C-g)}}} to omit the label altogether. Loading secondary libraries may make more field types available. *** Role fields diff --git a/ebdb.texi b/ebdb.texi index 33ffd48..e63b994 100644 --- a/ebdb.texi +++ b/ebdb.texi @@ -495,10 +495,11 @@ labeled ``birthday'' or ``wedding'', and URL fields might be labeled ``homepage'' or ``file-sharing''. In the case of fields with labels, you'll first choose the general -field (``anniversary'') and then be prompted to choose the label -(``birthday''). Again, if you choose a label that hasn't been seen -before, EBDB will first prompt for confirmation, then define the label -for future use. +field (``anniversary''), then enter the field data, and lastly choose a +label (``birthday''). Again, if you choose a label that hasn't been +seen before, EBDB will first prompt for confirmation, then define the +label for future use. You can also enter an empty string or hit +@kbd{C-g} to omit the label altogether. Loading secondary libraries may make more field types available. @@ -1552,11 +1553,11 @@ the class type. As an example: :initform unknown :type symbol :custom (choice - (const :tag "Female" female) - (const :tag "Male" male) - (const :tag "Other" other) - (const :tag "Unknown" unknown) - (const :tag "None/Not Applicable" none)))) + (const :tag "Female" female) + (const :tag "Male" male) + (const :tag "Other" other) + (const :tag "Unknown" unknown) + (const :tag "None/Not Applicable" none)))) :human-readable "gender" :documentation "A field holding gender information about this record.") @end lisp @@ -1579,19 +1580,19 @@ provide default values for the new object. @lisp (cl-defmethod ebdb-read ((class (subclass ebdb-field-gender)) - &optional slots obj) + &optional slots obj) (unless (plist-get slots :gender) (let ((gender (intern (completing-read - "Gender: " '(female male other unknown none) - nil t - (when obj (symbol-name (slot-value obj :gender))))))) + "Gender: " '(female male other unknown none) + nil t + (when obj (symbol-name (slot-value obj :gender))))))) (setq slots (plist-put slots :gender gender)))) (cl-call-next-method class slots obj)) (cl-defmethod ebdb-parse ((class (subclass ebdb-field-gender)) - str &optional slots) + str &optional slots) (when (and (null (plist-get slots :gender)) - (member str '("female" "male" "other" "unknown" "none"))) + (member str '("female" "male" "other" "unknown" "none"))) (setq slots (plist-put slots :gender (intern str))) (cl-call-next-method class str slots)) @@ -1746,14 +1747,14 @@ search methods for the @code{ebdb-field-tags} class. "Search for tags (eg +tag1-tag2|tag3): ")))) (cl-defmethod ebdb-field-search ((field ebdb-field-tags) - func) + func) (when (functionp func) (funcall func t (slot-value field 'tags) 1))) (cl-defmethod ebdb-field-search ((field ebdb-field-tags) - (tag string)) + (tag string)) (seq-find (lambda (tg) (string-match-p tag tg)) - (slot-value field 'tags))) + (slot-value field 'tags))) @end lisp The @code{ebdb-search-read} method returns a lambda (the @code{cdr} of the @@ -1830,9 +1831,9 @@ achieve that by overriding the @code{collapse} style like so: @lisp (cl-defmethod ebdb-fmt-field ((_fmt ebdb-formatter) - (field ebdb-field-address) - (_style (eql collapse)) - (_record ebdb-record)) + (field ebdb-field-address) + (_style (eql collapse)) + (_record ebdb-record)) "Give address fields a special 'collapse formatting." (with-slots (streets locality country) field (format "%s (%s, %s)" (car streets) locality country))) @@ -1914,7 +1915,7 @@ arguments. The method signature will look like this: @lisp (cl-defmethod ebdb-string-i18n ((phone ebdb-field-phone) - (_cc (eql 33)))) + (_cc (eql 33)))) @end lisp See the manual on generic functions for details; suffice it to say @@ -1927,14 +1928,14 @@ can format the number correctly: @lisp (cl-defmethod ebdb-string-i18n ((phone ebdb-field-phone) - (_cc (eql 33))) + (_cc (eql 33))) (with-slots (area-code number extension) phone (concat "+33 " (when area-code (format "%02d" area-code)) (format "%s%s %s%s %s%s %s%s" - (split-string number "" t)) + (split-string number "" t)) (when extension (format "X%d" extension))))) @end lisp @@ -1981,7 +1982,7 @@ return the contents of the appropriate header. For instance, in Gnus: @lisp (cl-defmethod ebdb-mua-message-header ((header string) - &context (major-mode gnus-summary-mode)) + &context (major-mode gnus-summary-mode)) "Return value of HEADER for current Gnus message." (set-buffer gnus-article-buffer) (gnus-fetch-original-field header))