# Documentation of user-defined predicates in the prolog lsp-server

**URL:** <https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889>\
**Category:** General\
**Created:** [October 16, 2023, 1:36pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889 "2023-10-16T13:36:05Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [October 16, 2023, 1:36pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/1 "2023-10-16T13:36:05Z")

</div>

I’m using [the prolog lsp server](https://github.com/jamesnvc/lsp_server) by @jamesnvc, and I find it works perfectly for going to definition, references, and quickly seeing documentation of builtin predicates. However, I can’t get it to display the documentation for my own predicates. Perusing the source of the `lsp_server`, I think they should be written as `pldoc`, so here’s an example module:

```prolog
:- module(foo, [bar/2]).

%! foo(-X:atom) is nondet.
%
% Beautiful predicate.
foo(a).
foo(b).
foo(c).
foo(d).

%! bar(-X:atom) is nondet.
%
% Another predicate.
bar(X, X) :- foo(X), member(X, [a,b,c,d,e,f,g]).

```

however, if I try to get the documentation of `foo`, I get `LSP :: no content at point`. Does any of you have this feature working?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 1:54pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/2 "2023-10-16T13:54:06Z")

</div>

I tried this on one of my modules … interactively entering `help(transform_kythe_fact)` produced warning messages “Invalid mode declaration in PlDoc comment”, “PlDoc: failed to process structured comment”, and this:

```plaintext
ERROR: Failed to translate to HTML: \man_pages([transform_kythe_fact/2],[no_manual(fail),links(false),link_source(false),navtree(false),server(false)])

```

I had `autoload` set to `true`, if that makes a difference.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [October 16, 2023, 2:08pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/3 "2023-10-16T14:08:40Z")

</div>

That’s the same error I get too, when I try to use `help` directly. However I think the lsp server should be able to take the pldoc documentation, based on [this line in the source code](https://github.com/jamesnvc/lsp_server/blob/7afc8d23b8f71473baa50200310deb8aa677cea5/prolog/lsp_utils.pl#L175). But you raise a good question: how can we have `help` see the `pldoc` documentation, without invoking the documentation server?

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 16, 2023, 2:09pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/4 "2023-10-16T14:09:01Z")

</div>

> [@peter.ludemann](#):
>
> produced warning messages “Invalid mode declaration in PlDoc comment”, “PlDoc: failed to process structured comment”

I assume you have invalid PlDoc comments. There is not a lot of syntax that is validated. Notably the mode lines have to satisfy the mode syntax though.

> [@peter.ludemann](#):
>
> I had `autoload` set to `true`, if that makes a difference.

Without autoloading many of the development tools do not work.

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [October 16, 2023, 2:15pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/5 "2023-10-16T14:15:08Z")

</div>

> [@jan](#):
>
> Without autoloading many of the development tools do not work.

I understand that the flag `autoload` is true by default, so should `help` work on a predicate in the example module I shared above? The pldocs seem in the right format to me (edit: I tried using a wrong pldoc format, and I get an error saying I’m wrong, which I don’t get in the module above).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 16, 2023, 2:29pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/6 "2023-10-16T14:29:27Z")

</div>

Yeas, that should not be a problem. I don’t know whether the lsp server supports user defined predicates. @jamesnvc was quite enthusiastic about the new Emacs sweep mode by @oskardrums. If Emacs is your target, I’d try that.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 2:32pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/7 "2023-10-16T14:32:44Z")

</div>

> [@jan](#):
>
> I assume you have invalid PlDoc comments

But the predicate whose help I was trying to output didn’t generate any warnings about invalid PlDoc syntax. So, I presume that there’s a problem with man\_page//2 (possibly related to [Text help fails in some cases](https://swi-prolog.discourse.group/t/text-help-fails-in-some-cases/6883) ?)

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 16, 2023, 2:43pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/8 "2023-10-16T14:43:47Z")

</div>

> [@peter.ludemann](#):
>
> So, I presume that there’s a problem with man\_page//2

Looks like there is an issue with this predicate. Possibly it fails if some of the predicates it tries to generate documentation for has wrong comments? Should be possible to debug with a spy point and a bit of tracing (although it isn’t the most beautiful piece of code ☹ )

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 2:55pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/9 "2023-10-16T14:55:19Z")

</div>

> [@jan](#):
>
> Should be possible to debug with a spy point and a bit of tracing

Challenge accepted. 🙂

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 4:20pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/10 "2023-10-16T16:20:12Z")

</div>

The problem is here: [https://github.com/SWI-Prolog/packages-pldoc/blob/fe1a2ea7e75f4df65c797bb2c9f1de78ff80db2c/doc\_man.pl#L567](https://github.com/SWI-Prolog/packages-pldoc/blob/fe1a2ea7e75f4df65c797bb2c9f1de78ff80db2c/doc_man.pl#L567)

This restricts help/1 to only predicates that are exported. This appears to be a design decision, so I’m not sure how best to fix it.

(In order to find this, I had a bit of fun removing the various “notrace” and `generate_debug_info,false` items)

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [October 16, 2023, 4:33pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/11 "2023-10-16T16:33:08Z")

</div>

> [@peter.ludemann](#):
>
> This restricts [help/1](https://www.swi-prolog.org/pldoc/doc_for?object=help/1) to only predicates that are exported.

Does `help` work for exported predicates for you? In my case, it will say:

```prolog
%@ Warning: No help for bar.
%@ Warning: Use ?- apropos(query). to search for candidates.
%@ true.

```

even when I have loaded the file and the predicate is exported.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 5:46pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/12 "2023-10-16T17:46:45Z")

</div>

> [@meditans](#):
>
> Does `help` work for exported predicates for you?

I got the same result as you: “No help for \<predicate name\>.”

So, I’ll have to dig deeper (but probably not today).

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 16, 2023, 7:27pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/13 "2023-10-16T19:27:16Z")

</div>

Correction: with the removal of `private(Full,Options)` from `packages/pldoc/doc_man.pl`, I get documentation on exported predicates (without this change, I get the “No help” message).

---

<div class="post-metadata">

**Author:** ![meditans](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/meditans/32/1768_2.png) [@meditans](https://swi-prolog.discourse.group/u/meditans)\
**Post date:** [October 16, 2023, 9:41pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/14 "2023-10-16T21:41:31Z")

</div>

> [@peter.ludemann](#):
>
> with the removal of `private(Full,Options)` from `packages/pldoc/doc_man.pl`

Amazing, is that something that could be done on the user side as an option, or does it require editing the source files?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 17, 2023, 12:08am UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/15 "2023-10-17T00:08:47Z")

</div>

> [@meditans](#):
>
> is that something that could be done on the user side as an option, or does it require editing the source files?

I edited the source files (I routinely build and install from the github sources).  
If you install in a user-writeable director, you can edit the source files. For example, my executable is `~/.local/bin/swipl` and the file that I edited is `~/.local/lib/swipl/library/pldoc/doc_man.pl` (if you install in the standard place, presumably you could edit `/usr/lib/swipl/library/pldoc/doc_man.pl` or something like that).

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 17, 2023, 9:04am UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/16 "2023-10-17T09:04:28Z")

</div>

Back to the original, the file defines bar/2, but documents bar/1. You easily see this when using

```
swipl --pldoc foo.pl

```

For me, as is, `help(bar)` results in telling me there is no help for bar and showing the close match var/1 as alternative. After fixing the comment it works as expected.

Does anyone has a reproducible example of main\_page//2 failing when called from help/1?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 17, 2023, 4:18pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/17 "2023-10-17T16:18:06Z")

</div>

> [@jan](#):
>
> Does anyone has a reproducible example of main\_page//2 failing when called from [help/1](https://www.swi-prolog.org/pldoc/doc_for?object=help/1)?

This is my test file (it’s longer than it needs to be). It succeeds with the exported predicate and fails with the non-exported one. (I earlier reported that it failed with an exported predicate, but that was incorrect):

> **test file**
>
> ```prolog
> :- module(pykythe, [pykythe_main/0]).
> 
> :- det(pykythe_main/0).
> %! pykythe_main is det.
> % By default, this is called as part of initialization. It sets up
> % an error handler and some appropriate global limits, then calls
> % pykythe_main2/0 to process the files according to the command line
> % arguments.
> pykythe_main =>
> set_prolog_flag(stack_limit, 1_610_612_736), % TODO: 1.5GB - default of 1GB might suffice
> 
> % TODO: catch_with_backtrace/3 wrap might not be needed when the
> % initialization/2 directive is enabled.
> catch_with_backtrace(pykythe_main2,
> Error,
> ( print_message(error, Error),
> halt(1) )),
> log_if(true, 'End'), % TODO: delete
> halt(0).
> 
> :- det(transform_kythe_fact/2).
> %! transform_kythe_fact(+Fact0, -Fact1) is det.
> % TODO: Note that this also changes fact_value to base64 and has special
> % cases for symtab, text, colors
> transform_kythe_fact(json{source:Source0, fact_name:FactName, fact_value:FactValue}, Fact1) =>
> Fact1 = json{source:Source1, fact_name:FactName, fact_value:FactValueBase64},
> % text is alread in base64 (from Meta.contents_base64)
> ( FactName == '/kythe/text'
> -> FactValueBase64 = FactValue
> ; FactName == '/pykythe/color_all'
> -> FactValueBase64 = FactValue
> ; base64_utf8(FactValue, FactValueBase64)
> ),
> transform_kythe_vname(Source0, Source1).
> 
> ```

with output:

> **failure in man\_page//2**
>
> ```plaintext
> $ ~/src/swipl-devel/build/src/swipl -O -l /tmp/mm.pl
> Welcome to SWI-Prolog (threaded, 64 bits, version 9.1.17-2-g95852849b-DIRTY)
> SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
> Please run ?- license. for legal details.
> 
> CMake built from "/home/peter/src/swipl-devel/build"
> 
> For online help and background, visit https://www.swi-prolog.org
> For built-in help, use ?- help(Topic). or ?- apropos(Word).
> 
> ?- help(transform_kythe_fact).
> ERROR: Failed to translate to HTML: \man_pages([transform_kythe_fact/2],[no_manual(fail),links(false),link_source(false),navtree(false),server(false)])
> true.
> 
> ```

and when I remove the `\\+ private(Full, Options)` in `man_page//2`, I get:

> **success (after changing doc\_man.pl)**
>
> ```plaintext
> ?- help(transform_kythe_fact).
> /tmp/mm.pl
> 
> transform_kythe_fact(+Fact0, -Fact1) is det[private]
> TODO: Note that this also changes fact_value to base64 and has special
> cases for symtab, text, colors
> true.
> 
> ```

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 18, 2023, 12:21pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/18 "2023-10-18T12:21:06Z")

</div>

Thanks. No time now, but I should investigate this. Just removing might give undesirable side effects.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [October 18, 2023, 2:52pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/19 "2023-10-18T14:52:11Z")

</div>

Pushed a fix that

- Preserves the module for user defined predicates, so we do mix up different predicates
- Show matches, also when private by passing an extra option and checking this when deciding to hide some predicate or not.

Probably a step in the right direction, but whether it always does what it is supposed to …

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [October 18, 2023, 6:31pm UTC](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889/20 "2023-10-18T18:31:48Z")

</div>

> [@jan](#):
>
> Pushed a fix

I did a quick test … one thing I noticed is that when I simply removed the `\+private(...)` test, the output from `help(transform_kythe_fact)` was

```prolog
 transform_kythe_fact(+Fact0, -Fact1) is det[private]
    ... other comments ...

```

but with the change a608a5a87f0f90f1851841d9cc0cf435a3e1a71a and ea19f38875a0fdb7a78dd14c52cc7e867bffa94b, the `[private]` was no longer there

[Next page](https://swi-prolog.discourse.group/t/documentation-of-user-defined-predicates-in-the-prolog-lsp-server/6889.md?page=2)
