|
4 | 4 | "bytes" |
5 | 5 | "context" |
6 | 6 | "encoding/json" |
| 7 | + "fmt" |
7 | 8 | "io" |
8 | 9 | "io/ioutil" |
9 | 10 | "log" |
@@ -587,29 +588,32 @@ func (handler *InoHandler) transformClangdResult(method string, uri lsp.Document |
587 | 588 | handler.cpp2inoTextEdit(&(*r)[index], uri) |
588 | 589 | } |
589 | 590 | case "textDocument/documentSymbol": |
590 | | - r := result.(*[]*documentSymbolOrSymbolInformation) |
| 591 | + r, ok := result.(*[]*documentSymbolOrSymbolInformation) |
| 592 | + |
| 593 | + if !ok || len(*r) == 0 { |
| 594 | + return result |
| 595 | + } |
| 596 | + |
591 | 597 | slice := *r |
592 | | - if len(slice) > 0 && slice[0].DocumentSymbol != nil { |
| 598 | + if slice[0].DocumentSymbol != nil { |
593 | 599 | // Treat the input as []DocumentSymbol |
594 | 600 | symbols := make([]DocumentSymbol, len(slice)) |
595 | 601 | for index := range slice { |
596 | 602 | symbols[index] = *slice[index].DocumentSymbol |
597 | 603 | } |
598 | | - result = handler.cpp2inoDocumentSymbols(symbols, uri) |
599 | | - } else if len(slice) > 0 && slice[0].SymbolInformation != nil { |
| 604 | + return handler.cpp2inoDocumentSymbols(symbols, uri) |
| 605 | + } |
| 606 | + if slice[0].SymbolInformation != nil { |
600 | 607 | // Treat the input as []SymbolInformation |
601 | | - symbols := make([]lsp.SymbolInformation, len(slice)) |
602 | | - for index := range slice { |
603 | | - symbols[index] = *slice[index].SymbolInformation |
| 608 | + symbols := make([]*lsp.SymbolInformation, len(slice)) |
| 609 | + for i, s := range slice { |
| 610 | + symbols[i] = s.SymbolInformation |
604 | 611 | } |
605 | | - for index := range symbols { |
606 | | - handler.cpp2inoLocation(&symbols[index].Location) |
607 | | - } |
608 | | - result = symbols |
| 612 | + return handler.cpp2inoSymbolInformation(symbols) |
609 | 613 | } |
610 | 614 | case "textDocument/rename": |
611 | 615 | r := result.(*lsp.WorkspaceEdit) |
612 | | - result = handler.cpp2inoWorkspaceEdit(r) |
| 616 | + return handler.cpp2inoWorkspaceEdit(r) |
613 | 617 | case "workspace/symbol": |
614 | 618 | r := result.(*[]lsp.SymbolInformation) |
615 | 619 | for index := range *r { |
@@ -711,29 +715,61 @@ func (handler *InoHandler) cpp2inoDocumentSymbols(origSymbols []DocumentSymbol, |
711 | 715 | if !ok || len(origSymbols) == 0 { |
712 | 716 | return origSymbols |
713 | 717 | } |
714 | | - newSymbols := make([]DocumentSymbol, len(origSymbols)) |
715 | | - j := 0 |
| 718 | + |
| 719 | + symbolIdx := make(map[string]*DocumentSymbol) |
716 | 720 | for i := 0; i < len(origSymbols); i++ { |
717 | 721 | symbol := &origSymbols[i] |
718 | 722 | symbol.Range.Start.Line = data.sourceLineMap[symbol.Range.Start.Line] |
719 | 723 | symbol.Range.End.Line = data.sourceLineMap[symbol.Range.End.Line] |
720 | 724 |
|
721 | 725 | duplicate := false |
722 | | - for k := 0; k < j; k++ { |
723 | | - if symbol.Name == newSymbols[k].Name && symbol.Range.Start.Line == newSymbols[k].Range.Start.Line { |
724 | | - duplicate = true |
725 | | - break |
| 726 | + other, duplicate := symbolIdx[symbol.Name] |
| 727 | + if duplicate { |
| 728 | + // we prefer symbols later in the file due to the function header generation. E.g. if one has a function `void foo() {}` somehwre in the code |
| 729 | + // the code generation will add a `void foo();` header at the beginning of the cpp file. We care about the function body later in the file, not |
| 730 | + // the header early on. |
| 731 | + if other.Range.Start.Line < symbol.Range.Start.Line { |
| 732 | + continue |
726 | 733 | } |
727 | 734 | } |
728 | | - if !duplicate { |
729 | | - symbol.SelectionRange.Start.Line = data.sourceLineMap[symbol.SelectionRange.Start.Line] |
730 | | - symbol.SelectionRange.End.Line = data.sourceLineMap[symbol.SelectionRange.End.Line] |
731 | | - symbol.Children = handler.cpp2inoDocumentSymbols(symbol.Children, uri) |
732 | | - newSymbols[j] = *symbol |
733 | | - j++ |
| 735 | + |
| 736 | + symbol.SelectionRange.Start.Line = data.sourceLineMap[symbol.SelectionRange.Start.Line] |
| 737 | + symbol.SelectionRange.End.Line = data.sourceLineMap[symbol.SelectionRange.End.Line] |
| 738 | + symbol.Children = handler.cpp2inoDocumentSymbols(symbol.Children, uri) |
| 739 | + symbolIdx[symbol.Name] = symbol |
| 740 | + } |
| 741 | + |
| 742 | + newSymbols := make([]DocumentSymbol, len(symbolIdx)) |
| 743 | + j := 0 |
| 744 | + for _, s := range symbolIdx { |
| 745 | + newSymbols[j] = *s |
| 746 | + j++ |
| 747 | + } |
| 748 | + return newSymbols |
| 749 | +} |
| 750 | + |
| 751 | +func (handler *InoHandler) cpp2inoSymbolInformation(syms []*lsp.SymbolInformation) []lsp.SymbolInformation { |
| 752 | + // much like in cpp2inoDocumentSymbols we de-duplicate symbols based on file in-file location. |
| 753 | + idx := make(map[string]*lsp.SymbolInformation) |
| 754 | + for _, sym := range syms { |
| 755 | + handler.cpp2inoLocation(&sym.Location) |
| 756 | + |
| 757 | + nme := fmt.Sprintf("%s::%s", sym.ContainerName, sym.Name) |
| 758 | + other, duplicate := idx[nme] |
| 759 | + if duplicate && other.Location.Range.Start.Line < sym.Location.Range.Start.Line { |
| 760 | + continue |
734 | 761 | } |
| 762 | + |
| 763 | + idx[nme] = sym |
| 764 | + } |
| 765 | + |
| 766 | + var j int |
| 767 | + symbols := make([]lsp.SymbolInformation, len(idx)) |
| 768 | + for _, sym := range idx { |
| 769 | + symbols[j] = *sym |
| 770 | + j++ |
735 | 771 | } |
736 | | - return newSymbols[:j] |
| 772 | + return symbols |
737 | 773 | } |
738 | 774 |
|
739 | 775 | // FromClangd handles a message received from clangd. |
|
0 commit comments