Skip to content

Commit

Permalink
Merge pull request #15 from xushiwei/q
Browse files Browse the repository at this point in the history
proxy/lsview support goxls
  • Loading branch information
xushiwei authored Oct 12, 2023
2 parents 03ce7d5 + 38764a6 commit 3fbb088
Show file tree
Hide file tree
Showing 9 changed files with 168 additions and 94 deletions.
7 changes: 6 additions & 1 deletion gopls/goxls/cmd/gopls.proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ import (
"golang.org/x/tools/gopls/goxls/proxy"
)

const (
gopls = "gopls.origin"
goxls = "goxls"
)

func main() {
proxy.Main()
proxy.Main(gopls, goxls)
}
2 changes: 1 addition & 1 deletion gopls/goxls/cmd/goxls/goxls.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ package main
import "golang.org/x/tools/gopls/goxls"

func main() {
goxls.Main()
goxls.Main(nil, nil)
}
18 changes: 18 additions & 0 deletions gopls/goxls/cmd/lsview/lsview_app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2022 The GoPlus Authors (goplus.org). All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
"golang.org/x/tools/gopls/goxls/lsview"
)

const (
gopls = "gopls.origin"
goxls = "goxls"
)

func main() {
lsview.Main(gopls, goxls)
}
10 changes: 7 additions & 3 deletions gopls/goxls/goxls.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ package goxls

import (
"context"
"io"
"os"

"golang.org/x/tools/gopls/internal/goxls/cmd"
"golang.org/x/tools/gopls/internal/hooks"
"golang.org/x/tools/gopls/internal/lsp/cmd"
"golang.org/x/tools/internal/tool"
)

func Main() {
func Main(in io.ReadCloser, out io.WriteCloser) {
ctx := context.Background()
tool.Main(ctx, cmd.New("goxls", "", nil, hooks.Options), os.Args[1:])
app := cmd.New("goxls", "", nil, hooks.Options)
app.Serve.In = in
app.Serve.Out = out
tool.Main(ctx, app, os.Args[1:])
}
117 changes: 73 additions & 44 deletions gopls/goxls/cmd/lsview/lsview.go → gopls/goxls/lsview/lsview.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main
package lsview

import (
"bytes"
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io"
"log"
Expand All @@ -21,28 +20,22 @@ import (
"golang.org/x/tools/internal/jsonrpc2"
)

func main() {
flag.Parse()

app := "gopls"
args := flag.Args()
if len(args) > 0 {
app = args[0]
}

func Main(app, goxls string) {
fin, err := os.Open(app + ".in")
check(err)
defer fin.Close()

fout, err := os.Open(app + ".out")
fdiff, err := os.Create(app + ".diff")
check(err)
defer fout.Close()
defer fdiff.Close()

logd := log.New(fdiff, "", log.LstdFlags)
reqStream := jsonrpc2.NewHeaderStream(fakenet.NewConn("request", fin, os.Stdout))
respStream := jsonrpc2.NewHeaderStream(fakenet.NewConn("response", fout, os.Stdout))
reqChan := make(chan jsonrpc2.ID, 1)
respChan := make(chan *jsonrpc2.Response, 1)
resps := make([]*jsonrpc2.Response, 0, 8)
reqChan2 := make(chan jsonrpc2.ID, 1)
respChan2 := make(chan *jsonrpc2.Response, 1)

go func() {
ctx := context.Background()
for {
Expand All @@ -59,47 +52,83 @@ func main() {
id := req.ID()
log.Printf("[%v] %s:\n%s", id, req.Method(), params(req.Params()))
reqChan <- id
select {
case <-time.After(time.Second):
case resp := <-respChan:
ret := any(resp.Err())
if ret == nil {
ret = params(resp.Result())
} else {
ret = fmt.Sprintf("%serror: %v\n", indent, ret)
resp := respFetch(respChan)
if resp != nil {
log.Printf("[%v] %s ret:\n%s", id, app, resp)
}
if goxls != "" {
select { // allow send request failed
case <-time.After(time.Second):
case reqChan2 <- id:
if resp2 := respFetch(respChan2); resp2 != nil {
log.Printf("[%v] %s ret:\n%s", id, goxls, resp2)
if !reflect.DeepEqual(resp, resp2) {
logd.Printf("[%v] %s:\n%s", id, req.Method(), params(req.Params()))
logd.Printf("[%v] %s ret:\n%s", id, app, resp)
logd.Printf("[%v] %s ret:\n%s", id, goxls, resp2)
}
}
}
log.Printf("[%v] ret:\n%s", id, ret)
}
case *jsonrpc2.Notification:
log.Printf("[] %s:\n%s", req.Method(), params(req.Params()))
}
}
}()
go func() {
ctx := context.Background()
next:
id := <-reqChan
for i, resp := range resps {
go respLoop(app, respChan, reqChan)
if goxls != "" {
go respLoop(app, respChan2, reqChan2)
}
select {}
}

func respFetch(respChan chan *jsonrpc2.Response) any {
select {
case <-time.After(time.Second):
case resp := <-respChan:
ret := any(resp.Err())
if ret == nil {
ret = params(resp.Result())
} else {
ret = fmt.Sprintf("%serror: %v\n", indent, ret)
}
return ret
}
return nil
}

func respLoop(app string, respChan chan *jsonrpc2.Response, reqChan chan jsonrpc2.ID) {
if app == "" {
return
}
fout, err := os.Open(app + ".out")
check(err)
defer fout.Close()

ctx := context.Background()
respStream := jsonrpc2.NewHeaderStream(fakenet.NewConn("response", fout, os.Stdout))
resps := make([]*jsonrpc2.Response, 0, 8)
next:
id := <-reqChan
for i, resp := range resps {
if resp.ID() == id {
resps = append(resps[i:], resps[i+1:]...)
respChan <- resp
goto next
}
}
for {
msg, _, err := respStream.Read(ctx)
check(err)
switch resp := msg.(type) {
case *jsonrpc2.Response:
if resp.ID() == id {
resps = append(resps[i:], resps[i+1:]...)
respChan <- resp
goto next
}
resps = append(resps, resp)
}
for {
msg, _, err := respStream.Read(ctx)
check(err)
switch resp := msg.(type) {
case *jsonrpc2.Response:
if resp.ID() == id {
respChan <- resp
goto next
}
resps = append(resps, resp)
}
}
}()
select {}
}
}

type any = interface{}
Expand Down
44 changes: 33 additions & 11 deletions gopls/goxls/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,66 @@ import (
"time"
)

const (
gopls = "gopls.origin"
)

func Main() {
func Main(gopls, goxls string) {
home, err := os.UserHomeDir()
check(err)

goplsDir := home + "/.gopls"
rotateDir := goplsDir + "/" + strconv.FormatInt(time.Now().UnixMicro(), 36)
goplsDir := home + "/.gopls/"
rotateDir := goplsDir + strconv.FormatInt(time.Now().UnixMicro(), 36)
err = os.MkdirAll(rotateDir, 0755)
check(err)

rotateDir += "/"
createFile := func(name string) (f *os.File, err error) {
normal, rotate := goplsDir+name, rotateDir+name
os.Rename(normal, rotate)
return os.Create(normal)
}

logf, err := createFile("/gopls.log")
logf, err := createFile(gopls + ".log")
check(err)
defer logf.Close()

stdinf, err := createFile("/gopls.in")
stdinf, err := createFile(gopls + ".in")
check(err)
defer stdinf.Close()

stdoutf, err := createFile("/gopls.out")
stdoutf, err := createFile(gopls + ".out")
check(err)
defer stdoutf.Close()

log.SetOutput(logf)
log.Println("[INFO] app start:", os.Args)

var pwGox io.WriteCloser
if goxls != "" {
goxoutf, err := createFile(goxls + ".out")
check(err)
defer goxoutf.Close()

pr, pw, err := os.Pipe()
check(err)
pwGox = pw

go func() {
cmd := exec.Command(goxls, os.Args[1:]...)
cmd.Stdin = pr
cmd.Stdout = goxoutf
cmd.Stderr = os.Stderr
err = cmd.Run()
check(err)
}()
}

pr, pw, err := os.Pipe()
check(err)
go func() {
w := io.MultiWriter(pw, stdinf)
writers := make([]io.Writer, 2, 3)
writers[0], writers[1] = pw, stdinf
if pwGox != nil {
writers = append(writers, pwGox)
}
w := io.MultiWriter(writers...)
for {
io.Copy(w, os.Stdin)
}
Expand Down
32 changes: 0 additions & 32 deletions gopls/internal/goxls/cmd/cmd.go

This file was deleted.

8 changes: 6 additions & 2 deletions gopls/internal/lsp/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"fmt"
"io"
"log"
"os"
"time"

"golang.org/x/tools/gopls/internal/lsp/cache"
Expand Down Expand Up @@ -39,6 +38,10 @@ type Serve struct {
RemoteLogfile string `flag:"remote.logfile" help:"when used with -remote=auto, the -logfile value used to start the daemon"`

app *Application

// goxls: input/output of jsonrpc
In io.ReadCloser
Out io.WriteCloser
}

func (s *Serve) Name() string { return "serve" }
Expand Down Expand Up @@ -133,7 +136,8 @@ func (s *Serve) Run(ctx context.Context, args ...string) error {
defer log.Printf("Gopls daemon: exiting")
return jsonrpc2.ListenAndServe(ctx, network, addr, ss, s.IdleTimeout)
}
stream := jsonrpc2.NewHeaderStream(fakenet.NewConn("stdio", os.Stdin, os.Stdout))
// goxls: os.Stdin => s.reqIn(), os.Stdout => s.reqOut()
stream := jsonrpc2.NewHeaderStream(fakenet.NewConn("stdio", s.reqIn(), s.reqOut()))
if s.Trace && di != nil {
stream = protocol.LoggingStream(stream, di.LogWriter)
}
Expand Down
24 changes: 24 additions & 0 deletions gopls/internal/lsp/cmd/serve_gox.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2023 The GoPlus Authors (goplus.org). All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cmd

import (
"io"
"os"
)

func (s *Serve) reqIn() io.ReadCloser {
if in := s.In; in != nil {
return in
}
return os.Stdin
}

func (s *Serve) reqOut() io.WriteCloser {
if out := s.Out; out != nil {
return out
}
return os.Stdout
}

0 comments on commit 3fbb088

Please sign in to comment.