flint-ls

command module
v0.0.0-...-7516fb6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 2, 2026 License: MIT Imports: 9 Imported by: 0

README

flint-ls

Actions Status

General purpose Language Server that can spawn formatters and linters.

linting

Description

This is a fork of efm-langserver that will maintain and develop separately. It is a cleaned up and simplified version of the original. It supports a subset of original configuration - only for formatting and linting. No code actions, completions, hover etc.

Notable changes from the original:

  • no config.yaml, settings need to be passed via DidChangeConfiguration
  • only linting and formatting (for now)
  • all formatters must support stdin, non-stdin formatters won't work. Option formatStdin was removed.
  • fixed behavior of LintIgnoreExitCode - when true, output is parsed for errors even if exit code is 0. Previously each lint command that resulted in exit code 0 was considered a problem, but exit code 0 is ok in situations when there's no lint issues.
  • better diffs handling for formatting (no more "format twice to remove an extra newline")
    • external, maintained diff library used for that
  • support for errorformat's end line and end column
  • added tests (always in progress)
  • refactored, cleaned and more maintainable code (always in progress)
  • fixed and applied sane defaults for options like LintAfterOpen, LintOnSave etc.
  • removed explicit support for LintWorkspace (linters that lint the whole workspace and do not need filename)
    • it may be implemented back in the future if needed, but I've no usage of such linters, and a quick search through creativenull/efmls-configs-nvim showed no usage of this property
    • tracked in #11
  • added Lsp Progress notifications, sent only to clients that advertise window.workDoneProgress
  • removed RootMarkers from root settings. They can only be provided per language now. The use of this was questionable.

Sections

Installation

go install github.com/konradmalik/flint-ls@latest

or via nix. Flake provided in this repo.

nix build

Usage

Usage of flint-ls:
  -h    Show help
  -logfile string
        File to save logs into. If provided stderr won't be used anymore.
  -loglevel int
        Set the log level. Max is 3 (debug), min is 0 (error). Higher number logs less. Set <0 for no logs. (default 2)
  -v    Print the version
Configuration

Configuration can be done through a DidChangeConfiguration notification from the client. DidChangeConfiguration can be called any time and will overwrite only provided properties (note though that per language configuration will be overwritten as a whole array).

DidChangeConfiguration cannot set LogFile.

flint-ls does not include formatters/linters for any language. You must install these manually, e.g.

InitializeParams

Because the configuration can be updated on the fly, capabilities might change throughout the lifetime of the server. To enable support for capabilities that will be available later, set them in the InitializeParams

Example

{
    "initializationOptions": {
        "documentFormatting": true,
        "documentRangeFormatting": true
    }
}
Example for DidChangeConfiguration notification
{
    "settings": {
        "languages": {
            "lua": {
                "formatCommand": "lua-format -i"
            }
        }
    }
}
Full config
type Config struct {
	Languages map[string][]Language `json:"languages,omitempty"`
	// how long a document must be idle before it is linted, in nanoseconds.
	// defaults to 100ms; debouncing is per document
	LintDebounce time.Duration `json:"lintDebounce,omitempty"`
}

type Language struct {
	Env           []string `json:"env,omitempty"`
	RootMarkers   []string `json:"rootMarkers,omitempty"`
	RequireMarker bool     `json:"requireMarker,omitempty"`
	// prefix for lint message
	Prefix      string   `json:"prefix,omitempty"`
	LintFormats []string `json:"lintFormats,omitempty"`
	LintStdin   bool     `json:"lintStdin,omitempty"`
	// warning: this will be subtracted from the line reported by the linter
	LintOffset int `json:"lintOffset,omitempty"`
	// warning: this will be added to the column reported by the linter
	LintOffsetColumns  int                `json:"lintOffsetColumns,omitempty"`
	LintCommand        string             `json:"lintCommand,omitempty"`
	LintIgnoreExitCode bool               `json:"lintIgnoreExitCode,omitempty"`
	LintCategoryMap    map[string]string  `json:"lintCategoryMap,omitempty"`
	LintSource         string             `json:"lintSource,omitempty"`
	LintSeverity       DiagnosticSeverity `json:"lintSeverity,omitempty"`
	// defaults to true if not provided as a sanity default
	LintAfterOpen *bool `json:"lintAfterOpen,omitempty"`
	// defaults to true if not provided as a sanity default
	LintOnChange *bool `json:"lintOnChange,omitempty"`
	// defaults to true if not provided as a sanity default
	LintOnSave    *bool  `json:"lintOnSave,omitempty"`
	FormatCommand string `json:"formatCommand,omitempty"`
	// whether formatCommand can format a range; only such formatters run for a
	// range formatting request
	FormatCanRange bool `json:"formatCanRange,omitempty"`
}

Also note that there's a wildcard for language name =. So if you want to define some config entry for all languages, you can use = as a key.

Placeholders

lintCommand and formatCommand may use the following placeholders:

placeholder value
${INPUT} path of the document being processed, with / separators
${FILENAME} the same path, with the platform's separators
${ROOT} working directory the command runs in
${FILEEXT} extension of the document, without the leading dot

Commands run through a shell. A path placeholder that you leave bare is quoted for you, so paths containing spaces or other characters the shell would act on still reach the tool as a single argument. A placeholder you quote yourself is substituted as-is, since the quoting it needs is already there — both styles work, and configs written for efm-langserver need no changes:

"lintCommand": "eslint -f visualstudio --stdin --stdin-filename ${INPUT}", // quoted for you
"lintCommand": "cspell lint --no-color \"${INPUT}\"",                      // your quotes are kept

${FILEEXT} is never quoted, as it is meant to be substituted mid-word (foo.${FILEEXT}).

Formatting

All formatters must support stdin. When a formatter uses non-stdin in replaces file contents on disk which leads to confusing and unpredictable results.

Client Setup

Configuration for neovim builtin LSP with nvim-lspconfig

Neovim's built-in LSP client sends DidChangeConfiguration.

require "lspconfig".flint_ls.setup {
    init_options = {documentFormatting = true},
    settings = {
        languages = {
            lua = {
                {formatCommand = "lua-format -i"}
            }
        }
    }
}

You can get premade tool definitions from creativenull/efmls-configs-nvim:

lua = {
  require('efmls-configs.linters.luacheck'),
  require('efmls-configs.formatters.stylua'),
}

If you define your own, make sure to define as a table of tables:

lua = {
    {formatCommand = "lua-format -i"}
}

-- and for multiple formatters, add to the table
lua = {
    {formatCommand = "lua-format -i"},
    {formatCommand = "lua-pretty -i"}
}
Configuration for coc.nvim

coc-settings.json

  // languageserver
  "languageserver": {
    "flint-ls": {
      "command": "flint-ls",
      "args": [],
      "filetypes": ["vim", "eruby", "markdown", "yaml"]
    }
  },
Configuration for VSCode

Generic LSP Client for VSCode

Example settings.json (change to fit your local installs):

{
    "glspc.languageId": "lua",
    "glspc.serverCommand": "/Users/me/.local/share/nvim/mason/bin/flint-ls",
    "glspc.pathPrepend": "/Users/me/.local/share/rtx/installs/python/3.11.4/bin:/Users/me/.local/share/rtx/installs/node/20.3.1/bin"
}
Configuration for Helix

~/.config/helix/languages.toml

[language-server.flint-ls]
command = "flint-ls"

[[language]]
name = "typescript"
language-servers = [
  { name = "flint-ls", only-features = [ "diagnostics", "format" ] },
  { name = "typescript-language-server", except-features = [ "format" ] }
]
Configuration for SublimeText LSP

Open Preferences: LSP Settings command from the Command Palette (Ctrl+Shift+P)

{
	"clients": {
	    "flint-ls": {
	      "enabled": true,
	      "command": ["flint-ls"],
	      "selector": "source.c | source.php | source.python" // see https://www.sublimetext.com/docs/3/selectors.html
	    }
  	}
}
Configuration for vim-lsp
augroup LspFlint
  au!
  autocmd User lsp_setup call lsp#register_server({
      \ 'name': 'flint-ls',
      \ 'cmd': {server_info->['flint-ls']},
      \ 'allowlist': ['vim', 'eruby', 'markdown', 'yaml'],
      \ })
augroup END

vim-lsp-settings provide installer for flint-ls.

Configuration for Eglot (Emacs)

Add to eglot-server-programs with major mode you want.

(with-eval-after-load 'eglot
  (add-to-list 'eglot-server-programs
    `(markdown-mode . ("flint-ls"))))

License

MIT

Authors

  • Yasuhiro Matsumoto (a.k.a. mattn) before 2025-04-29 (original flint-ls author)
  • Konrad Malik after 2025-04-29 (author and maintainer of this fork)

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL