1fd4e5da5Sopenharmony_ci// Copyright (C) 2019 Google Inc. 2fd4e5da5Sopenharmony_ci// 3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License. 5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at 6fd4e5da5Sopenharmony_ci// 7fd4e5da5Sopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 8fd4e5da5Sopenharmony_ci// 9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software 10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and 13fd4e5da5Sopenharmony_ci// limitations under the License. 14fd4e5da5Sopenharmony_ci 15fd4e5da5Sopenharmony_ci// langsvr implements a Language Server for the SPIRV assembly language. 16fd4e5da5Sopenharmony_cipackage main 17fd4e5da5Sopenharmony_ci 18fd4e5da5Sopenharmony_ciimport ( 19fd4e5da5Sopenharmony_ci "context" 20fd4e5da5Sopenharmony_ci "fmt" 21fd4e5da5Sopenharmony_ci "io" 22fd4e5da5Sopenharmony_ci "io/ioutil" 23fd4e5da5Sopenharmony_ci "log" 24fd4e5da5Sopenharmony_ci "os" 25fd4e5da5Sopenharmony_ci "path" 26fd4e5da5Sopenharmony_ci "sort" 27fd4e5da5Sopenharmony_ci "strings" 28fd4e5da5Sopenharmony_ci "sync" 29fd4e5da5Sopenharmony_ci "unicode/utf8" 30fd4e5da5Sopenharmony_ci 31fd4e5da5Sopenharmony_ci "github.com/KhronosGroup/SPIRV-Tools/utils/vscode/src/parser" 32fd4e5da5Sopenharmony_ci "github.com/KhronosGroup/SPIRV-Tools/utils/vscode/src/schema" 33fd4e5da5Sopenharmony_ci 34fd4e5da5Sopenharmony_ci "github.com/KhronosGroup/SPIRV-Tools/utils/vscode/src/lsp/jsonrpc2" 35fd4e5da5Sopenharmony_ci lsp "github.com/KhronosGroup/SPIRV-Tools/utils/vscode/src/lsp/protocol" 36fd4e5da5Sopenharmony_ci) 37fd4e5da5Sopenharmony_ci 38fd4e5da5Sopenharmony_ciconst ( 39fd4e5da5Sopenharmony_ci enableDebugLogging = false 40fd4e5da5Sopenharmony_ci) 41fd4e5da5Sopenharmony_ci 42fd4e5da5Sopenharmony_ci// rSpy is a reader 'spy' that wraps an io.Reader, and logs all data that passes 43fd4e5da5Sopenharmony_ci// through it. 44fd4e5da5Sopenharmony_citype rSpy struct { 45fd4e5da5Sopenharmony_ci prefix string 46fd4e5da5Sopenharmony_ci r io.Reader 47fd4e5da5Sopenharmony_ci} 48fd4e5da5Sopenharmony_ci 49fd4e5da5Sopenharmony_cifunc (s rSpy) Read(p []byte) (n int, err error) { 50fd4e5da5Sopenharmony_ci n, err = s.r.Read(p) 51fd4e5da5Sopenharmony_ci log.Printf("%v %v", s.prefix, string(p[:n])) 52fd4e5da5Sopenharmony_ci return n, err 53fd4e5da5Sopenharmony_ci} 54fd4e5da5Sopenharmony_ci 55fd4e5da5Sopenharmony_ci// wSpy is a reader 'spy' that wraps an io.Writer, and logs all data that passes 56fd4e5da5Sopenharmony_ci// through it. 57fd4e5da5Sopenharmony_citype wSpy struct { 58fd4e5da5Sopenharmony_ci prefix string 59fd4e5da5Sopenharmony_ci w io.Writer 60fd4e5da5Sopenharmony_ci} 61fd4e5da5Sopenharmony_ci 62fd4e5da5Sopenharmony_cifunc (s wSpy) Write(p []byte) (n int, err error) { 63fd4e5da5Sopenharmony_ci n, err = s.w.Write(p) 64fd4e5da5Sopenharmony_ci log.Printf("%v %v", s.prefix, string(p)) 65fd4e5da5Sopenharmony_ci return n, err 66fd4e5da5Sopenharmony_ci} 67fd4e5da5Sopenharmony_ci 68fd4e5da5Sopenharmony_ci// main entry point. 69fd4e5da5Sopenharmony_cifunc main() { 70fd4e5da5Sopenharmony_ci log.SetOutput(ioutil.Discard) 71fd4e5da5Sopenharmony_ci if enableDebugLogging { 72fd4e5da5Sopenharmony_ci // create a log file in the executable's directory. 73fd4e5da5Sopenharmony_ci if logfile, err := os.Create(path.Join(path.Dir(os.Args[0]), "log.txt")); err == nil { 74fd4e5da5Sopenharmony_ci defer logfile.Close() 75fd4e5da5Sopenharmony_ci log.SetOutput(logfile) 76fd4e5da5Sopenharmony_ci } 77fd4e5da5Sopenharmony_ci } 78fd4e5da5Sopenharmony_ci 79fd4e5da5Sopenharmony_ci log.Println("language server started") 80fd4e5da5Sopenharmony_ci 81fd4e5da5Sopenharmony_ci stream := jsonrpc2.NewHeaderStream(rSpy{"IDE", os.Stdin}, wSpy{"LS", os.Stdout}) 82fd4e5da5Sopenharmony_ci s := server{ 83fd4e5da5Sopenharmony_ci files: map[string]*file{}, 84fd4e5da5Sopenharmony_ci } 85fd4e5da5Sopenharmony_ci s.ctx, s.conn, s.client = lsp.NewServer(context.Background(), stream, &s) 86fd4e5da5Sopenharmony_ci if err := s.conn.Run(s.ctx); err != nil { 87fd4e5da5Sopenharmony_ci log.Panicln(err) 88fd4e5da5Sopenharmony_ci os.Exit(1) 89fd4e5da5Sopenharmony_ci } 90fd4e5da5Sopenharmony_ci 91fd4e5da5Sopenharmony_ci log.Println("language server stopped") 92fd4e5da5Sopenharmony_ci} 93fd4e5da5Sopenharmony_ci 94fd4e5da5Sopenharmony_citype server struct { 95fd4e5da5Sopenharmony_ci ctx context.Context 96fd4e5da5Sopenharmony_ci conn *jsonrpc2.Conn 97fd4e5da5Sopenharmony_ci client lsp.Client 98fd4e5da5Sopenharmony_ci 99fd4e5da5Sopenharmony_ci files map[string]*file 100fd4e5da5Sopenharmony_ci filesMutex sync.Mutex 101fd4e5da5Sopenharmony_ci} 102fd4e5da5Sopenharmony_ci 103fd4e5da5Sopenharmony_ci// file represents a source file 104fd4e5da5Sopenharmony_citype file struct { 105fd4e5da5Sopenharmony_ci fullRange parser.Range 106fd4e5da5Sopenharmony_ci res parser.Results 107fd4e5da5Sopenharmony_ci} 108fd4e5da5Sopenharmony_ci 109fd4e5da5Sopenharmony_ci// tokAt returns the parser token at the given position lp 110fd4e5da5Sopenharmony_cifunc (f *file) tokAt(lp lsp.Position) *parser.Token { 111fd4e5da5Sopenharmony_ci toks := f.res.Tokens 112fd4e5da5Sopenharmony_ci p := parser.Position{Line: int(lp.Line) + 1, Column: int(lp.Character) + 1} 113fd4e5da5Sopenharmony_ci i := sort.Search(len(toks), func(i int) bool { return p.LessThan(toks[i].Range.End) }) 114fd4e5da5Sopenharmony_ci if i == len(toks) { 115fd4e5da5Sopenharmony_ci return nil 116fd4e5da5Sopenharmony_ci } 117fd4e5da5Sopenharmony_ci if toks[i].Range.Contains(p) { 118fd4e5da5Sopenharmony_ci return toks[i] 119fd4e5da5Sopenharmony_ci } 120fd4e5da5Sopenharmony_ci return nil 121fd4e5da5Sopenharmony_ci} 122fd4e5da5Sopenharmony_ci 123fd4e5da5Sopenharmony_cifunc (s *server) DidChangeWorkspaceFolders(ctx context.Context, p *lsp.DidChangeWorkspaceFoldersParams) error { 124fd4e5da5Sopenharmony_ci log.Println("server.DidChangeWorkspaceFolders()") 125fd4e5da5Sopenharmony_ci return nil 126fd4e5da5Sopenharmony_ci} 127fd4e5da5Sopenharmony_cifunc (s *server) Initialized(ctx context.Context, p *lsp.InitializedParams) error { 128fd4e5da5Sopenharmony_ci log.Println("server.Initialized()") 129fd4e5da5Sopenharmony_ci return nil 130fd4e5da5Sopenharmony_ci} 131fd4e5da5Sopenharmony_cifunc (s *server) Exit(ctx context.Context) error { 132fd4e5da5Sopenharmony_ci log.Println("server.Exit()") 133fd4e5da5Sopenharmony_ci return nil 134fd4e5da5Sopenharmony_ci} 135fd4e5da5Sopenharmony_cifunc (s *server) DidChangeConfiguration(ctx context.Context, p *lsp.DidChangeConfigurationParams) error { 136fd4e5da5Sopenharmony_ci log.Println("server.DidChangeConfiguration()") 137fd4e5da5Sopenharmony_ci return nil 138fd4e5da5Sopenharmony_ci} 139fd4e5da5Sopenharmony_cifunc (s *server) DidOpen(ctx context.Context, p *lsp.DidOpenTextDocumentParams) error { 140fd4e5da5Sopenharmony_ci log.Println("server.DidOpen()") 141fd4e5da5Sopenharmony_ci return s.processFile(ctx, p.TextDocument.URI, p.TextDocument.Text) 142fd4e5da5Sopenharmony_ci} 143fd4e5da5Sopenharmony_cifunc (s *server) DidChange(ctx context.Context, p *lsp.DidChangeTextDocumentParams) error { 144fd4e5da5Sopenharmony_ci log.Println("server.DidChange()") 145fd4e5da5Sopenharmony_ci return s.processFile(ctx, p.TextDocument.URI, p.ContentChanges[0].Text) 146fd4e5da5Sopenharmony_ci} 147fd4e5da5Sopenharmony_cifunc (s *server) DidClose(ctx context.Context, p *lsp.DidCloseTextDocumentParams) error { 148fd4e5da5Sopenharmony_ci log.Println("server.DidClose()") 149fd4e5da5Sopenharmony_ci return nil 150fd4e5da5Sopenharmony_ci} 151fd4e5da5Sopenharmony_cifunc (s *server) DidSave(ctx context.Context, p *lsp.DidSaveTextDocumentParams) error { 152fd4e5da5Sopenharmony_ci log.Println("server.DidSave()") 153fd4e5da5Sopenharmony_ci return nil 154fd4e5da5Sopenharmony_ci} 155fd4e5da5Sopenharmony_cifunc (s *server) WillSave(ctx context.Context, p *lsp.WillSaveTextDocumentParams) error { 156fd4e5da5Sopenharmony_ci log.Println("server.WillSave()") 157fd4e5da5Sopenharmony_ci return nil 158fd4e5da5Sopenharmony_ci} 159fd4e5da5Sopenharmony_cifunc (s *server) DidChangeWatchedFiles(ctx context.Context, p *lsp.DidChangeWatchedFilesParams) error { 160fd4e5da5Sopenharmony_ci log.Println("server.DidChangeWatchedFiles()") 161fd4e5da5Sopenharmony_ci return nil 162fd4e5da5Sopenharmony_ci} 163fd4e5da5Sopenharmony_cifunc (s *server) Progress(ctx context.Context, p *lsp.ProgressParams) error { 164fd4e5da5Sopenharmony_ci log.Println("server.Progress()") 165fd4e5da5Sopenharmony_ci return nil 166fd4e5da5Sopenharmony_ci} 167fd4e5da5Sopenharmony_cifunc (s *server) SetTraceNotification(ctx context.Context, p *lsp.SetTraceParams) error { 168fd4e5da5Sopenharmony_ci log.Println("server.SetTraceNotification()") 169fd4e5da5Sopenharmony_ci return nil 170fd4e5da5Sopenharmony_ci} 171fd4e5da5Sopenharmony_cifunc (s *server) LogTraceNotification(ctx context.Context, p *lsp.LogTraceParams) error { 172fd4e5da5Sopenharmony_ci log.Println("server.LogTraceNotification()") 173fd4e5da5Sopenharmony_ci return nil 174fd4e5da5Sopenharmony_ci} 175fd4e5da5Sopenharmony_cifunc (s *server) Implementation(ctx context.Context, p *lsp.ImplementationParams) ([]lsp.Location, error) { 176fd4e5da5Sopenharmony_ci log.Println("server.Implementation()") 177fd4e5da5Sopenharmony_ci return nil, nil 178fd4e5da5Sopenharmony_ci} 179fd4e5da5Sopenharmony_cifunc (s *server) TypeDefinition(ctx context.Context, p *lsp.TypeDefinitionParams) ([]lsp.Location, error) { 180fd4e5da5Sopenharmony_ci log.Println("server.TypeDefinition()") 181fd4e5da5Sopenharmony_ci return nil, nil 182fd4e5da5Sopenharmony_ci} 183fd4e5da5Sopenharmony_cifunc (s *server) DocumentColor(ctx context.Context, p *lsp.DocumentColorParams) ([]lsp.ColorInformation, error) { 184fd4e5da5Sopenharmony_ci log.Println("server.DocumentColor()") 185fd4e5da5Sopenharmony_ci return nil, nil 186fd4e5da5Sopenharmony_ci} 187fd4e5da5Sopenharmony_cifunc (s *server) ColorPresentation(ctx context.Context, p *lsp.ColorPresentationParams) ([]lsp.ColorPresentation, error) { 188fd4e5da5Sopenharmony_ci log.Println("server.ColorPresentation()") 189fd4e5da5Sopenharmony_ci return nil, nil 190fd4e5da5Sopenharmony_ci} 191fd4e5da5Sopenharmony_cifunc (s *server) FoldingRange(ctx context.Context, p *lsp.FoldingRangeParams) ([]lsp.FoldingRange, error) { 192fd4e5da5Sopenharmony_ci log.Println("server.FoldingRange()") 193fd4e5da5Sopenharmony_ci return nil, nil 194fd4e5da5Sopenharmony_ci} 195fd4e5da5Sopenharmony_cifunc (s *server) Declaration(ctx context.Context, p *lsp.DeclarationParams) ([]lsp.DeclarationLink, error) { 196fd4e5da5Sopenharmony_ci log.Println("server.Declaration()") 197fd4e5da5Sopenharmony_ci return nil, nil 198fd4e5da5Sopenharmony_ci} 199fd4e5da5Sopenharmony_cifunc (s *server) SelectionRange(ctx context.Context, p *lsp.SelectionRangeParams) ([]lsp.SelectionRange, error) { 200fd4e5da5Sopenharmony_ci log.Println("server.SelectionRange()") 201fd4e5da5Sopenharmony_ci return nil, nil 202fd4e5da5Sopenharmony_ci} 203fd4e5da5Sopenharmony_cifunc (s *server) Initialize(ctx context.Context, p *lsp.ParamInitia) (*lsp.InitializeResult, error) { 204fd4e5da5Sopenharmony_ci log.Println("server.Initialize()") 205fd4e5da5Sopenharmony_ci res := lsp.InitializeResult{ 206fd4e5da5Sopenharmony_ci Capabilities: lsp.ServerCapabilities{ 207fd4e5da5Sopenharmony_ci TextDocumentSync: lsp.TextDocumentSyncOptions{ 208fd4e5da5Sopenharmony_ci OpenClose: true, 209fd4e5da5Sopenharmony_ci Change: lsp.Full, // TODO: Implement incremental 210fd4e5da5Sopenharmony_ci }, 211fd4e5da5Sopenharmony_ci HoverProvider: true, 212fd4e5da5Sopenharmony_ci DefinitionProvider: true, 213fd4e5da5Sopenharmony_ci ReferencesProvider: true, 214fd4e5da5Sopenharmony_ci RenameProvider: true, 215fd4e5da5Sopenharmony_ci DocumentFormattingProvider: true, 216fd4e5da5Sopenharmony_ci }, 217fd4e5da5Sopenharmony_ci } 218fd4e5da5Sopenharmony_ci return &res, nil 219fd4e5da5Sopenharmony_ci} 220fd4e5da5Sopenharmony_cifunc (s *server) Shutdown(ctx context.Context) error { 221fd4e5da5Sopenharmony_ci log.Println("server.Shutdown()") 222fd4e5da5Sopenharmony_ci return nil 223fd4e5da5Sopenharmony_ci} 224fd4e5da5Sopenharmony_cifunc (s *server) WillSaveWaitUntil(ctx context.Context, p *lsp.WillSaveTextDocumentParams) ([]lsp.TextEdit, error) { 225fd4e5da5Sopenharmony_ci log.Println("server.WillSaveWaitUntil()") 226fd4e5da5Sopenharmony_ci return nil, nil 227fd4e5da5Sopenharmony_ci} 228fd4e5da5Sopenharmony_cifunc (s *server) Completion(ctx context.Context, p *lsp.CompletionParams) (*lsp.CompletionList, error) { 229fd4e5da5Sopenharmony_ci log.Println("server.Completion()") 230fd4e5da5Sopenharmony_ci return nil, nil 231fd4e5da5Sopenharmony_ci} 232fd4e5da5Sopenharmony_cifunc (s *server) Resolve(ctx context.Context, p *lsp.CompletionItem) (*lsp.CompletionItem, error) { 233fd4e5da5Sopenharmony_ci log.Println("server.Resolve()") 234fd4e5da5Sopenharmony_ci return nil, nil 235fd4e5da5Sopenharmony_ci} 236fd4e5da5Sopenharmony_cifunc (s *server) Hover(ctx context.Context, p *lsp.HoverParams) (*lsp.Hover, error) { 237fd4e5da5Sopenharmony_ci log.Println("server.Hover()") 238fd4e5da5Sopenharmony_ci f := s.getFile(p.TextDocument.URI) 239fd4e5da5Sopenharmony_ci if f == nil { 240fd4e5da5Sopenharmony_ci return nil, fmt.Errorf("Unknown file") 241fd4e5da5Sopenharmony_ci } 242fd4e5da5Sopenharmony_ci 243fd4e5da5Sopenharmony_ci if tok := f.tokAt(p.Position); tok != nil { 244fd4e5da5Sopenharmony_ci sb := strings.Builder{} 245fd4e5da5Sopenharmony_ci switch v := f.res.Mappings[tok].(type) { 246fd4e5da5Sopenharmony_ci default: 247fd4e5da5Sopenharmony_ci sb.WriteString(fmt.Sprintf("<Unhandled type '%T'>", v)) 248fd4e5da5Sopenharmony_ci case *parser.Instruction: 249fd4e5da5Sopenharmony_ci sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Opcode.Opname)) 250fd4e5da5Sopenharmony_ci case *parser.Identifier: 251fd4e5da5Sopenharmony_ci sb.WriteString(fmt.Sprintf("```\n%v\n```", v.Definition.Range.Text(f.res.Lines))) 252fd4e5da5Sopenharmony_ci case *parser.Operand: 253fd4e5da5Sopenharmony_ci if v.Name != "" { 254fd4e5da5Sopenharmony_ci sb.WriteString(strings.Trim(v.Name, `'`)) 255fd4e5da5Sopenharmony_ci sb.WriteString("\n\n") 256fd4e5da5Sopenharmony_ci } 257fd4e5da5Sopenharmony_ci 258fd4e5da5Sopenharmony_ci switch v.Kind.Category { 259fd4e5da5Sopenharmony_ci case schema.OperandCategoryBitEnum: 260fd4e5da5Sopenharmony_ci case schema.OperandCategoryValueEnum: 261fd4e5da5Sopenharmony_ci sb.WriteString("```\n") 262fd4e5da5Sopenharmony_ci sb.WriteString(strings.Trim(v.Kind.Kind, `'`)) 263fd4e5da5Sopenharmony_ci sb.WriteString("\n```") 264fd4e5da5Sopenharmony_ci case schema.OperandCategoryID: 265fd4e5da5Sopenharmony_ci if s := tok.Text(f.res.Lines); s != "" { 266fd4e5da5Sopenharmony_ci if id, ok := f.res.Identifiers[s]; ok && id.Definition != nil { 267fd4e5da5Sopenharmony_ci sb.WriteString("```\n") 268fd4e5da5Sopenharmony_ci sb.WriteString(id.Definition.Range.Text(f.res.Lines)) 269fd4e5da5Sopenharmony_ci sb.WriteString("\n```") 270fd4e5da5Sopenharmony_ci } 271fd4e5da5Sopenharmony_ci } 272fd4e5da5Sopenharmony_ci case schema.OperandCategoryLiteral: 273fd4e5da5Sopenharmony_ci case schema.OperandCategoryComposite: 274fd4e5da5Sopenharmony_ci } 275fd4e5da5Sopenharmony_ci case nil: 276fd4e5da5Sopenharmony_ci } 277fd4e5da5Sopenharmony_ci 278fd4e5da5Sopenharmony_ci if sb.Len() > 0 { 279fd4e5da5Sopenharmony_ci res := lsp.Hover{ 280fd4e5da5Sopenharmony_ci Contents: lsp.MarkupContent{ 281fd4e5da5Sopenharmony_ci Kind: "markdown", 282fd4e5da5Sopenharmony_ci Value: sb.String(), 283fd4e5da5Sopenharmony_ci }, 284fd4e5da5Sopenharmony_ci } 285fd4e5da5Sopenharmony_ci return &res, nil 286fd4e5da5Sopenharmony_ci } 287fd4e5da5Sopenharmony_ci } 288fd4e5da5Sopenharmony_ci 289fd4e5da5Sopenharmony_ci return nil, nil 290fd4e5da5Sopenharmony_ci} 291fd4e5da5Sopenharmony_cifunc (s *server) SignatureHelp(ctx context.Context, p *lsp.SignatureHelpParams) (*lsp.SignatureHelp, error) { 292fd4e5da5Sopenharmony_ci log.Println("server.SignatureHelp()") 293fd4e5da5Sopenharmony_ci return nil, nil 294fd4e5da5Sopenharmony_ci} 295fd4e5da5Sopenharmony_cifunc (s *server) Definition(ctx context.Context, p *lsp.DefinitionParams) ([]lsp.Location, error) { 296fd4e5da5Sopenharmony_ci log.Println("server.Definition()") 297fd4e5da5Sopenharmony_ci if f := s.getFile(p.TextDocument.URI); f != nil { 298fd4e5da5Sopenharmony_ci if tok := f.tokAt(p.Position); tok != nil { 299fd4e5da5Sopenharmony_ci if s := tok.Text(f.res.Lines); s != "" { 300fd4e5da5Sopenharmony_ci if id, ok := f.res.Identifiers[s]; ok { 301fd4e5da5Sopenharmony_ci loc := lsp.Location{ 302fd4e5da5Sopenharmony_ci URI: p.TextDocument.URI, 303fd4e5da5Sopenharmony_ci Range: rangeToLSP(id.Definition.Range), 304fd4e5da5Sopenharmony_ci } 305fd4e5da5Sopenharmony_ci return []lsp.Location{loc}, nil 306fd4e5da5Sopenharmony_ci } 307fd4e5da5Sopenharmony_ci } 308fd4e5da5Sopenharmony_ci } 309fd4e5da5Sopenharmony_ci } 310fd4e5da5Sopenharmony_ci return nil, nil 311fd4e5da5Sopenharmony_ci} 312fd4e5da5Sopenharmony_cifunc (s *server) References(ctx context.Context, p *lsp.ReferenceParams) ([]lsp.Location, error) { 313fd4e5da5Sopenharmony_ci log.Println("server.References()") 314fd4e5da5Sopenharmony_ci if f := s.getFile(p.TextDocument.URI); f != nil { 315fd4e5da5Sopenharmony_ci if tok := f.tokAt(p.Position); tok != nil { 316fd4e5da5Sopenharmony_ci if s := tok.Text(f.res.Lines); s != "" { 317fd4e5da5Sopenharmony_ci if id, ok := f.res.Identifiers[s]; ok { 318fd4e5da5Sopenharmony_ci locs := make([]lsp.Location, len(id.References)) 319fd4e5da5Sopenharmony_ci for i, r := range id.References { 320fd4e5da5Sopenharmony_ci locs[i] = lsp.Location{ 321fd4e5da5Sopenharmony_ci URI: p.TextDocument.URI, 322fd4e5da5Sopenharmony_ci Range: rangeToLSP(r.Range), 323fd4e5da5Sopenharmony_ci } 324fd4e5da5Sopenharmony_ci } 325fd4e5da5Sopenharmony_ci return locs, nil 326fd4e5da5Sopenharmony_ci } 327fd4e5da5Sopenharmony_ci } 328fd4e5da5Sopenharmony_ci } 329fd4e5da5Sopenharmony_ci } 330fd4e5da5Sopenharmony_ci return nil, nil 331fd4e5da5Sopenharmony_ci} 332fd4e5da5Sopenharmony_cifunc (s *server) DocumentHighlight(ctx context.Context, p *lsp.DocumentHighlightParams) ([]lsp.DocumentHighlight, error) { 333fd4e5da5Sopenharmony_ci log.Println("server.DocumentHighlight()") 334fd4e5da5Sopenharmony_ci return nil, nil 335fd4e5da5Sopenharmony_ci} 336fd4e5da5Sopenharmony_cifunc (s *server) DocumentSymbol(ctx context.Context, p *lsp.DocumentSymbolParams) ([]lsp.DocumentSymbol, error) { 337fd4e5da5Sopenharmony_ci log.Println("server.DocumentSymbol()") 338fd4e5da5Sopenharmony_ci return nil, nil 339fd4e5da5Sopenharmony_ci} 340fd4e5da5Sopenharmony_cifunc (s *server) CodeAction(ctx context.Context, p *lsp.CodeActionParams) ([]lsp.CodeAction, error) { 341fd4e5da5Sopenharmony_ci log.Println("server.CodeAction()") 342fd4e5da5Sopenharmony_ci return nil, nil 343fd4e5da5Sopenharmony_ci} 344fd4e5da5Sopenharmony_cifunc (s *server) Symbol(ctx context.Context, p *lsp.WorkspaceSymbolParams) ([]lsp.SymbolInformation, error) { 345fd4e5da5Sopenharmony_ci log.Println("server.Symbol()") 346fd4e5da5Sopenharmony_ci return nil, nil 347fd4e5da5Sopenharmony_ci} 348fd4e5da5Sopenharmony_cifunc (s *server) CodeLens(ctx context.Context, p *lsp.CodeLensParams) ([]lsp.CodeLens, error) { 349fd4e5da5Sopenharmony_ci log.Println("server.CodeLens()") 350fd4e5da5Sopenharmony_ci return nil, nil 351fd4e5da5Sopenharmony_ci} 352fd4e5da5Sopenharmony_cifunc (s *server) ResolveCodeLens(ctx context.Context, p *lsp.CodeLens) (*lsp.CodeLens, error) { 353fd4e5da5Sopenharmony_ci log.Println("server.ResolveCodeLens()") 354fd4e5da5Sopenharmony_ci return nil, nil 355fd4e5da5Sopenharmony_ci} 356fd4e5da5Sopenharmony_cifunc (s *server) DocumentLink(ctx context.Context, p *lsp.DocumentLinkParams) ([]lsp.DocumentLink, error) { 357fd4e5da5Sopenharmony_ci log.Println("server.DocumentLink()") 358fd4e5da5Sopenharmony_ci return nil, nil 359fd4e5da5Sopenharmony_ci} 360fd4e5da5Sopenharmony_cifunc (s *server) ResolveDocumentLink(ctx context.Context, p *lsp.DocumentLink) (*lsp.DocumentLink, error) { 361fd4e5da5Sopenharmony_ci log.Println("server.ResolveDocumentLink()") 362fd4e5da5Sopenharmony_ci return nil, nil 363fd4e5da5Sopenharmony_ci} 364fd4e5da5Sopenharmony_cifunc (s *server) Formatting(ctx context.Context, p *lsp.DocumentFormattingParams) ([]lsp.TextEdit, error) { 365fd4e5da5Sopenharmony_ci log.Println("server.Formatting()") 366fd4e5da5Sopenharmony_ci if f := s.getFile(p.TextDocument.URI); f != nil { 367fd4e5da5Sopenharmony_ci // Start by measuring the distance from the start of each line to the 368fd4e5da5Sopenharmony_ci // first opcode on that line. 369fd4e5da5Sopenharmony_ci lineInstOffsets, maxInstOffset, instOffset, curOffset := []int{}, 0, 0, -1 370fd4e5da5Sopenharmony_ci for _, t := range f.res.Tokens { 371fd4e5da5Sopenharmony_ci curOffset++ // whitespace between tokens 372fd4e5da5Sopenharmony_ci switch t.Type { 373fd4e5da5Sopenharmony_ci case parser.Ident: 374fd4e5da5Sopenharmony_ci if _, isInst := schema.Opcodes[t.Text(f.res.Lines)]; isInst && instOffset == 0 { 375fd4e5da5Sopenharmony_ci instOffset = curOffset 376fd4e5da5Sopenharmony_ci continue 377fd4e5da5Sopenharmony_ci } 378fd4e5da5Sopenharmony_ci case parser.Newline: 379fd4e5da5Sopenharmony_ci lineInstOffsets = append(lineInstOffsets, instOffset) 380fd4e5da5Sopenharmony_ci if instOffset > maxInstOffset { 381fd4e5da5Sopenharmony_ci maxInstOffset = instOffset 382fd4e5da5Sopenharmony_ci } 383fd4e5da5Sopenharmony_ci curOffset, instOffset = -1, 0 384fd4e5da5Sopenharmony_ci default: 385fd4e5da5Sopenharmony_ci curOffset += utf8.RuneCountInString(t.Text(f.res.Lines)) 386fd4e5da5Sopenharmony_ci } 387fd4e5da5Sopenharmony_ci } 388fd4e5da5Sopenharmony_ci lineInstOffsets = append(lineInstOffsets, instOffset) 389fd4e5da5Sopenharmony_ci 390fd4e5da5Sopenharmony_ci // Now rewrite each of the lines, adding padding at the start of the 391fd4e5da5Sopenharmony_ci // line for alignment. 392fd4e5da5Sopenharmony_ci sb, newline := strings.Builder{}, true 393fd4e5da5Sopenharmony_ci for _, t := range f.res.Tokens { 394fd4e5da5Sopenharmony_ci if newline { 395fd4e5da5Sopenharmony_ci newline = false 396fd4e5da5Sopenharmony_ci indent := maxInstOffset - lineInstOffsets[0] 397fd4e5da5Sopenharmony_ci lineInstOffsets = lineInstOffsets[1:] 398fd4e5da5Sopenharmony_ci switch t.Type { 399fd4e5da5Sopenharmony_ci case parser.Newline, parser.Comment: 400fd4e5da5Sopenharmony_ci default: 401fd4e5da5Sopenharmony_ci for s := 0; s < indent; s++ { 402fd4e5da5Sopenharmony_ci sb.WriteRune(' ') 403fd4e5da5Sopenharmony_ci } 404fd4e5da5Sopenharmony_ci } 405fd4e5da5Sopenharmony_ci } else if t.Type != parser.Newline { 406fd4e5da5Sopenharmony_ci sb.WriteString(" ") 407fd4e5da5Sopenharmony_ci } 408fd4e5da5Sopenharmony_ci 409fd4e5da5Sopenharmony_ci sb.WriteString(t.Text(f.res.Lines)) 410fd4e5da5Sopenharmony_ci if t.Type == parser.Newline { 411fd4e5da5Sopenharmony_ci newline = true 412fd4e5da5Sopenharmony_ci } 413fd4e5da5Sopenharmony_ci } 414fd4e5da5Sopenharmony_ci 415fd4e5da5Sopenharmony_ci formatted := sb.String() 416fd4e5da5Sopenharmony_ci 417fd4e5da5Sopenharmony_ci // Every good file ends with a single new line. 418fd4e5da5Sopenharmony_ci formatted = strings.TrimRight(formatted, "\n") + "\n" 419fd4e5da5Sopenharmony_ci 420fd4e5da5Sopenharmony_ci return []lsp.TextEdit{ 421fd4e5da5Sopenharmony_ci { 422fd4e5da5Sopenharmony_ci Range: rangeToLSP(f.fullRange), 423fd4e5da5Sopenharmony_ci NewText: formatted, 424fd4e5da5Sopenharmony_ci }, 425fd4e5da5Sopenharmony_ci }, nil 426fd4e5da5Sopenharmony_ci } 427fd4e5da5Sopenharmony_ci return nil, nil 428fd4e5da5Sopenharmony_ci} 429fd4e5da5Sopenharmony_cifunc (s *server) RangeFormatting(ctx context.Context, p *lsp.DocumentRangeFormattingParams) ([]lsp.TextEdit, error) { 430fd4e5da5Sopenharmony_ci log.Println("server.RangeFormatting()") 431fd4e5da5Sopenharmony_ci return nil, nil 432fd4e5da5Sopenharmony_ci} 433fd4e5da5Sopenharmony_cifunc (s *server) OnTypeFormatting(ctx context.Context, p *lsp.DocumentOnTypeFormattingParams) ([]lsp.TextEdit, error) { 434fd4e5da5Sopenharmony_ci log.Println("server.OnTypeFormatting()") 435fd4e5da5Sopenharmony_ci return nil, nil 436fd4e5da5Sopenharmony_ci} 437fd4e5da5Sopenharmony_cifunc (s *server) Rename(ctx context.Context, p *lsp.RenameParams) (*lsp.WorkspaceEdit, error) { 438fd4e5da5Sopenharmony_ci log.Println("server.Rename()") 439fd4e5da5Sopenharmony_ci if f := s.getFile(p.TextDocument.URI); f != nil { 440fd4e5da5Sopenharmony_ci if tok := f.tokAt(p.Position); tok != nil { 441fd4e5da5Sopenharmony_ci if s := tok.Text(f.res.Lines); s != "" { 442fd4e5da5Sopenharmony_ci if id, ok := f.res.Identifiers[s]; ok { 443fd4e5da5Sopenharmony_ci changes := make([]lsp.TextEdit, len(id.References)) 444fd4e5da5Sopenharmony_ci for i, r := range id.References { 445fd4e5da5Sopenharmony_ci changes[i].Range = rangeToLSP(r.Range) 446fd4e5da5Sopenharmony_ci changes[i].NewText = p.NewName 447fd4e5da5Sopenharmony_ci } 448fd4e5da5Sopenharmony_ci m := map[string][]lsp.TextEdit{} 449fd4e5da5Sopenharmony_ci m[p.TextDocument.URI] = changes 450fd4e5da5Sopenharmony_ci return &lsp.WorkspaceEdit{Changes: &m}, nil 451fd4e5da5Sopenharmony_ci } 452fd4e5da5Sopenharmony_ci } 453fd4e5da5Sopenharmony_ci } 454fd4e5da5Sopenharmony_ci } 455fd4e5da5Sopenharmony_ci return nil, nil 456fd4e5da5Sopenharmony_ci} 457fd4e5da5Sopenharmony_cifunc (s *server) PrepareRename(ctx context.Context, p *lsp.PrepareRenameParams) (*lsp.Range, error) { 458fd4e5da5Sopenharmony_ci log.Println("server.PrepareRename()") 459fd4e5da5Sopenharmony_ci return nil, nil 460fd4e5da5Sopenharmony_ci} 461fd4e5da5Sopenharmony_cifunc (s *server) ExecuteCommand(ctx context.Context, p *lsp.ExecuteCommandParams) (interface{}, error) { 462fd4e5da5Sopenharmony_ci log.Println("server.ExecuteCommand()") 463fd4e5da5Sopenharmony_ci return nil, nil 464fd4e5da5Sopenharmony_ci} 465fd4e5da5Sopenharmony_ci 466fd4e5da5Sopenharmony_cifunc (s *server) processFile(ctx context.Context, uri, source string) error { 467fd4e5da5Sopenharmony_ci log.Println("server.DidOpen()") 468fd4e5da5Sopenharmony_ci res, err := parser.Parse(source) 469fd4e5da5Sopenharmony_ci if err != nil { 470fd4e5da5Sopenharmony_ci return err 471fd4e5da5Sopenharmony_ci } 472fd4e5da5Sopenharmony_ci fullRange := parser.Range{ 473fd4e5da5Sopenharmony_ci Start: parser.Position{Line: 1, Column: 1}, 474fd4e5da5Sopenharmony_ci End: parser.Position{Line: len(res.Lines), Column: utf8.RuneCountInString(res.Lines[len(res.Lines)-1]) + 1}, 475fd4e5da5Sopenharmony_ci } 476fd4e5da5Sopenharmony_ci 477fd4e5da5Sopenharmony_ci s.filesMutex.Lock() 478fd4e5da5Sopenharmony_ci s.files[uri] = &file{ 479fd4e5da5Sopenharmony_ci fullRange: fullRange, 480fd4e5da5Sopenharmony_ci res: res, 481fd4e5da5Sopenharmony_ci } 482fd4e5da5Sopenharmony_ci s.filesMutex.Unlock() 483fd4e5da5Sopenharmony_ci 484fd4e5da5Sopenharmony_ci dp := lsp.PublishDiagnosticsParams{URI: uri, Diagnostics: make([]lsp.Diagnostic, len(res.Diagnostics))} 485fd4e5da5Sopenharmony_ci for i, d := range res.Diagnostics { 486fd4e5da5Sopenharmony_ci dp.Diagnostics[i] = diagnosticToLSP(d) 487fd4e5da5Sopenharmony_ci } 488fd4e5da5Sopenharmony_ci s.client.PublishDiagnostics(ctx, &dp) 489fd4e5da5Sopenharmony_ci return nil 490fd4e5da5Sopenharmony_ci} 491fd4e5da5Sopenharmony_ci 492fd4e5da5Sopenharmony_cifunc (s *server) getFile(uri string) *file { 493fd4e5da5Sopenharmony_ci s.filesMutex.Lock() 494fd4e5da5Sopenharmony_ci defer s.filesMutex.Unlock() 495fd4e5da5Sopenharmony_ci return s.files[uri] 496fd4e5da5Sopenharmony_ci} 497fd4e5da5Sopenharmony_ci 498fd4e5da5Sopenharmony_cifunc diagnosticToLSP(d parser.Diagnostic) lsp.Diagnostic { 499fd4e5da5Sopenharmony_ci return lsp.Diagnostic{ 500fd4e5da5Sopenharmony_ci Range: rangeToLSP(d.Range), 501fd4e5da5Sopenharmony_ci Severity: severityToLSP(d.Severity), 502fd4e5da5Sopenharmony_ci Message: d.Message, 503fd4e5da5Sopenharmony_ci } 504fd4e5da5Sopenharmony_ci} 505fd4e5da5Sopenharmony_ci 506fd4e5da5Sopenharmony_cifunc severityToLSP(s parser.Severity) lsp.DiagnosticSeverity { 507fd4e5da5Sopenharmony_ci switch s { 508fd4e5da5Sopenharmony_ci case parser.SeverityError: 509fd4e5da5Sopenharmony_ci return lsp.SeverityError 510fd4e5da5Sopenharmony_ci case parser.SeverityWarning: 511fd4e5da5Sopenharmony_ci return lsp.SeverityWarning 512fd4e5da5Sopenharmony_ci case parser.SeverityInformation: 513fd4e5da5Sopenharmony_ci return lsp.SeverityInformation 514fd4e5da5Sopenharmony_ci case parser.SeverityHint: 515fd4e5da5Sopenharmony_ci return lsp.SeverityHint 516fd4e5da5Sopenharmony_ci default: 517fd4e5da5Sopenharmony_ci log.Panicf("Invalid severity '%d'", int(s)) 518fd4e5da5Sopenharmony_ci return lsp.SeverityError 519fd4e5da5Sopenharmony_ci } 520fd4e5da5Sopenharmony_ci} 521fd4e5da5Sopenharmony_ci 522fd4e5da5Sopenharmony_cifunc rangeToLSP(r parser.Range) lsp.Range { 523fd4e5da5Sopenharmony_ci return lsp.Range{ 524fd4e5da5Sopenharmony_ci Start: positionToLSP(r.Start), 525fd4e5da5Sopenharmony_ci End: positionToLSP(r.End), 526fd4e5da5Sopenharmony_ci } 527fd4e5da5Sopenharmony_ci} 528fd4e5da5Sopenharmony_ci 529fd4e5da5Sopenharmony_cifunc positionToLSP(r parser.Position) lsp.Position { 530fd4e5da5Sopenharmony_ci return lsp.Position{ 531fd4e5da5Sopenharmony_ci Line: float64(r.Line - 1), 532fd4e5da5Sopenharmony_ci Character: float64(r.Column - 1), 533fd4e5da5Sopenharmony_ci } 534fd4e5da5Sopenharmony_ci} 535