From 4c77104c2efb6d5200389182034d83e6fcd42e8a Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Fri, 7 Jul 2023 00:07:11 +0900 Subject: [PATCH] Add RuboCop built-in launguage server for linting Ruby code RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter: https://github.com/rubocop/rubocop RuboCop provides built-in language server, as detailed here: https://docs.rubocop.org/rubocop/usage/lsp.html. This PR introduces a client for this server. --- CHANGELOG.org | 1 + clients/lsp-rubocop.el | 83 ++++++++++++++++++++++++++++++++++++++++++ docs/lsp-clients.json | 9 +++++ lsp-mode.el | 4 +- mkdocs.yml | 1 + 5 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 clients/lsp-rubocop.el diff --git a/CHANGELOG.org b/CHANGELOG.org index d6f41b3e7e7..8142bc3e517 100644 --- a/CHANGELOG.org +++ b/CHANGELOG.org @@ -80,6 +80,7 @@ * Remove custom variable ~lsp-inlay-hint-enum-format~ since LSP Specification 3.17 only has ~type~ and ~parameter~ hint kinds. * Add [[https://semgrep.dev][Semgrep]] support + * Add [https://github.com/rubocop/rubocop][RuboCop built-in language server]] for linting Ruby code. ** Release 8.0.0 * Add ~lsp-clients-angular-node-get-prefix-command~ to get the Angular server from another location which is still has ~/lib/node_modules~ in it. * Set ~lsp-clients-angular-language-server-command~ after the first connection to speed up subsequent connections. diff --git a/clients/lsp-rubocop.el b/clients/lsp-rubocop.el new file mode 100644 index 00000000000..6d550848490 --- /dev/null +++ b/clients/lsp-rubocop.el @@ -0,0 +1,83 @@ +;;; lsp-rubocop.el --- lsp-mode for RuboCop -*- lexical-binding: t; -*- + +;; Copyright (C) 2023 Koichi Ito + +;; Author: Koichi Ito +;; Keywords: lsp, ruby, languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; LSP client for RuboCop which is a Ruby static code analyzer (a.k.a. linter) +;; and code formatter. + +;;; Code: + +(require 'lsp-mode) + +(defgroup lsp-rubocop nil + "LSP support for RuboCop, using the RuboCop built-in language server." + :group 'lsp-mode + :link '(url-link "https://github.com/rubocop/rubocop") + :package-version '(lsp-mode . "8.0.1")) + +(defcustom lsp-rubocop-diagnostics t + "Enable diagnostics" + :type 'boolean + :group 'lsp-rubocop + :package-version '(lsp-mode . "8.0.1")) + +(defcustom lsp-rubocop-formatting t + "Enable document formatting" + :type 'boolean + :group 'lsp-rubocop + :package-version '(lsp-mode . "8.0.1")) + +(defcustom lsp-rubocop-use-bundler nil + "Run RuboCop using Bundler." + :type 'boolean + :safe #'booleanp + :group 'lsp-rubocop + :package-version '(lsp-mode . "8.0.1")) + +(defcustom lsp-rubocop-server-path nil + "Path of the RuboCop built-in language server executable. +If specified, `lsp-rubocop-use-bundler' is ignored." + :type 'file + :group 'lsp-rubocop + :package-version '(lsp-mode . "8.0.1")) + +(defun lsp-rubocop--build-command () + "Build a command to start the RuboCop built-in language server." + (append + (if (and lsp-rubocop-use-bundler (not lsp-rubocop-server-path)) '("bundle" "exec")) + (list (or lsp-rubocop-server-path "rubocop") "--lsp"))) + +(lsp-register-custom-settings + '(("rubocop.formatting" lsp-rubocop-formatting t) + ("rubocop.diagnostics" lsp-rubocop-diagnostics t) + ("rubocop.useBundler" lsp-rubocop-use-bundler t))) + +(lsp-register-client + (make-lsp-client + :new-connection (lsp-stdio-connection #'lsp-rubocop--build-command) + :activation-fn (lsp-activate-on "ruby") + :priority -1 + :server-id 'rubocop-ls)) + +(lsp-consistency-check lsp-rubocop) + +(provide 'lsp-rubocop) +;;; lsp-rubocop.el ends here diff --git a/docs/lsp-clients.json b/docs/lsp-clients.json index f2f63ee094e..00d1f43757c 100644 --- a/docs/lsp-clients.json +++ b/docs/lsp-clients.json @@ -714,6 +714,15 @@ "installation": "npm i -g remark-language-server", "debugger": "Not available" }, + { + "name": "robocop", + "full-name": "Ruby (RuboCop)", + "server-name": "rubocop", + "server-url": "https://github.com/rubocop/rubocop", + "installation-url": "https://docs.rubocop.org/rubocop/installation.html", + "installation": "gem install rubocop", + "debugger": "Not available" + }, { "name": "robot", "full-name": "robot framework", diff --git a/lsp-mode.el b/lsp-mode.el index fe5942c0eb5..185c2016018 100644 --- a/lsp-mode.el +++ b/lsp-mode.el @@ -183,8 +183,8 @@ As defined by the Language Server Protocol 3.16." lsp-lua lsp-markdown lsp-marksman lsp-mint lsp-nginx lsp-nim lsp-nix lsp-magik lsp-metals lsp-mssql lsp-ocaml lsp-openscad lsp-pascal lsp-perl lsp-perlnavigator lsp-pls lsp-php lsp-pwsh lsp-pyls lsp-pylsp lsp-pyright lsp-python-ms lsp-purescript - lsp-r lsp-racket lsp-remark lsp-ruff-lsp lsp-rf lsp-rust lsp-semgrep lsp-shader lsp-solargraph - lsp-sorbet lsp-sourcekit lsp-sonarlint lsp-tailwindcss lsp-tex lsp-terraform + lsp-r lsp-racket lsp-remark lsp-ruff-lsp lsp-rf lsp-rubocop lsp-rust lsp-semgrep lsp-shader + lsp-solargraph lsp-sorbet lsp-sourcekit lsp-sonarlint lsp-tailwindcss lsp-tex lsp-terraform lsp-toml lsp-ttcn3 lsp-typeprof lsp-v lsp-vala lsp-verilog lsp-vetur lsp-volar lsp-vhdl lsp-vimscript lsp-xml lsp-yaml lsp-ruby-lsp lsp-ruby-syntax-tree lsp-sqls lsp-svelte lsp-steep lsp-tilt lsp-zig) diff --git a/mkdocs.yml b/mkdocs.yml index 89a281607c1..285c7313f12 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -125,6 +125,7 @@ nav: - R: page/lsp-r.md - Racket (jeapostrophe): page/lsp-racket-langserver.md - Racket (Theia): page/lsp-racket-language-server.md + - Ruby (RuboCop): page/lsp-rubocop.md - Ruby (ruby-lsp): page/lsp-ruby-lsp.md - Ruby (Solargraph): page/lsp-solargraph.md - Ruby (Sorbet): page/lsp-sorbet.md