Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent multiple linters running for the same URI #82

Merged
merged 2 commits into from
Dec 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 41 additions & 15 deletions langserver/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,24 +212,42 @@ func (h *langHandler) logMessage(typ MessageType, message string) {
}

func (h *langHandler) linter() {
running := make(map[DocumentURI]context.CancelFunc)

for {
uri, ok := <-h.request
if !ok {
break
}
diagnostics, err := h.lint(uri)
if err != nil {
h.logger.Println(err)
continue

cancel, ok := running[uri]
if ok {
cancel()
}
h.conn.Notify(
context.Background(),
"textDocument/publishDiagnostics",
&PublishDiagnosticsParams{
URI: uri,
Diagnostics: diagnostics,
Version: h.files[uri].Version,
})

ctx, cancel := context.WithCancel(context.Background())
running[uri] = cancel

go func() {
diagnostics, err := h.lint(ctx, uri)
if err != nil {
h.logger.Println(err)
return
}

if diagnostics == nil {
return
}

h.conn.Notify(
context.Background(),
"textDocument/publishDiagnostics",
&PublishDiagnosticsParams{
URI: uri,
Diagnostics: diagnostics,
Version: h.files[uri].Version,
})
}()
}
}

Expand Down Expand Up @@ -302,7 +320,7 @@ func isFilename(s string) bool {

}

func (h *langHandler) lint(uri DocumentURI) ([]Diagnostic, error) {
func (h *langHandler) lint(ctx context.Context, uri DocumentURI) ([]Diagnostic, error) {
f, ok := h.files[uri]
if !ok {
return nil, fmt.Errorf("document not found: %v", uri)
Expand Down Expand Up @@ -362,16 +380,24 @@ func (h *langHandler) lint(uri DocumentURI) ([]Diagnostic, error) {

var cmd *exec.Cmd
if runtime.GOOS == "windows" {
cmd = exec.Command("cmd", "/c", command)
cmd = exec.CommandContext(ctx, "cmd", "/c", command)
} else {
cmd = exec.Command("sh", "-c", command)
cmd = exec.CommandContext(ctx, "sh", "-c", command)
}
cmd.Dir = h.findRootPath(fname, config)
cmd.Env = append(os.Environ(), config.Env...)
if config.LintStdin {
cmd.Stdin = strings.NewReader(f.Text)
}
b, err := cmd.CombinedOutput()
if err != nil {
exitErr, ok := err.(*exec.ExitError)
// When the context is canceled, the process is killed,
// and the exit code is -1
if ok && exitErr.ExitCode() < 0 {
return nil, nil
}
}
// Most of lint tools exit with non-zero value. But some commands
// return with zero value. We can not handle the output is real result
// or output of usage. So efm-langserver ignore that command exiting
Expand Down
9 changes: 5 additions & 4 deletions langserver/handler_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package langserver

import (
"context"
"log"
"os"
"path/filepath"
Expand All @@ -17,7 +18,7 @@ func TestLintNoLinter(t *testing.T) {
},
}

_, err := h.lint("file:///foo")
_, err := h.lint(context.Background(), "file:///foo")
if err != nil {
t.Fatal("Should not be an error if no linters")
}
Expand All @@ -32,7 +33,7 @@ func TestLintNoFileMatched(t *testing.T) {
},
}

_, err := h.lint("file:///bar")
_, err := h.lint(context.Background(), "file:///bar")
if err == nil {
t.Fatal("Should be an error if no linters")
}
Expand Down Expand Up @@ -63,7 +64,7 @@ func TestLintFileMatched(t *testing.T) {
},
}

d, err := h.lint(uri)
d, err := h.lint(context.Background(), uri)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -109,7 +110,7 @@ func TestLintFileMatchedForce(t *testing.T) {
},
}

d, err := h.lint(uri)
d, err := h.lint(context.Background(), uri)
if err != nil {
t.Fatal(err)
}
Expand Down