1:- module(lsp_completion, [completions_at/3]).

LSP Completion

This module implements code completion, based on defined predicates in the file & imports.

Uses lsp_changes in order to see the state of the buffer being edited.

author
- James Cash */
See also
- doc_text_fallback/2
   14:- use_module(library(apply), [maplist/3]).   15:- use_module(library(lists), [numlist/3]).   16:- use_module(library(prolog_xref), [xref_defined/3, xref_source/2]).   17:- use_module(library(yall)).   18:- use_module(lsp_utils, [linechar_offset/3]).   19:- use_module(lsp_changes, [doc_text_fallback/2]).   20
   21part_of_prefix(Code) :- code_type(Code, prolog_var_start).
   22part_of_prefix(Code) :- code_type(Code, prolog_atom_start).
   23part_of_prefix(Code) :- code_type(Code, prolog_identifier_continue).
   24
   25get_prefix_codes(Stream, Offset, Codes) :-
   26    get_prefix_codes(Stream, Offset, [], Codes).
   27
   28get_prefix_codes(Stream, Offset0, Codes0, Codes) :-
   29    peek_code(Stream, Code),
   30    part_of_prefix(Code), !,
   31    succ(Offset1, Offset0),
   32    seek(Stream, Offset1, bof, Offset),
   33    get_prefix_codes(Stream, Offset, [Code|Codes0], Codes).
   34get_prefix_codes(_, _, Codes, Codes).
   35
   36prefix_at(File, Position, Prefix) :-
   37    doc_text_fallback(File, DocCodes),
   38    setup_call_cleanup(
   39        open_string(DocCodes, Stream),
   40        ( linechar_offset(Stream, Position, _),
   41          seek(Stream, -1, current, Offset),
   42          get_prefix_codes(Stream, Offset, PrefixCodes),
   43          string_codes(Prefix, PrefixCodes) ),
   44        close(Stream)
   45    ).
   46
   47completions_at(File, Position, Completions) :-
   48    prefix_at(File, Position, Prefix),
   49    xref_source(File, [silent(true)]),
   50    findall(
   51        Result,
   52        ( xref_defined(File, Goal, _),
   53          functor(Goal, Name, Arity),
   54          atom_concat(Prefix, _, Name),
   55          args_str(Arity, Args),
   56          format(string(Func), "~w(~w)$0", [Name, Args]),
   57          format(string(Label), "~w/~w", [Name, Arity]),
   58          Result = _{label: Label,
   59                     insertText: Func,
   60                     insertTextFormat: 2}),
   61        Completions
   62    ).
   63
   64args_str(Arity, Str) :-
   65    numlist(1, Arity, Args),
   66    maplist([A, S]>>format(string(S), "${~w:_}", [A]),
   67           Args, ArgStrs),
   68    atomic_list_concat(ArgStrs, ', ', Str)