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

#+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 .vsix file 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 .vsix file yourself by the follwing steps:
    1. cd /path/to/clone/vscode
    2. npm install
    3. npx vsce package
    4. add the resulting .vsix to VSCode by clicking the ... at the top right of the "Extensions" panel then selecting Install 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