github.com/jmigpin/editor@v1.6.0/core/lsproto/registration.go (about) 1 package lsproto 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/jmigpin/editor/util/osutil" 8 "github.com/jmigpin/editor/util/parseutil" 9 ) 10 11 //---------- 12 13 type Registration struct { 14 Language string 15 Exts []string 16 Network string // {stdio,tcpclient,tcp{templatevals:.Addr}} 17 Cmd string 18 Optional []string // {stderr,nogotoimpl} 19 } 20 21 func NewRegistration(s string) (*Registration, error) { 22 reg, err := parseRegistration(s) 23 if err != nil { 24 return nil, err 25 } 26 return reg, nil 27 } 28 29 func (reg *Registration) HasOptional(s string) bool { 30 for _, v := range reg.Optional { 31 if v == s { 32 return true 33 } 34 } 35 36 // handle backwards compatibility (keep old defaults) 37 if s == "nogotoimpl" { 38 // - these won't use gotoimplementation, and there is no way to enable it (it would just be slower) 39 // - other languages (ex:c/c++) will use gotoimplementation 40 languagesToBypass := "go python javascript" 41 if strings.Contains(languagesToBypass, strings.ToLower(reg.Language)) { 42 return true 43 } 44 } 45 46 return false 47 } 48 49 func (reg *Registration) String() string { 50 return stringifyRegistration(reg) 51 } 52 53 //---------- 54 55 func parseRegistration(s string) (*Registration, error) { 56 fields, err := parseutil.ParseFields(s, ',') 57 if err != nil { 58 return nil, err 59 } 60 61 minFields := 4 62 if len(fields) < minFields { 63 return nil, fmt.Errorf("expecting at least %v fields: %v", minFields, len(fields)) 64 } 65 66 reg := &Registration{} 67 reg.Language = fields[0] 68 if reg.Language == "" { 69 return nil, fmt.Errorf("empty language") 70 } 71 reg.Exts = strings.Split(fields[1], " ") 72 reg.Network = fields[2] 73 reg.Cmd = fields[3] 74 if len(fields) > 4 { 75 reg.Optional = strings.Split(fields[4], " ") 76 } 77 78 return reg, nil 79 } 80 81 func stringifyRegistration(reg *Registration) string { 82 exts := strings.Join(reg.Exts, " ") 83 if len(reg.Exts) >= 2 { 84 exts = fmt.Sprintf("%q", exts) 85 } 86 87 cmd := reg.Cmd 88 cmd2 := parseutil.AddEscapes(cmd, '\\', " ,") 89 if cmd != cmd2 { 90 cmd = fmt.Sprintf("%q", cmd) 91 } 92 93 u := []string{ 94 reg.Language, 95 exts, 96 reg.Network, 97 cmd, 98 } 99 if len(reg.Optional) >= 1 { 100 h := strings.Join(reg.Optional, " ") 101 if len(reg.Optional) >= 2 { 102 h = fmt.Sprintf("%q", h) 103 } 104 u = append(u, h) 105 } 106 return strings.Join(u, ",") 107 } 108 109 //---------- 110 111 func RegistrationExamples() []string { 112 return []string{ 113 GoplsRegistration(false, false, false), 114 GoplsRegistration(false, true, false), 115 cLangRegistration(false), 116 "python,.py,stdio,pylsp", 117 "python,.py,tcpclient,127.0.0.1:9000", 118 "python,.py,stdio,pylsp,\"stderr nogotoimpl\"", 119 } 120 } 121 122 //---------- 123 124 func GoplsRegistration(stderr bool, tcp bool, trace bool) string { 125 cmd := osutil.ExecName("gopls") 126 if trace { 127 cmd += " -v" 128 } 129 cmd += " serve" 130 if trace { 131 cmd += " -rpc.trace" 132 } 133 net := "stdio" 134 if tcp { 135 net = "tcp" 136 cmd += " -listen={{.Addr}}" 137 } 138 139 errOut := "" 140 if net == "stdio" { 141 if stderr { 142 //errOut = ",stderr" 143 // DEBUG 144 //errOut = ",stderrmanmsg" 145 } 146 } 147 148 return fmt.Sprintf("go,.go,%v,%q%s", net, cmd, errOut) 149 } 150 151 func cLangRegistration(stderr bool) string { 152 ext := ".c .h .cpp .hpp .cc" 153 cmd := osutil.ExecName("clangd") 154 errOut := "" 155 if stderr { 156 //errOut = ",stderr" 157 } 158 return fmt.Sprintf("cpp,%q,stdio,%q%s", ext, cmd, errOut) 159 } 160 161 func pylspRegistration(stderr bool, tcp bool) string { 162 cmd := osutil.ExecName("pylsp") 163 net := "stdio" 164 if tcp { 165 net = "tcp" 166 cmd += " --tcp" 167 cmd += " --host={{.Host}}" 168 cmd += " --port={{.Port}}" 169 } 170 errOut := "" 171 if stderr { 172 errOut = ",stderr" 173 } 174 return fmt.Sprintf("python,.py,%s,%q%s", net, cmd, errOut) 175 }