Repository: go
Issue: x/tools/gopls: workspace/didChangeWatchedFiles RegisterCapability globs are too broad
Labels: help wanted,NeedsFix,gopls,Tools

<!-- Please answer these questions before submitting your issue. Thanks! -->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version devel +06f7e655d1 Fri Sep 18 07:56:50 2020 +0000 linux/amd64
$ go list -m golang.org/x/tools
golang.org/x/tools v0.0.0-20200918232735-d647fc253266
$ go list -m golang.org/x/tools/gopls
golang.org/x/tools/gopls v0.0.0-20200918232735-d647fc253266
</pre>

### Does this issue reproduce with the latest release?

Yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/myitcv/.cache/go-build"
GOENV="/home/myitcv/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/myitcv/gostuff/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/myitcv/gostuff"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/myitcv/gos"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/myitcv/gos/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/myitcv/gostuff/src/github.com/myitcv/govim/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build962924290=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

Given the following setup:

```
-- blah/blah.go --
package blah

const Message = "hello"
-- blah/go.mod --
module blah.com

go 1.16
-- go.mod --
module mod.com

go 1.16

require blah.com v0.0.0-00010101000000-000000000000

replace blah.com => ./blah
-- go.sum --
-- main.go --
package main

import (
	"fmt"

	"blah.com"
)

func main() {
	fmt.Println(blah.Message)
}
```

I loaded `govim`.

### What did you expect to see?

Precise `workspace/didChangeWatchedFiles` globls in any `RegisterCapability` call.

### What did you see instead?

```
RegisterCapability: &protocol.RegistrationParams{
    Registrations: {
        {
            ID:              "workspace/didChangeWatchedFiles-0",
            Method:          "workspace/didChangeWatchedFiles",
            RegisterOptions: map[string]interface {}{
                "watchers": []interface {}{
                    map[string]interface {}{
                        "globPattern": "**/*.{go,mod,sum}",
                        "kind":        float64(7),
                    },
                    map[string]interface {}{
                        "globPattern": "/home/myitcv/gostuff/src/github.com/myitcv/playground/blah/**/*.{go,mod,sum}",
                        "kind":        float64(7),
                    },
                    map[string]interface {}{
                        "globPattern": "/home/myitcv/gostuff/src/github.com/myitcv/playground/**/*.{go,mod,sum}",
                        "kind":        float64(7),
                    },
                },
            },
        },
    },
}
```

_Side note: the working directory of `govim` (and therefore `gopls`) in this case was `/home/myitcv/gostuff/src/github.com/myitcv/playground`, so the first and third watchers appear to be duplicates._

If I understand the [glob spec](https://microsoft.github.io/language-server-protocol/specifications/specification-3-16/#workspace_didChangeWatchedFiles), `**/*.{go,mod,sum}` means "all `.go`, `.mod` and `.sum` files in all subdirectories". 

The recursive descent into subdirectories does not stop at directories whose names start with `.` or `_`, or those that contain `go.mod` files. This can, and does, make this watch very expensive if, for example, you have a directory like `node_modules` that contains lots of files that are and always will be totally irrelevant to `gopls` (the advice here is to put a `go.mod` in that directory). 

I suspect this situation is somewhat a function of the LSP spec, but can these globs be made more specific in some way?

An approach to [`.gitignore` patterns](https://git-scm.com/docs/gitignore) would work for example.


---


cc @stamblerre

FYI @leitzler