Skip to content

Stability patchset 1 #48

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

Merged
merged 6 commits into from
Jan 21, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Added progress reporting support
  • Loading branch information
cmaglie committed Jan 14, 2021
commit e807d554a7ed0eada0f71c777aa9f8314533d8a0
46 changes: 46 additions & 0 deletions handler/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handler

import (
"bytes"
"context"
"encoding/json"
"log"
"strings"
Expand All @@ -10,6 +11,7 @@ import (
"github.com/arduino/arduino-cli/arduino/libraries"
"github.com/arduino/arduino-cli/executils"
"github.com/arduino/go-paths-helper"
"github.com/bcmi-labs/arduino-language-server/lsp"
"github.com/bcmi-labs/arduino-language-server/streams"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -50,9 +52,53 @@ func (handler *InoHandler) rebuildEnvironmentLoop() {
}

// Regenerate preprocessed sketch!
done := make(chan bool)
go func() {
{
// Request a new progress token
req := &lsp.WorkDoneProgressCreateParams{Token: "arduinoLanguageServerRebuild"}
var resp lsp.WorkDoneProgressCreateResult
if err := handler.StdioConn.Call(context.Background(), "window/workDoneProgress/create", req, &resp, nil); err != nil {
log.Printf(" !!! could not create report progress: %s", err)
<-done
return
}
}

req := &lsp.ProgressParams{Token: "arduinoLanguageServerRebuild"}
req.Value = lsp.WorkDoneProgressBegin{
Title: "Building sketch",
}
if err := handler.StdioConn.Notify(context.Background(), "$/progress", req, nil); err != nil {
log.Printf(" !!! could not report progress: %s", err)
}
count := 0
dots := []string{".", "..", "..."}
for {
select {
case <-time.After(time.Millisecond * 400):
msg := "compiling" + dots[count%3]
count++
req.Value = lsp.WorkDoneProgressReport{Message: &msg}
if err := handler.StdioConn.Notify(context.Background(), "$/progress", req, nil); err != nil {
log.Printf(" !!! could not report progress: %s", err)
}
case <-done:
msg := "done"
req.Value = lsp.WorkDoneProgressEnd{Message: &msg}
if err := handler.StdioConn.Notify(context.Background(), "$/progress", req, nil); err != nil {
log.Printf(" !!! could not report progress: %s", err)
}
return
}
}
}()

handler.synchronizer.DataMux.Lock()
handler.initializeWorkbench(nil)
handler.synchronizer.DataMux.Unlock()
done <- true
close(done)
}
}

Expand Down
12 changes: 11 additions & 1 deletion lsp/protocol_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ func TestDocumentSymbolParse(t *testing.T) {
}

func TestVariousMessages(t *testing.T) {
x := &ProgressParams{
Token: "token",
Value: WorkDoneProgressBegin{
Title: "some work",
},
}
data, err := json.Marshal(&x)
require.NoError(t, err)
require.JSONEq(t, `{"token":"token", "value":{"kind":"begin","title":"some work"}}`, string(data))

msg := `{
"capabilities":{
"codeActionProvider":{
Expand Down Expand Up @@ -107,6 +117,6 @@ func TestVariousMessages(t *testing.T) {
},
"serverInfo":{"name":"clangd","version":"clangd version 11.0.0 (https://github.com/llvm/llvm-project 176249bd6732a8044d457092ed932768724a6f06)"}}`
var init InitializeResult
err := json.Unmarshal([]byte(msg), &init)
err = json.Unmarshal([]byte(msg), &init)
require.NoError(t, err)
}
122 changes: 122 additions & 0 deletions lsp/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"encoding/binary"
"encoding/json"
"errors"
"strings"
)

Expand Down Expand Up @@ -1029,3 +1030,124 @@ type SemanticHighlightingToken struct {
Length uint16
Scope uint16
}

type ProgressParams struct {
Token string `json:"token"`
Value interface{} `json:"value"`
}

type WorkDoneProgressCreateParams struct {
Token string `json:"token"`
}

type WorkDoneProgressCreateResult struct{}

// MarshalJSON implements json.Marshaler.
func (v *WorkDoneProgressCreateResult) MarshalJSON() ([]byte, error) {
return []byte("null"), nil
}

// UnmarshalJSON implements json.Unmarshaler.
func (v *WorkDoneProgressCreateResult) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, []byte("null")) {
return nil
}
return errors.New("expected null")
}

type WorkDoneProgressBegin struct {
Title string `json:"title"`
Cancellable *bool `json:"cancellable,omitempty"`
Message *string `json:"message,omitempty"`
Percentage *int `json:"percentage,omitempty"`
}

// MarshalJSON implements json.Marshaler.
func (v WorkDoneProgressBegin) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Title string `json:"title"`
Cancellable *bool `json:"cancellable,omitempty"`
Message *string `json:"message,omitempty"`
Percentage *int `json:"percentage,omitempty"`
Kind string `json:"kind"`
}{v.Title, v.Cancellable, v.Message, v.Percentage, "begin"})
}

// UnmarshalJSON implements json.Unmarshaler.
func (v *WorkDoneProgressBegin) UnmarshalJSON(data []byte) error {
type ProgressBegin struct {
WorkDoneProgressBegin
Kind string `json:"kind"`
}
var x ProgressBegin
if err := json.Unmarshal(data, &x); err != nil {
return err
}
if x.Kind != "begin" {
return errors.New(`expected kind == "begin"`)
}
*v = x.WorkDoneProgressBegin
return nil
}

type WorkDoneProgressReport struct {
Cancellable *bool `json:"cancellable,omitempty"`
Message *string `json:"message,omitempty"`
Percentage *int `json:"percentage,omitempty"`
}

// MarshalJSON implements json.Marshaler.
func (v WorkDoneProgressReport) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Cancellable *bool `json:"cancellable,omitempty"`
Message *string `json:"message,omitempty"`
Percentage *int `json:"percentage,omitempty"`
Kind string `json:"kind"`
}{v.Cancellable, v.Message, v.Percentage, "report"})
}

// UnmarshalJSON implements json.Unmarshaler.
func (v *WorkDoneProgressReport) UnmarshalJSON(data []byte) error {
type ProgressReport struct {
WorkDoneProgressReport
Kind string `json:"kind"`
}
var x ProgressReport
if err := json.Unmarshal(data, &x); err != nil {
return err
}
if x.Kind != "report" {
return errors.New(`expected kind == "report"`)
}
*v = x.WorkDoneProgressReport
return nil
}

type WorkDoneProgressEnd struct {
Message *string `json:"message,omitempty"`
}

// MarshalJSON implements json.Marshaler.
func (v WorkDoneProgressEnd) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Message *string `json:"message,omitempty"`
Kind string `json:"kind"`
}{v.Message, "end"})
}

// UnmarshalJSON implements json.Unmarshaler.
func (v *WorkDoneProgressEnd) UnmarshalJSON(data []byte) error {
type ProgressEnd struct {
WorkDoneProgressEnd
Kind string `json:"kind"`
}
var x ProgressEnd
if err := json.Unmarshal(data, &x); err != nil {
return err
}
if x.Kind != "end" {
return errors.New(`expected kind == "end"`)
}
*v = x.WorkDoneProgressEnd
return nil
}