unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* [QUESTION] I have problem on my org-contacts capf function source code
@ 2021-11-14  9:59 Christopher M. Miles
  2021-11-14 23:10 ` Stefan Monnier via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 7+ messages in thread
From: Christopher M. Miles @ 2021-11-14  9:59 UTC (permalink / raw)
  To: Emacs Help

[-- Attachment #1: Type: text/plain, Size: 3309 bytes --]


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. Can someone help me to review my code and figure out the problem.
If you provide problem solution is welcome. Thanks a lot.

#+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)))
    (list begin
          end
          (all-completions
           prefix
           (mapcar
            (lambda (contact) (plist-get contact :name))
            (org-contacts--all-contacts))
           'stringp)

          ;; (completion-table-dynamic
          ;;  (lambda (input)
          ;;    (mapcar
          ;;     (lambda (contact) (plist-get contact :name))
          ;;     (org-contacts--all-contacts))))

          :exclusive 'no
          :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)))))))

;;; @Chr
(add-hook 'completion-at-point-functions 'org-contacts-completion-at-point nil 'local)
;; (add-to-list 'completion-at-point-functions 'org-contacts-completion-at-point)
#+end_src


-- 
[ 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-14  9:59 [QUESTION] I have problem on my org-contacts capf function source code Christopher M. Miles
@ 2021-11-14 23:10 ` Stefan Monnier via Users list for the GNU Emacs text editor
  2021-11-15  9:05   ` Christopher M. Miles
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier via Users list for the GNU Emacs text editor @ 2021-11-14 23:10 UTC (permalink / raw)
  To: help-gnu-emacs

> 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.

>     (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.

>           ;; (completion-table-dynamic
>           ;;  (lambda (input)
>           ;;    (mapcar
>           ;;     (lambda (contact) (plist-get contact :name))
>           ;;     (org-contacts--all-contacts))))

That would be better, yes.

>           :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.

>           :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.


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-14 23:10 ` Stefan Monnier via Users list for the GNU Emacs text editor
@ 2021-11-15  9:05   ` Christopher M. Miles
  2021-11-15 13:50     ` Stefan Monnier via Users list for the GNU Emacs text editor
  0 siblings, 1 reply; 7+ messages in thread
From: Christopher M. Miles @ 2021-11-15  9:05 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 8016 bytes --]


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 <help-gnu-emacs@gnu.org> 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-15  9:05   ` Christopher M. Miles
@ 2021-11-15 13:50     ` Stefan Monnier via Users list for the GNU Emacs text editor
  2021-11-15 15:43       ` Christopher M. Miles
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier via Users list for the GNU Emacs text editor @ 2021-11-15 13:50 UTC (permalink / raw)
  To: help-gnu-emacs

> (add-hook 'completion-at-point-functions 'org-contacts-org-complete-function nil 'local)

I assume you're careful to run this `add-hook` in the appropriate buffer
(otherwise, of course it won't do anything useful ;-)

> When I evaluated upper code, and test by typing in "@Chri", I have not seen org-contacts related
> complete popup candidates.

Try `M-x trace-function RET org-contacts-org-complete-function RET`.
Also you may prefer to first just try

    M-: (org-contacts-org-complete-function) RET

and make sure that what it returns makes sense.
Then

    M-: (all-completions "Chr" (nth 2 (org-contacts-org-complete-function))) RET

Maybe try also

    M-: (all-completions "@Chr" (nth 2 (org-contacts-org-complete-function))) RET

then check whether the BEG..END area returned by
`org-contacts-org-complete-function` contains "@Chr" or "Chr".


        Stefan




^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-15 13:50     ` Stefan Monnier via Users list for the GNU Emacs text editor
@ 2021-11-15 15:43       ` Christopher M. Miles
  2021-11-15 21:30         ` Stefan Monnier
  0 siblings, 1 reply; 7+ messages in thread
From: Christopher M. Miles @ 2021-11-15 15:43 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 4026 bytes --]


Stefan Monnier via Users list for the GNU Emacs text editor <help-gnu-emacs@gnu.org> writes:

>> (add-hook 'completion-at-point-functions 'org-contacts-org-complete-function nil 'local)
>
> I assume you're careful to run this `add-hook` in the appropriate buffer
> (otherwise, of course it won't do anything useful ;-)
>

I test this `add-hook` in org-mode buffer and elisp-mode buffer.

>> When I evaluated upper code, and test by typing in "@Chri", I have not seen org-contacts related
>> complete popup candidates.
>
> Try `M-x trace-function RET org-contacts-org-complete-function RET`.
> Also you may prefer to first just try
>
>     M-: (org-contacts-org-complete-function) RET
>
> and make sure that what it returns makes sense.
> Then
>
>     M-: (all-completions "Chr" (nth 2 (org-contacts-org-complete-function))) RET
>
> Maybe try also
>
>     M-: (all-completions "@Chr" (nth 2 (org-contacts-org-complete-function))) RET
>
> then check whether the BEG..END area returned by
> `org-contacts-org-complete-function` contains "@Chr" or "Chr".

I followed your steps. Got following trace output:

#+begin_example
======================================================================
1 -> (org-contacts-org-complete-function)
1 <- org-contacts-org-complete-function: nil
======================================================================
1 -> (org-contacts-org-complete-function)
1 <- org-contacts-org-complete-function: nil
======================================================================
1 -> (org-contacts-org-complete-function)
1 <- org-contacts-org-complete-function: nil
#+end_example

I found ~org-contacts-org-complete-function~ returned a special value:

#+begin_example
#f(compiled-function (string pred action) #<bytecode -0x9e1a398d61d3acb>)
#+end_example


And this code,

#+begin_src emacs-lisp
(completion-table-dynamic
             (lambda (_)
               (mapcar
                (lambda (contact) (plist-get contact :name))
                (org-contacts--all-contacts))))
#+end_src

returned following:

#+begin_example
#[771 "....." [(lambda (_) (mapcar ... ...)) nil boundaries metadata minibuffer-selected-window window-live-p window-buffer complete-with-action] 8 "

(fn STRING PRED ACTION)"]
#+end_example

Don't know whether this is correct.

I can confirm the bellowing basic completion with ~try-completion~ code works fine:

#+begin_src emacs-lisp
(try-completion
 "tri"
 (mapcar
  (lambda (contact) (plist-get contact :name))
  (org-contacts--all-contacts)))
#+end_src

# ==================================================================================================

At last, I paste my latest simple code version:

#+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* ((bounds (bounds-of-thing-at-point 'symbol))
              (begin (1- (car bounds)))
              (end (cdr bounds))
              (symbol (buffer-substring-no-properties begin end))
              (org-contacts-prefix-p (string-prefix-p "@" symbol))
              ;; (prefix (substring-no-properties symbol 1 nil))
              )
    (when org-contacts-prefix-p
      (list begin
            end
            (completion-table-dynamic
             (lambda (_)
               (mapcar
                (lambda (contact) (plist-get contact :name))
                (org-contacts--all-contacts))))))))
#+end_src

And test with execute following ~add-hook~ in org-mode buffer or emacs-lisp-mode buffer:

#+begin_src emacs-lisp
(add-hook 'completion-at-point-functions 'org-contacts-org-complete-function nil 'local)
#+end_src



-- 
[ 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-15 15:43       ` Christopher M. Miles
@ 2021-11-15 21:30         ` Stefan Monnier
  2021-11-18  6:56           ` [SOLVED] " Christopher M. Miles
  0 siblings, 1 reply; 7+ messages in thread
From: Stefan Monnier @ 2021-11-15 21:30 UTC (permalink / raw)
  To: Christopher M. Miles; +Cc: help-gnu-emacs

> I followed your steps. Got following trace output:
>
> #+begin_example
> ======================================================================
> 1 -> (org-contacts-org-complete-function)
> 1 <- org-contacts-org-complete-function: nil
> ======================================================================
> 1 -> (org-contacts-org-complete-function)
> 1 <- org-contacts-org-complete-function: nil
> ======================================================================
> 1 -> (org-contacts-org-complete-function)
> 1 <- org-contacts-org-complete-function: nil
> #+end_example

So when that function was called (what called it, BTW?  Did you hit
`M-TAB` or are you using `company-mode`?) apparently
`org-contacts-prefix-p` ended up being nil.

And what do you get when you try

    M-: (org-contacts-org-complete-function) RET

?

> I found ~org-contacts-org-complete-function~ returned a special value:
>
> #+begin_example
> #f(compiled-function (string pred action) #<bytecode -0x9e1a398d61d3acb>)
> #+end_example

I can't see any way M-: (org-contacts-org-complete-function) RET
can return the above value.  So I suspect a "pilot error".
This looks like the 3rd value in the returned list (i.e. the value
returned by `completion-table-dynamic`).

> #+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* ((bounds (bounds-of-thing-at-point 'symbol))
>               (begin (1- (car bounds)))
>               (end (cdr bounds))
>               (symbol (buffer-substring-no-properties begin end))
>               (org-contacts-prefix-p (string-prefix-p "@" symbol))
>               ;; (prefix (substring-no-properties symbol 1 nil))
>               )
>     (when org-contacts-prefix-p
>       (list begin
>             end
>             (completion-table-dynamic
>              (lambda (_)
>                (mapcar
>                 (lambda (contact) (plist-get contact :name))
>                 (org-contacts--all-contacts))))))))
> #+end_src

This gives a `begin..end` region which presumably includes `@`.
Does (plist-get contact :name) return names that start with `@`?
If not, the completion will never match.

> And test with execute following ~add-hook~ in org-mode buffer or
>  emacs-lisp-mode buffer:

In emacs-lisp-mode, `@` has symbol syntax, so
(bounds-of-thing-at-point 'symbol)
will include `@` in the returned region, whereas in Org mode
`@` seems to have punctuation syntax so the `@` will not be included in
the returned region.

Maybe instead of `bounds-of-thing-at-point` you want to use something
less "magic", like (skip-chars-backward "[:alnum:]@").

> #+begin_src emacs-lisp
> (add-hook 'completion-at-point-functions 'org-contacts-org-complete-function nil 'local)
> #+end_src




^ permalink raw reply	[flat|nested] 7+ messages in thread

* [SOLVED] Re: [QUESTION] I have problem on my org-contacts capf function source code
  2021-11-15 21:30         ` Stefan Monnier
@ 2021-11-18  6:56           ` Christopher M. Miles
  0 siblings, 0 replies; 7+ messages in thread
From: Christopher M. Miles @ 2021-11-18  6:56 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: help-gnu-emacs

[-- Attachment #1: Type: text/plain, Size: 3782 bytes --]


I found the problem reason.

> This gives a `begin..end` region which presumably includes `@`.
> Does (plist-get contact :name) return names that start with `@`?
> If not, the completion will never match.

Here is my workable 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 (1- (car bounds)))
              (end (cdr bounds))
              (symbol (buffer-substring-no-properties begin end))
              (org-contacts-prefix-p (string-prefix-p "@" symbol))
              ;; (prefix (substring-no-properties symbol 1 nil))
              )
    (when org-contacts-prefix-p
      (list begin
            end
            
            ;; (all-completions
            ;;  prefix
            ;;  (mapcar
            ;;   (lambda (contact) (plist-get contact :name))
            ;;   (org-contacts--all-contacts))
            ;;  'stringp)

            (completion-table-dynamic
             (lambda (_)
               (mapcar
                (lambda (contact) (concat "@" (plist-get contact :name))) ; <----- prepend "@" solved the problem.
                (org-contacts--all-contacts))))

            ;; :predicate 'stringp
            ;; :exclusive 'no
            ;; properties check out `completion-extra-properties'
            ;; :annotation-function #'org-contacts-org-complete--annotation-function
            ;; :exit-function ; TODO change completion candidate inserted contact name into org-contact link??

            ;; :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

Also learned your other detailed suggestion. Learned lot from you. Thanks for your teaching. 😄

-- 
[ 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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-11-18  6:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-11-14  9:59 [QUESTION] I have problem on my org-contacts capf function source code Christopher M. Miles
2021-11-14 23:10 ` Stefan Monnier via Users list for the GNU Emacs text editor
2021-11-15  9:05   ` Christopher M. Miles
2021-11-15 13:50     ` Stefan Monnier via Users list for the GNU Emacs text editor
2021-11-15 15:43       ` Christopher M. Miles
2021-11-15 21:30         ` Stefan Monnier
2021-11-18  6:56           ` [SOLVED] " Christopher M. Miles

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).