Here is my changed source code: #+begin_src emacs-lisp (defun org-contacts-org-complete--annotation-function (candidate) "Return org-contacts tags of contact candidate." ;; TODO "Tags: ") (defun org-contacts-org-complete--doc-function (candidate) "Return org-contacts content of contact candidate." (let ((name (plist-get candidate :name)) (file (plist-get candidate :file)) (position (plist-get candidate :position))) (company-doc-buffer ;; get org-contact headline and property drawer. (with-current-buffer (find-file-noselect file) (goto-char position) (when (derived-mode-p 'org-mode) ;; `org-edit-src-code' is not a real narrowing command. ;; Remove this first conditional if you don't want it. (cond ((ignore-errors (org-edit-src-code)) (delete-other-windows)) ((org-at-block-p) (org-narrow-to-block)) (t (org-narrow-to-subtree))) (buffer-substring (point-min) (point-max))))))) (defun org-contacts-org-complete--location-function (candidate) "Return org-contacts location of contact candidate." (let ((name (plist-get candidate :name)) (file (plist-get candidate :file)) (position (plist-get candidate :position))) (with-current-buffer (find-file-noselect file) (goto-char position) (cons (current-buffer) position)))) (defun org-contacts-org-complete-function () "Function used in `completion-at-point-functions' in `org-mode' to complete @name." (when-let* ((bounds (bounds-of-thing-at-point 'symbol)) (begin (car bounds)) (end (cdr bounds)) (symbol (buffer-substring-no-properties begin end)) (@-prefix-p (string-prefix-p "@" symbol)) (prefix (substring-no-properties symbol 1 nil)) ) (list begin end ;; (all-completions ;; nil ;; (mapcar ;; (lambda (contact) (plist-get contact :name)) ;; (org-contacts--all-contacts)) ;; 'stringp) ;; FIXME (completion-table-dynamic (lambda (input) (mapcar (lambda (contact) (plist-get contact :name)) (org-contacts--all-contacts)))) ;; :exclusive 'no ;; :annotation-function #'org-contacts-org-complete--annotation-function ;; :company-docsig #'identity ; metadata ;; :company-doc-buffer #'org-contacts-org-complete--doc-function ; doc popup ;; :company-location #'org-contacts-org-complete--location-function ))) (add-hook 'completion-at-point-functions 'org-contacts-org-complete-function nil 'local) #+end_src When I evaluated upper code, and test by typing in "@Chri", I have not seen org-contacts related complete popup candidates. So I describe it not working. I also try to edebug on the source code. Have not found error stacktrace. Don't know where is the problem. If you have time, can you try my code and take a testing debug? Thanks a lot. Stefan Monnier via Users list for the GNU Emacs text editor writes: >> I try to write a capf function for org-contacts to auto complete >> contact names after "@". Here is my code, but it still does not >> work. > > Some description of what you mean by "doesn't work" would be helpful. > >> #+begin_src emacs-lisp >> (defun org-contacts-org-complete-function () >> "Function used in `completion-at-point-functions' in `org-mode' to complete @name." >> (when-let* ((@-prefix-p (string-prefix-p "@" (thing-at-point 'symbol))) >> (symbol (thing-at-point 'symbol)) >> (prefix (substring-no-properties symbol 1 nil)) >> (bounds (bounds-of-thing-at-point 'symbol)) >> (begin (car bounds)) >> (end (cdr bounds))) > > You ask thingatpt to compute the same information 3 times. Not only > it's inefficient, but if for some reason it doesn't return the same info > all three times your code will be broken. So better start with > `bounds-of-thing-at-point` and then use `buffer-substring` to extract > `symbol` from it, and then use that in the `string-prefix-p` test. Advice taken. > >> (list begin >> end >> (all-completions >> prefix >> (mapcar >> (lambda (contact) (plist-get contact :name)) >> (org-contacts--all-contacts)) >> 'stringp) > > Don't use `prefix` here. > Provide the a general completion table which can be used with other > prefixes as well: the CAPF function should only choose which kind of > completion to perform and which part of the buffer. > So, does that mean the "prefix" should be nil? >> ;; (completion-table-dynamic >> ;; (lambda (input) >> ;; (mapcar >> ;; (lambda (contact) (plist-get contact :name)) >> ;; (org-contacts--all-contacts)))) > > That would be better, yes. Don't know whether my code is right. > >> :exclusive 'no > > Is this *really* necessary? This functionality is fundamentally very > hard to implement, so it comes with a lot of warts and restrictions. > Only use it if it's really really indispensable. I read the ~:exclusive 'no~ docstring of ~completion-at-point-functions~ which means auto pass to next completion backend if this completion backend failed. I think it should be used here. > >> :annotation-function ; tags >> ;; TODO >> (lambda (candidate) >> "Tags: ") >> :company-docsig #'identity ; metadata >> :company-doc-buffer ; doc popup >> (lambda (candidate) >> (let ((name (plist-get candidate :name)) >> (file (plist-get candidate :file)) >> (position (plist-get candidate :position))) >> (company-doc-buffer >> ;; get org-contact headline and property drawer. >> (with-current-buffer (find-file-noselect file) >> (goto-char position) >> (when (derived-mode-p 'org-mode) >> ;; `org-edit-src-code' is not a real narrowing command. >> ;; Remove this first conditional if you don't want it. >> (cond ((ignore-errors (org-edit-src-code)) >> (delete-other-windows)) >> ((org-at-block-p) >> (org-narrow-to-block)) >> (t (org-narrow-to-subtree))) >> (buffer-substring (point-min) (point-max))))))) >> :company-location (lambda (candidate) >> (let ((name (plist-get candidate :name)) >> (file (plist-get candidate :file)) >> (position (plist-get candidate :position))) >> (with-current-buffer (find-file-noselect file) >> (goto-char position) >> (cons (current-buffer) position))))))) > > I recommend you move those functions outside of the CAFP function > instead, give them a name and refer to them by name here. Will make the > code easier to read, will help indentation-depth, and can also > help debugging. > I moved those lambda functions to single functions now. Thanks for your suggestions. -- [ stardiviner ] I try to make every word tell the meaning that I want to express. Blog: https://stardiviner.github.io/ IRC(freenode): stardiviner, Matrix: stardiviner GPG: F09F650D7D674819892591401B5DF1C95AE89AC3