meatwallace / dotfiles

:whale2::computer::rocket: dotfiles in docker
https://meatbox.one
The Unlicense
14 stars 1 forks source link

investigate shfmt and shellcheck with coc.nvim #129

Open meatwallace opened 5 years ago

nathanshelly commented 4 years ago

Came across this issue as the top result when searching shfmt coc.nvim. Figured I'd share what I did in case it helps anyone else who comes across this.

Below are two similar but slightly different configurations depending on whether you use coc.nvim extensions or not. Both configuration strategies require installing shellcheck and shfmt separately.

If you use Homebrew run brew install shfmt shellcheck to install both.

If you use coc.nvim extensions

Install coc-diagnostic - :CocInstall coc-diagnostic.

This extension will automatically install diagnostic-languageserver for you.

Add the following config top-level (nested only inside the outermost {}) in your coc-settings.json:

"diagnostic-languageserver.filetypes": {
  // lint `sh` (includes `bash`) files
  "sh": "shellcheck"
},
"diagnostic-languageserver.formatFiletypes": {
  // format `sh` (includes `bash`) files using formatter defined below
  "sh": "shfmt"
},
"diagnostic-languageserver.formatters": {
  // define our formatter so that we can reference it from
  // `diagnostic-languageserver.formatFiletypes`
  "shfmt": {
    "command": "shfmt",
    // all the below args are entirely optional
    // primarily listed here to call out that flags which take an
    // argument (such as `-i <num-spaces>` for specifying indentation)
    // should be split into two strings, the flag and then the value
    "args": ["-i", "2", "-bn", "-ci", "-sr"]
  }
},

You should now have linting & formatting for shell scripts!

If you don't use extensions (or use a different language server client)

Install diagnostic-languageserver by running yarn global add diagnostic-languageserver.

Add the following config top-level (nested only inside the outermost {}) in your coc-settings.json (or corresponding settings file for other language server clients):

All configuration below besides the shfmt settings taken from this example. Note: the header suggests this example is coc.nvim specific but it should translate well to other clients. See additional details in this issue.

{
  "languageserver": {
    "dls": {
      "command": "diagnostic-languageserver",
      "args": ["--stdio"],
      "filetypes": ["sh"],
      "initializationOptions": {
        // <<< start of config for shellcheck >>>
        "filetypes": {
          // lint `sh` (includes `bash`) files
          "sh": "shellcheck"
        },
        "linters": {
          // set up `shellcheck`, this lifted directly from example on README
          "shellcheck": {
            "command": "shellcheck",
            "debounce": 100,
            "args": ["--format=gcc", "-"],
            "offsetLine": 0,
            "offsetColumn": 0,
            "sourceName": "shellcheck",
            "formatLines": 1,
            "formatPattern": [
              "^[^:]+:(\\d+):(\\d+):\\s+([^:]+):\\s+(.*)$",
              {
                "line": 1,
                "column": 2,
                "message": 4,
                "security": 3
              }
            ],
            "securities": {
              "error": "error",
              "warning": "warning",
              "note": "info"
            }
          }
        },
        // <<< start of config for shfmt >>>
        "formatFiletypes": {
          // format `sh` (includes `bash`) files using formatter defined below
          "sh": "shfmt"
        },
        "formatters": {
          // define our formatter so that we can reference it from `formatFiletypes`
          "shfmt": {
            "command": "shfmt",
            // all the below args are entirely optional
            // primarily listed here to call out that flags which take an
            // argument (such as `-i <num-spaces>` for specifying indentation)
            // should be split into two strings, the flag and then the value
            "args": ["-i", "2", "-bn", "-ci", "-sr"]
          }
        },
      }
    }
  }
}

You should now have linting & formatting for shell scripts!

raine commented 4 years ago

Thank you @nathanshelly. The setup for coc.nvim worked for me.

The JSON is missing a comma after diagnostic-languageserver.formatFiletypes ending curly brace.

nathanshelly commented 4 years ago

Fixed! Thanks for the heads up @raine 😃

lifeBalance commented 4 years ago

@nathanshelly I tried the :CocInstall coc-diagnostic approach, copy-pasting your settings to my coc-settings.json but every time I start Neovim I get an error:

[coc.nvim] settings file parse error, run ':CocList diagnostics'

I run :CocList diagnostics and I get:

 /Users/bob/.config/nvim/coc-settings.json:1:38 Error [config] end of file expected

Any suggestion would be appreciated ;-)

raine commented 4 years ago

@lifeBalance Did you remove the comments? JSON files can't have comments.

nathanshelly commented 4 years ago

@lifeBalance just to confirm your settings match mine here?

Since you're using coc.nvim there theoretically shouldn't be any issues with comments as it uses jsonc for the config file which does support comments.

lifeBalance commented 4 years ago

Yes, the comments were all in red, so I deleted them. I'm still getting that same error. To be clear I have the same contents in coc-settings.json, and only that.

"diagnostic-languageserver.filetypes": {
  "sh": "shellcheck"
},
"diagnostic-languageserver.formatFiletypes": {
  "sh": "shfmt"
},
"diagnostic-languageserver.formatters": {
  "shfmt": {
    "command": "shfmt",
    "args": ["-i", "2", "-bn", "-ci", "-sr"]
  }
}
nathanshelly commented 4 years ago

~hmm hard to tell what could be going wrong here. Are you willing to post your full coc-settings.json (or link to if it's already public somewhere)?~

Nvm your last message suggests this is the full config. Are these lines wrapped in outer braces? The config should be a single JSON object with these values as keys, for example:

{
  "diagnostic-languageserver.filetypes": {
    "sh": "shellcheck"
  },
  "diagnostic-languageserver.formatFiletypes": {
    "sh": "shfmt"
  },
  "diagnostic-languageserver.formatters": {
    "shfmt": {
      "command": "shfmt",
      "args": ["-i", "2", "-bn", "-ci", "-sr"]
    }
  }
}
lifeBalance commented 4 years ago

Thanks man, that was it, thanks!

unphased commented 3 years ago

I've followed this and shellcheck diagnostics are showing up beautifully, thanks!

I'm unable to figure out how to get shfmt to work though. I can confirm that the command line is able to spit out the formatted output when I run shfmt from the command line, but it's unclear to me how to trigger file formatting through coc. Alright, I figured it out. Just following the default bindings from coc.nvim there are many ways to trigger formatting. Looks like they are triggering shfmt properly!

pvonmoradi commented 3 years ago

@nathanshelly For this to work, shfmt and shellcheck should be in PATH right? coc-nvim can't auto-install them? And doesn't this setting conflict with coc-sh (a LSP for bash)?

nathanshelly commented 3 years ago

hi @pvonmoradi yes shfmt and shellcheck need to be installed separately. Some extensions like coc-sh for example install the underlying language server as they know ahead of time which language server to install (in coc-sh's case a bash language server). The coc-diagnostic extension installs it's own diagnostic-languageserver which acts as the interface to coc-nvim for whatever tools you want to add diagnostics (or formatting in shfmt's case) for.

These days I use Nix to handle all my dependencies but you could use Homebrew or any other method.

I use coc-sh in my own dotfiles alongside this and haven't noticed any issues myself.

hejops commented 3 years ago

My coc-settings.json file is as such (https://github.com/meatwallace/dotfiles/issues/129#issuecomment-631718457), but I get the following error when executing <Plug>(coc-format-selected):

|| [coc.nvim]: Error on notification "formatSelected": formatRange provider not found for current buffer, your language server don't support it.

Both shfmt and shellcheck are installed. Diagnostics with shellcheck work fine. Any idea what I'm doing wrong?

pvonmoradi commented 3 years ago

My coc-settings.json file is as such (#129 (comment)), but I get the following error when executing <Plug>(coc-format-selected):

|| [coc.nvim]: Error on notification "formatSelected": formatRange provider not found for current buffer, your language server don't support it.

Both shfmt and shellcheck are installed. Diagnostics with shellcheck work fine. Any idea what I'm doing wrong?

Is shfmt on PATH? $ type -a shfmt?

hejops commented 3 years ago

Yes, it is:

shfmt is /usr/bin/shfmt
shfmt is /bin/shfmt
hejops commented 3 years ago

:Format seems to work, however. Do these two commands call the formatting engine differently?

pvonmoradi commented 3 years ago

@hejops I don't think :Format is a CoC function. My coc-settings is also like that (https://dpaste.com/A8ASVT4ZF), but the weird thing is your error is about a "language server" those commands should be related to diagnostics...
Are you using latest stable CoC?

hejops commented 3 years ago

Yes:

vim version: VIM - Vi IMproved 8.2 8022489
node version: v15.11.0
coc.nvim version: 0.0.80-9184dcccc4
term: dumb
platform: linux
pvonmoradi commented 3 years ago

Yes:

vim version: VIM - Vi IMproved 8.2 8022489
node version: v15.11.0
coc.nvim version: 0.0.80-9184dcccc4
term: dumb
platform: linux

I just realized I also have coc-sh installed. Can you try that? https://github.com/neoclide/coc.nvim/wiki/Language-servers#bash

" CoC extensions
let g:coc_global_extensions = [
             "coc-sh",
             ]
hejops commented 3 years ago

I already have it installed. I should mention that the format function works as it should in python (autopep8) and js (prettier), so it has certainly something to do with coc-sh and/or coc-diagnostic. I should probably open an issue on one of those repos as well.

laoshaw commented 1 month ago

is this still the same? I have coc-sh and no coc-diagnostics, shfmt is not working for me, how to get shfmt and shellcheck both working with coc-sh