README.org
August 5, 2025 · View on GitHub
- Prolog Language server
/Recent development has been sponsored by [[https://logicmoo.org][LogicMoo]] - Thank you!/
Still a work-in-progress -- please open an issue if you have any issues or feature requests!.
Currently supports:
- diagnostics (singleton variables, syntax errors) via xref
- find references/definitions
- documentation of predicates on hover
- auto-completion of predicates
- code formatting (✨new!✨)
- symbol highlighting (✨new!✨)
- variable renaming (✨new!✨)
The code formatter can also be run stand-alone. After installing the lsp_server pack, you can run swipl formatter at the command line.
Only tested with SWI-Prolog, as it heavily uses its introspection facilities to do its stuff.
It should work with any relatively-recent version of SWI-Prolog, but for best results (for "find references" in particular), use a version with xref_called/5 (8.1.5 or newer; past commit [[https://github.com/SWI-Prolog/swipl-devel/commit/303f6430de5c9d7e225d8eb6fb8bb8b59e7c5f8f][303f6430de5c]]).
Installable as a pack with swipl pack install lsp_server or ?- pack_install(lsp_server). from a repl.
As of version 2.5.0, running the server over a socket is now supported by passing in the commandline arguments port (instead of stdio).
If running on Windows directly (i.e. not via WSL) running the server via stdio will NOT work and you will need to run the server over a socket, so please consult that section of the documention for your editor..
- Emacs
** [[https://github.com/emacs-lsp/lsp-mode][lsp-mode]]:
*** socket server
#+begin_src emacs-lisp (lsp-register-client (make-lsp-client :new-connection (lsp-tcp-connection (lambda (port) (list "swipl" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "port" port))) :major-modes '(prolog-mode) :priority 1 :multi-root t :server-id 'prolog-ls)) #+end_src *** stdio server
#+begin_src emacs-lisp (lsp-register-client (make-lsp-client :new-connection (lsp-stdio-connection (list "swipl" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "stdio")) :major-modes '(prolog-mode) :priority 1 :multi-root t :server-id 'prolog-ls)) #+end_src
** [[https://github.com/joaotavora/eglot][eglot]] *** socket server #+begin_src emacs-lisp (setopt eglot-server-programs (cons (cons 'prolog-mode (list "swipl" "-O" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "port" :autoport)) eglot-server-programs)) #+end_src
*** stdio server #+begin_src emacs-lisp (setopt eglot-server-programs (cons (cons 'prolog-mode (list "swipl" "-O" "-g" "use_module(library(lsp_server))." "-g" "lsp_server:main" "-t" "halt" "--" "stdio")) eglot-server-programs)) #+end_src
-
Vim/Neovim
-
Neovim ** [[https://github.com/neoclide/coc.nvim][CoC]] *** stdio server Put the following in
coc-settings.json(which you can access by using the command:CocConfig).
#+begin_src json {"languageserver": { "prolog-lsp": { "command": "swipl", "args": ["-g", "use_module(library(lsp_server)).", "-g", "lsp_server:main", "-t", "halt", "--", "stdio" ], "filetypes": ["prolog"] }} } #+end_src *** socket server
CoC does not support automatically starting a socket server. If you are on Windows and using CoC and hence need a socket server, you'll have to manually start the LSP process by running the following command:
#+begin_src sh swipl -g 'use_module(library(lsp_server))' -g 'lsp_server:main' -t halt -- port 12345 #+end_src
Where "12345" is an arbitrary, free port number.
Then, with that started, add the following to coc-settings.json (accessed via :CocConfig).
#+begin_src json {"languageserver": { "prolog-lsp": { "host": "127.0.0.1", "port": 12345, "filetypes": ["prolog"] }} } #+end_src
Ensuring the port entered in the config is the same one used when starting the server process
** Native LSP (for Neovim >= 0.11)
*** stdio server
Put the following in $XDG_CONFIG_DIR/nvim/lsp/prolog.lua:
#+begin_src lua return { cmd = { 'swipl', '-g', 'use_module(library(lsp_server))', '-g', 'lsp_server:main', '-t', 'halt', '--', 'stdio' }, root_markers = { '.git', }, filetypes = { 'prolog' }, } #+end_src
And add vim.lsp.enable({'prolog'}) to $XDG_CONFIG_DIR/nvim/init.lua.
*** socket server
Put the following in $XDG_CONFIG_DIR/nvim/lsp/prolog.lua:
#+begin_src lua local find_port = function() local uv = vim.uv local tcp = uv.new_tcp() tcp:bind("127.0.0.1", 0) local port = tcp:getsockname().port tcp:close_reset() return port end return { cmd = function(...) local server_port = find_port() vim.system({'swipl', '-g', 'use_module(library(lsp_server))', '-g', 'lsp_server:main', '-t', 'halt', '--', 'port', server_port}, {}, function(...) print("LSP PROCESS EXITED", ...) end) vim.uv.sleep(500) return vim.lsp.rpc.connect('127.0.0.1', server_port)(...) end, root_markers = { '.git', }, filetypes = { 'prolog' }, } #+end_src
And add vim.lsp.enable({'prolog'}) to $XDG_CONFIG_DIR/nvim/init.lua.
** Native LSP (for Neovim >= 0.5 < 0.11)
Install the [[https://github.com/neovim/nvim-lspconfig][neovim/nvim-lspconfig]] package
Put the following in $XDG_CONFIG_DIR/nvim/lua/lspconfig/prolog_lsp.lua:
#+begin_src lua local configs = require 'lspconfig/configs' local util = require 'lspconfig/util'
configs.prolog_lsp = { default_config = { cmd = {"swipl", "-g", "use_module(library(lsp_server)).", "-g", "lsp_server:main", "-t", "halt", "--", "stdio"}; filetypes = {"prolog"}; root_dir = util.root_pattern("pack.pl"); }; docs = { description = [[ https://github.com/jamesnvc/prolog_lsp
Prolog Language Server ]]; } } -- vim:et ts=2 sw=2 #+end_src
Then add the following to init.vim:
#+begin_src viml lua << EOF require('lspconfig/prolog_lsp') require('lspconfig').prolog_lsp.setup{} EOF #+end_src
- LazyVim
** stdio
Create the following file in $XDG_CONFIG_DIR/nvim/lua/plugins/lsp.lua
#+begin_src lua return { { "neovim/nvim-lspconfig", opts = { servers = { prolog = {}, }, setup = { prolog = function(_, opts) local lspconfig = require("lspconfig") local configs = require("lspconfig.configs") local util = require("lspconfig.util")
local root_files = { ".git", "pack.pl" }
if not configs.prolog then
configs.prolog = {
default_config = {
cmd = {
"swipl",
"-g",
"use_module(library(lsp_server)).",
"-g",
"lsp_server:main",
"-t",
"halt",
"--",
"stdio",
},
filetypes = { "prolog" },
single_file_support = true,
root_dir = util.root_pattern(unpack(root_files)),
settings = {},
},
commands = {},
docs = {
description = [[
Prolog LSP server
]],
},
}
end
lspconfig.prolog.setup(opts)
end,
},
},
}, } #+end_src
- VSCode
Choose one from the list below:
- download the latest
.vsixfile from the [[https://github.com/jamesnvc/lsp_server/releases][releases page]] - clone this repo and copy/symlink the
vscode/directory to ~~/.vscode/extensions/~ - clone and build the
.vsixfile yourself by the follwing steps:cd /path/to/clone/vscodenpm installnpx vsce package- add the resulting
.vsixto VSCode by clicking the...at the top right of the "Extensions" panel then selectingInstall from VSIX...
- Helix
Helix already includes configuration for this Prolog LSP server, so it should mostly Just Work.
However, the default configuration gives the '.pl' extension to perl, so to avoid having to manually do :set-language prolog each time, you can add the following to $XDG_CONFIG/helix/languages.toml to remove Perl's association with that extension:
#+begin_src toml [[language]] name = "perl" file-types = ["perl"] #+end_src