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 // -----------------------------------------------------------------------------