github.com/goplus/gop@v1.2.6/x/langserver/server.go (about)

     1  /*
     2   * Copyright (c) 2023 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package langserver
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"path/filepath"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/goplus/gop"
    27  	"github.com/goplus/gop/x/gopprojs"
    28  	"github.com/goplus/gop/x/jsonrpc2"
    29  )
    30  
    31  // -----------------------------------------------------------------------------
    32  
    33  // Listener is implemented by protocols to accept new inbound connections.
    34  type Listener = jsonrpc2.Listener
    35  
    36  // Server is a running server that is accepting incoming connections.
    37  type Server = jsonrpc2.Server
    38  
    39  // Config holds the options for new connections.
    40  type Config struct {
    41  	// Framer allows control over the message framing and encoding.
    42  	// If nil, HeaderFramer will be used.
    43  	Framer jsonrpc2.Framer
    44  }
    45  
    46  // NewServer creates a new LangServer and returns it.
    47  func NewServer(ctx context.Context, listener Listener, conf *Config) (ret *Server) {
    48  	h := newHandle()
    49  	ret = jsonrpc2.NewServer(ctx, listener, jsonrpc2.BinderFunc(
    50  		func(ctx context.Context, c *jsonrpc2.Connection) (ret jsonrpc2.ConnectionOptions) {
    51  			if conf != nil {
    52  				ret.Framer = conf.Framer
    53  			}
    54  			ret.Handler = h
    55  			// ret.OnInternalError = h.OnInternalError
    56  			return
    57  		}))
    58  	h.server = ret
    59  	go h.runLoop()
    60  	return
    61  }
    62  
    63  // -----------------------------------------------------------------------------
    64  
    65  type none = struct{}
    66  
    67  type handler struct {
    68  	mutex sync.Mutex
    69  	dirty map[string]none
    70  
    71  	server *Server
    72  }
    73  
    74  func newHandle() *handler {
    75  	return &handler{
    76  		dirty: make(map[string]none),
    77  	}
    78  }
    79  
    80  /*
    81  func (p *handler) OnInternalError(err error) {
    82  	panic("jsonrpc2: " + err.Error())
    83  }
    84  */
    85  
    86  func (p *handler) runLoop() {
    87  	const (
    88  		duration = time.Second / 100
    89  	)
    90  	for {
    91  		var dir string
    92  		p.mutex.Lock()
    93  		for dir = range p.dirty {
    94  			delete(p.dirty, dir)
    95  			break
    96  		}
    97  		p.mutex.Unlock()
    98  		if dir == "" {
    99  			time.Sleep(duration)
   100  			continue
   101  		}
   102  		gop.GenGoEx(dir, nil, true, gop.GenFlagPrompt)
   103  	}
   104  }
   105  
   106  func (p *handler) Changed(files []string) {
   107  	p.mutex.Lock()
   108  	defer p.mutex.Unlock()
   109  
   110  	for _, file := range files {
   111  		dir := filepath.Dir(file)
   112  		p.dirty[dir] = none{}
   113  	}
   114  }
   115  
   116  func (p *handler) Handle(ctx context.Context, req *jsonrpc2.Request) (result interface{}, err error) {
   117  	switch req.Method {
   118  	case methodChanged:
   119  		var files []string
   120  		err = json.Unmarshal(req.Params, &files)
   121  		if err != nil {
   122  			return
   123  		}
   124  		p.Changed(files)
   125  	case methodGenGo:
   126  		var pattern []string
   127  		err = json.Unmarshal(req.Params, &pattern)
   128  		if err != nil {
   129  			return
   130  		}
   131  		err = GenGo(pattern...)
   132  	}
   133  	return
   134  }
   135  
   136  func GenGo(pattern ...string) (err error) {
   137  	projs, err := gopprojs.ParseAll(pattern...)
   138  	if err != nil {
   139  		return
   140  	}
   141  	for _, proj := range projs {
   142  		switch v := proj.(type) {
   143  		case *gopprojs.DirProj:
   144  			gop.GenGoEx(v.Dir, nil, true, 0)
   145  		case *gopprojs.PkgPathProj:
   146  			if v.Path == "builtin" {
   147  				continue
   148  			}
   149  			gop.GenGoPkgPathEx("", v.Path, nil, true, 0)
   150  		}
   151  	}
   152  	return
   153  }
   154  
   155  // -----------------------------------------------------------------------------