Skip to content

Commit

Permalink
Merge branch 'main' of github.com:janpfeifer/gonb
Browse files Browse the repository at this point in the history
  • Loading branch information
janpfeifer committed May 13, 2023
2 parents 6829256 + 0c7464a commit c8091a9
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 61 deletions.
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# GoNB Changelog

## v0.6.1

* Issue #21: Added call to `goimports` and `go get` before trying to get contextual information or auto-complete,
fixing many of the issues with those.

## v0.6.0

* Issue #16: Added package `cache`: implements a convenient cache of values for things that
Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@
"name": "go",
"nbconvert_exporter": "",
"pygments_lexer": "",
"version": "go1.20.3"
"version": "go1.20.2"
}
},
"nbformat": 4,
Expand Down
107 changes: 107 additions & 0 deletions go.sum

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions goexec/errorcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package goexec
import (
"bytes"
"fmt"
"github.com/golang/glog"
"github.com/janpfeifer/gonb/kernel"
"github.com/pkg/errors"
"golang.org/x/exp/constraints"
"html"
"io"
"log"
"os"
"regexp"
"strconv"
Expand Down Expand Up @@ -102,20 +102,24 @@ var templateErrorReport = template.Must(template.New("error_report").Parse(`
// Any errors within here are logged and simply ignored, since this is already
// used to report errors
func (s *State) DisplayErrorWithContext(msg kernel.Message, fileToCellIdAndLine []CellIdAndLine, errorMsg string) {
if msg == nil {
// Ignore, if there is no kernel.Message to reply to.
return
}
// Default report, and makes sure display is called at the end.
reportHTML := "<pre>" + errorMsg + "</pre>" // If anything goes wrong, simply display the error message.
defer func() {
// Display HTML report on exit.
err := kernel.PublishDisplayDataWithHTML(msg, reportHTML)
if err != nil {
log.Printf("Failed to publish data in DisplayErrorWithContext: %+v", err)
glog.Errorf("Failed to publish data in DisplayErrorWithContext: %+v", err)
}
}()

// Read main.go into lines.
mainGo, err := s.readMainGo()
if err != nil {
log.Printf("DisplayErrorWithContext: %+v", err)
glog.Errorf("DisplayErrorWithContext: %+v", err)
return
}
codeLines := strings.Split(mainGo, "\n")
Expand All @@ -130,7 +134,7 @@ func (s *State) DisplayErrorWithContext(msg kernel.Message, fileToCellIdAndLine
// Render error block.
buf := bytes.NewBuffer(make([]byte, 0, 512*len(lines)))
if err := templateErrorReport.Execute(buf, report); err != nil {
log.Printf("Failed to execute template in DisplayErrorWithContext: %+v", err)
glog.Errorf("Failed to execute template in DisplayErrorWithContext: %+v", err)
return
}
reportHTML = buf.String()
Expand Down
28 changes: 16 additions & 12 deletions goexec/execcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (s *State) ExecuteCell(msg kernel.Message, cellId int, lines []string, skip
}

// Exec `goimports` (or the code that implements it)
fileToCellIdAndLine, err = s.GoImports(msg, updatedDecls, mainDecl, fileToCellIdAndLine)
_, fileToCellIdAndLine, err = s.GoImports(msg, updatedDecls, mainDecl, fileToCellIdAndLine)
if err != nil {
return errors.WithMessagef(err, "goimports failed")
}
Expand Down Expand Up @@ -78,8 +78,9 @@ func (s *State) Compile(msg kernel.Message, fileToCellIdAndLines []CellIdAndLine
// GoImports execute `goimports` which adds imports to non-declared imports automatically.
// It also runs "go get" to download any missing dependencies.
//
// It returns an updated fileToCellIdAndLines that reflect any changes in `main.go`.
func (s *State) GoImports(msg kernel.Message, decls *Declarations, mainDecl *Function, fileToCellIdAndLine []CellIdAndLine) ([]CellIdAndLine, error) {
// It returns the updated cursorInFile and fileToCellIdAndLines that reflect any changes in `main.go`.
func (s *State) GoImports(msg kernel.Message, decls *Declarations, mainDecl *Function, fileToCellIdAndLine []CellIdAndLine) (cursorInFile Cursor, updatedFileToCellIdAndLine []CellIdAndLine, err error) {
cursorInFile = NoCursor
goimportsPath, err := exec.LookPath("goimports")
if err != nil {
_ = kernel.PublishWriteStream(msg, kernel.StreamStderr, `
Expand All @@ -90,27 +91,29 @@ can install it from the notebook with:
!go install golang.org/x/tools/cmd/goimports@latest
`)
return nil, errors.WithMessagef(err, "while trying to run goimports\n")
err = errors.WithMessagef(err, "while trying to run goimports\n")
return
}
cmd := exec.Command(goimportsPath, "-w", s.MainPath())
cmd.Dir = s.TempDir
var output []byte
output, err = cmd.CombinedOutput()
if err != nil {
s.DisplayErrorWithContext(msg, fileToCellIdAndLine, string(output)+"\n"+err.Error())
return nil, errors.Wrapf(err, "failed to run %q", cmd.String())
err = errors.Wrapf(err, "failed to run %q", cmd.String())
return
}

// Parse declarations in created `main.go` file.
var newDecls *Declarations
newDecls, err = s.parseFromMainGo(msg, -1, NoCursor, nil)
if err != nil {
return nil, err
return
}

// Find only imports that `goimports` found were used.
usedImports := MakeSet[string]()
for key, _ := range newDecls.Imports {
for key := range newDecls.Imports {
usedImports.Insert(key)
}

Expand All @@ -126,24 +129,25 @@ can install it from the notebook with:
}

delete(newDecls.Functions, "main")
_, fileToCellIdAndLine, err = s.createMainFileFromDecls(newDecls, mainDecl)
cursorInFile, updatedFileToCellIdAndLine, err = s.createMainFileFromDecls(newDecls, mainDecl)
if err != nil {
err = errors.WithMessagef(err, "while composing main.go with all declarations")
return nil, err
return
}

// Download missing dependencies.
if !s.AutoGet {
return fileToCellIdAndLine, nil
return
}
cmd = exec.Command("go", "get")
cmd.Dir = s.TempDir
output, err = cmd.CombinedOutput()
if err != nil {
s.DisplayErrorWithContext(msg, fileToCellIdAndLine, string(output)+"\n"+err.Error())
return nil, errors.Wrapf(err, "failed to run %q", cmd.String())
err = errors.Wrapf(err, "failed to run %q", cmd.String())
return
}
return fileToCellIdAndLine, nil
return
}

// jupyterStackTraceMapperWriter implements an io.Writer that maps stack traces to their corresponding
Expand Down
33 changes: 17 additions & 16 deletions goexec/goplsclient/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"log"
"net"
"strings"
"time"
Expand All @@ -20,7 +19,7 @@ var _ = lsp.MethodInitialize

var (
ConnectTimeout = 2000 * time.Millisecond
CommunicationTimeout = 500 * time.Millisecond
CommunicationTimeout = 2000 * time.Millisecond
)

// jsonrpc2Handler implements jsonrpc2.Handler, listening to incoming events.
Expand Down Expand Up @@ -88,7 +87,7 @@ func (c *Client) Connect(ctx context.Context) error {
// Exec should use a non-expiring context.
ctx := context.Background()
_ = c.jsonConn.Run(ctx)
log.Printf("- gopls connection stopped")
glog.Infof("- gopls connection stopped")
c.mu.Lock()
defer c.mu.Unlock()
if c.conn == currentConn {
Expand Down Expand Up @@ -229,8 +228,10 @@ func (c *Client) callDefinitionLocked(ctx context.Context, filePath string, line
if err != nil {
return nil, errors.Wrapf(err, "failed call to `gopls` \"definition_request\"")
}
for ii, r := range results {
log.Printf(" Result[%d].URI=%s\n", ii, r.URI)
if glog.V(2) {
for ii, r := range results {
glog.Infof(" Result[%d].URI=%s\n", ii, r.URI)
}
}
return
}
Expand Down Expand Up @@ -351,34 +352,34 @@ func (h *jsonrpc2Handler) Deliver(ctx context.Context, r *jsonrpc2.Request, deli
var params lsp.ShowMessageParams
err := json.Unmarshal(*r.WireRequest.Params, &params)
if err != nil {
log.Printf("Failed to parse ShowMessageParams: %v", err)
glog.Errorf("Failed to parse ShowMessageParams: %v", err)
return true
}
h.client.messages = append(h.client.messages, params.Message)
log.Printf("gopls message: %s", trimString(params.Message, 100))
glog.V(1).Infof("gopls message: %s", trimString(params.Message, 100))
return true
case lsp.MethodWindowLogMessage:
var params lsp.LogMessageParams
err := json.Unmarshal(*r.WireRequest.Params, &params)
if err != nil {
log.Printf("Failed to parse LogMessageParams: %v", err)
glog.Errorf("Failed to parse LogMessageParams: %v", err)
return true
}
h.client.messages = append(h.client.messages, params.Message)
log.Printf("gopls message: %s", trimString(params.Message, 100))
glog.V(1).Infof("gopls message: %s", trimString(params.Message, 100))
return true
case lsp.MethodTextDocumentPublishDiagnostics:
var params lsp.PublishDiagnosticsParams
err := json.Unmarshal(*r.WireRequest.Params, &params)
if err != nil {
log.Printf("Failed to parse LogMessageParams: %v", err)
glog.Errorf("Failed to parse LogMessageParams: %v", err)
return true
}
h.client.messages = append(h.client.messages, fmt.Sprintf("Diagnostics:\n%+v", params))
log.Printf("gopls diagnostics: %s", trimString(fmt.Sprintf("%+v", params), 100))
glog.V(1).Infof("gopls diagnostics: %s", trimString(fmt.Sprintf("%+v", params), 100))
return true
default:
log.Printf("gopls jsonrpc2 delivered but not handled: %q", r.Method)
glog.Errorf("gopls jsonrpc2 delivered but not handled: %q", r.Method)
}
return false
}
Expand All @@ -388,15 +389,15 @@ func (h *jsonrpc2Handler) Cancel(ctx context.Context, conn *jsonrpc2.Conn, id js
_ = ctx
_ = conn
_ = canceled
log.Printf("- jsonrpc2 cancelled request id=%+v", id)
glog.Warningf("- jsonrpc2 cancelled request id=%+v", id)
return false
}

// Request implements jsonrpc2.Handler.
func (h *jsonrpc2Handler) Request(ctx context.Context, conn *jsonrpc2.Conn, direction jsonrpc2.Direction, r *jsonrpc2.WireRequest) context.Context {
_ = conn
_ = direction
//log.Printf("- jsonrpc2 Request(direction=%s) %q", direction, r.Method)
glog.V(2).Infof("- jsonrpc2 Request(direction=%s) %q", direction, r.Method)
return ctx
}

Expand All @@ -407,7 +408,7 @@ func (h *jsonrpc2Handler) Response(ctx context.Context, conn *jsonrpc2.Conn, dir
if r.Result != nil && len(*r.Result) > 0 {
content = trimString(string(*r.Result), 100)
}
log.Printf("- jsonrpc2 Response(direction=%s) id=%+v, content=%s", direction, r.ID, content)
glog.V(2).Infof("- jsonrpc2 Response(direction=%s) id=%+v, content=%s", direction, r.ID, content)
return ctx
}

Expand All @@ -422,5 +423,5 @@ func (h *jsonrpc2Handler) Write(ctx context.Context, _ int64) context.Context {

// Error implements jsonrpc2.Handler.
func (h *jsonrpc2Handler) Error(ctx context.Context, err error) {
log.Printf("- jsonrpc2 Error: %+v", err)
glog.Errorf("- jsonrpc2 Error: %+v", err)
}
15 changes: 9 additions & 6 deletions goexec/goplsclient/goplsclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ package goplsclient
import (
"context"
"io"
"log"
"net"
"os"
"os/exec"
Expand Down Expand Up @@ -110,11 +109,15 @@ func isGoInternalOrCache(filePath string) bool {
// in Markdown. It returns empty if position has no identifier.
func (c *Client) Definition(ctx context.Context, filePath string, line, col int) (markdown string, err error) {
glog.V(2).Infof("goplsclient.Definition(ctx, %s, %d, %d)", filePath, line, col)
// Send "go.mod", in case it changes.
// Send "go.mod" and "go.sum" in case it changes.
err = c.NotifyDidOpenOrChange(ctx, path.Join(c.dir, "go.mod"))
if err != nil {
return "", err
}
err = c.NotifyDidOpenOrChange(ctx, path.Join(c.dir, "go.sum"))
if err != nil {
return "", err
}
// Send filePath.
err = c.NotifyDidOpenOrChange(ctx, filePath)
if err != nil {
Expand All @@ -124,7 +127,7 @@ func (c *Client) Definition(ctx context.Context, filePath string, line, col int)
var results []lsp.Location
results, err = c.CallDefinition(ctx, filePath, line, col)
if err != nil {
log.Printf("c.CallDefinition failed: %+v", err)
glog.Errorf("c.CallDefinition failed: %+v", err)
return "", err
}
_ = results
Expand All @@ -138,11 +141,11 @@ func (c *Client) Definition(ctx context.Context, filePath string, line, col int)
}
hover, err := c.CallHover(ctx, filePath, line, col)
if err != nil {
log.Printf("c.CallHover failed: %+v", err)
glog.Errorf("c.CallHover failed: %+v", err)
return "", err
}
if hover.Contents.Kind != lsp.Markdown {
log.Printf("gopls returned 'hover' with unexpected kind %q", hover.Contents.Kind)
glog.Warningf("gopls returned 'hover' with unexpected kind %q", hover.Contents.Kind)
}
return hover.Contents.Value, nil
}
Expand Down Expand Up @@ -188,7 +191,7 @@ func (c *Client) Complete(ctx context.Context, filePath string, line, col int) (
matches = append(matches, edit.NewText)
}
if len(items.Items) != len(matches) {
log.Printf("Complete found %d items, used only %d", len(items.Items), len(matches))
glog.Infof("Complete found %d items, used only %d", len(items.Items), len(matches))
}
return
}
Expand Down
Loading

0 comments on commit c8091a9

Please sign in to comment.