mirror of
https://github.com/golang/go
synced 2024-11-18 08:54:45 -07:00
internal/lsp: changing server noun to serve verb
Also adding in --remote support and using it to implement the equivalent functionality of the external forward command Also adding in --listen as a replacement for --port as it is more flexible, specifically it allows localhost:port which is helpful in environments where opening remotely accesible ports is problematic. Change-Id: I5de1cea7dd6f1ee46e7423f3be2a4caca6f040b2 Reviewed-on: https://go-review.googlesource.com/c/161658 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
657755b003
commit
44bee7e801
@ -1,59 +0,0 @@
|
||||
// The forward command writes and reads to a gopls server on a network socket.
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/cmd"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tool.Main(context.Background(), &app{&cmd.Server{}}, os.Args[1:])
|
||||
}
|
||||
|
||||
type app struct {
|
||||
*cmd.Server
|
||||
}
|
||||
|
||||
func (*app) Name() string { return "forward" }
|
||||
func (*app) Usage() string { return "[-port=<value>]" }
|
||||
func (*app) ShortHelp() string { return "An intermediary between an editor and gopls." }
|
||||
func (*app) DetailedHelp(*flag.FlagSet) {}
|
||||
|
||||
func (a *app) Run(ctx context.Context, args ...string) error {
|
||||
if a.Server.Port == 0 {
|
||||
a.ShortHelp()
|
||||
os.Exit(0)
|
||||
}
|
||||
conn, err := net.Dial("tcp", fmt.Sprintf(":%v", a.Server.Port))
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
go func(conn net.Conn) {
|
||||
_, err := io.Copy(conn, os.Stdin)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}(conn)
|
||||
|
||||
go func(conn net.Conn) {
|
||||
_, err := io.Copy(os.Stdout, conn)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
os.Exit(0)
|
||||
}
|
||||
}(conn)
|
||||
|
||||
for {
|
||||
}
|
||||
}
|
@ -25,12 +25,16 @@ type Application struct {
|
||||
// Embed the basic profiling flags supported by the tool package
|
||||
tool.Profile
|
||||
|
||||
// We include the server directly for now, so the flags work even without the verb.
|
||||
// TODO: Remove this when we stop allowing the server verb by default.
|
||||
Server Server
|
||||
// We include the server configuration directly for now, so the flags work
|
||||
// even without the verb.
|
||||
// TODO: Remove this when we stop allowing the serve verb by default.
|
||||
Serve Serve
|
||||
|
||||
// An initial, common go/packages configuration
|
||||
Config packages.Config
|
||||
|
||||
// Support for remote lsp server
|
||||
Remote string `flag:"remote" help:"*EXPERIMENTAL* - forward all commands to a remote lsp"`
|
||||
}
|
||||
|
||||
// Name implements tool.Application returning the binary name.
|
||||
@ -65,7 +69,7 @@ gopls flags are:
|
||||
// temporary measure for compatibility.
|
||||
func (app *Application) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) == 0 {
|
||||
tool.Main(ctx, &app.Server, args)
|
||||
tool.Main(ctx, &app.Serve, args)
|
||||
return nil
|
||||
}
|
||||
app.Config.Mode = packages.LoadSyntax
|
||||
@ -87,8 +91,9 @@ func (app *Application) Run(ctx context.Context, args ...string) error {
|
||||
// command line.
|
||||
// The command is specified by the first non flag argument.
|
||||
func (app *Application) commands() []tool.Application {
|
||||
app.Serve.app = app
|
||||
return []tool.Application{
|
||||
&app.Server,
|
||||
&app.Serve,
|
||||
&query{app: app},
|
||||
}
|
||||
}
|
||||
|
@ -15,26 +15,30 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
"net"
|
||||
|
||||
"golang.org/x/tools/internal/jsonrpc2"
|
||||
"golang.org/x/tools/internal/lsp"
|
||||
"golang.org/x/tools/internal/tool"
|
||||
)
|
||||
|
||||
// Server is a struct that exposes the configurable parts of the LSP server as
|
||||
// Serve is a struct that exposes the configurable parts of the LSP server as
|
||||
// flags, in the right form for tool.Main to consume.
|
||||
type Server struct {
|
||||
type Serve struct {
|
||||
Logfile string `flag:"logfile" help:"filename to log to. if value is \"auto\", then logging to a default output file is enabled"`
|
||||
Mode string `flag:"mode" help:"no effect"`
|
||||
Port int `flag:"port" help:"port on which to run gopls for debugging purposes"`
|
||||
Address string `flag:"listen" help:"address on which to listen for remote connections"`
|
||||
|
||||
app *Application
|
||||
}
|
||||
|
||||
func (s *Server) Name() string { return "server" }
|
||||
func (s *Server) Usage() string { return "" }
|
||||
func (s *Server) ShortHelp() string {
|
||||
func (s *Serve) Name() string { return "serve" }
|
||||
func (s *Serve) Usage() string { return "" }
|
||||
func (s *Serve) ShortHelp() string {
|
||||
return "run a server for Go code using the Language Server Protocol"
|
||||
}
|
||||
func (s *Server) DetailedHelp(f *flag.FlagSet) {
|
||||
func (s *Serve) DetailedHelp(f *flag.FlagSet) {
|
||||
fmt.Fprint(f.Output(), `
|
||||
The server communicates using JSONRPC2 on stdin and stdout, and is intended to be run directly as
|
||||
a child of an editor process.
|
||||
@ -46,7 +50,7 @@ gopls server flags are:
|
||||
|
||||
// Run configures a server based on the flags, and then runs it.
|
||||
// It blocks until the server shuts down.
|
||||
func (s *Server) Run(ctx context.Context, args ...string) error {
|
||||
func (s *Serve) Run(ctx context.Context, args ...string) error {
|
||||
if len(args) > 0 {
|
||||
return tool.CommandLineErrorf("server does not take arguments, got %v", args)
|
||||
}
|
||||
@ -64,6 +68,9 @@ func (s *Server) Run(ctx context.Context, args ...string) error {
|
||||
log.SetOutput(io.MultiWriter(os.Stderr, f))
|
||||
out = f
|
||||
}
|
||||
if s.app.Remote != "" {
|
||||
return s.forward()
|
||||
}
|
||||
logger := func(direction jsonrpc2.Direction, id *jsonrpc2.ID, elapsed time.Duration, method string, payload *json.RawMessage, err *jsonrpc2.Error) {
|
||||
const eol = "\r\n\r\n\r\n"
|
||||
if err != nil {
|
||||
@ -112,9 +119,33 @@ func (s *Server) Run(ctx context.Context, args ...string) error {
|
||||
fmt.Fprintf(out, "%s", outx.String())
|
||||
}
|
||||
// For debugging purposes only.
|
||||
if s.Address != "" {
|
||||
return lsp.RunServerOnAddress(ctx, s.Address, logger)
|
||||
}
|
||||
if s.Port != 0 {
|
||||
return lsp.RunServerOnPort(ctx, s.Port, logger)
|
||||
}
|
||||
stream := jsonrpc2.NewHeaderStream(os.Stdin, os.Stdout)
|
||||
return lsp.RunServer(ctx, stream, logger)
|
||||
}
|
||||
|
||||
|
||||
func (s *Serve) forward() error {
|
||||
conn, err := net.Dial("tcp", s.app.Remote)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errc := make(chan error)
|
||||
|
||||
go func(conn net.Conn) {
|
||||
_, err := io.Copy(conn, os.Stdin)
|
||||
errc <- err
|
||||
}(conn)
|
||||
|
||||
go func(conn net.Conn) {
|
||||
_, err := io.Copy(os.Stdout, conn)
|
||||
errc <- err
|
||||
}(conn)
|
||||
|
||||
return <-errc
|
||||
}
|
@ -31,8 +31,14 @@ func RunServer(ctx context.Context, stream jsonrpc2.Stream, opts ...interface{})
|
||||
// RunServerOnPort starts an LSP server on the given port and does not exit.
|
||||
// This function exists for debugging purposes.
|
||||
func RunServerOnPort(ctx context.Context, port int, opts ...interface{}) error {
|
||||
return RunServerOnAddress(ctx, fmt.Sprintf(":%v", port))
|
||||
}
|
||||
|
||||
// RunServerOnPort starts an LSP server on the given port and does not exit.
|
||||
// This function exists for debugging purposes.
|
||||
func RunServerOnAddress(ctx context.Context, addr string, opts ...interface{}) error {
|
||||
s := &server{}
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
|
||||
ln, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user