Skip to content

Commit

Permalink
Basic implementation of language server document highlight.
Browse files Browse the repository at this point in the history
If the cursor is on a symbol, this will highlight all the symbols
in the buffer with the same name (it does _not_ take naming
scopes into account yet).

Signed-off-by: Henner Zeller <[email protected]>
  • Loading branch information
hzeller committed Nov 4, 2021
1 parent f49690d commit a2ae26e
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 7 deletions.
13 changes: 13 additions & 0 deletions common/lsp/lsp-protocol.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ TextDocumentContentChangeEvent:
range?: Range # Range optional; if no range given, full document replace
text: string

# For hover or highlight
TextDocumentPositionParams:
textDocument: TextDocumentIdentifier
position: Position

# -- Text document notifiations. These allow us to keep track of the content.
DidOpenTextDocumentParams: # textDocument/didOpen
textDocument: TextDocumentItem
Expand Down Expand Up @@ -108,3 +113,11 @@ DocumentSymbol:
# children: DocumentSymbol[]. Since we can't to that recursively in jcxxgen,
# these are directly emitted as json
children?: object = nullptr

# -- textDocument/documentHighlight
DocumentHighlightParams:
<: TextDocumentPositionParams

DocumentHighlight: # response documentHighlight is [] of this.
range: Range
# there is also a highlight kind to distinguish read/write
1 change: 1 addition & 0 deletions verilog/tools/ls/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ cc_library(
"//common/text:text_structure",
"//verilog/analysis:verilog_analyzer",
"//verilog/analysis:verilog_linter",
"//verilog/parser:verilog_token_enum",
"@jsonhpp",
],
)
Expand Down
3 changes: 2 additions & 1 deletion verilog/tools/ls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ progress
- [x] Provide code actions for autofixes provided by lint rules
- [x] Generate file symbol outline ('navigation tree')
- [ ] Provide formatting.
- [ ] Highlight all the symbols that are the same as current under cursor.
- [x] Highlight all the symbols that are the same as current under cursor.
- [ ] Take scope and type into account to only highlight _same_ symbols.
- [ ] Find definition of symbol even if in another file.
- [ ] Rename refactor a symbol

Expand Down
32 changes: 32 additions & 0 deletions verilog/tools/ls/verible-lsp-adapter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "nlohmann/json.hpp"
#include "verilog/analysis/verilog_analyzer.h"
#include "verilog/analysis/verilog_linter.h"
#include "verilog/parser/verilog_token_enum.h"
#include "verilog/tools/ls/document-symbol-filler.h"
#include "verilog/tools/ls/lsp-parse-buffer.h"

Expand Down Expand Up @@ -172,4 +173,35 @@ nlohmann::json CreateDocumentSymbolOutline(
return toplevel.children;
}

std::vector<verible::lsp::DocumentHighlight> CreateHighlightRanges(
const BufferTracker *tracker,
const verible::lsp::DocumentHighlightParams &p) {
std::vector<verible::lsp::DocumentHighlight> result;
if (!tracker) return result;
const ParsedBuffer *const current = tracker->current();
if (!current) return result;
const verible::LineColumn cursor{p.position.line, p.position.character};
const verible::TextStructureView &text = current->parser().Data();
const verible::TokenInfo cursor_token = text.FindTokenAt(cursor);

if (cursor_token.token_enum() == SymbolIdentifier) {
// Find all the symbols with the same name in the buffer.
// Note, this is very simplistic as it does _not_ take scopes into account.
// For that, we'd need the symbol table, but that implementation is not
// complete yet.
for (const verible::TokenInfo &tok : text.TokenStream()) {
if (tok.token_enum() != cursor_token.token_enum()) continue;
if (tok.text() != cursor_token.text()) continue;
const verible::LineColumnRange range = text.GetRangeForToken(tok);
result.push_back(verible::lsp::DocumentHighlight{
.range = {
.start = {.line = range.start.line,
.character = range.start.column},
.end = {.line = range.end.line, .character = range.end.column},
}});
}
}
return result;
}

} // namespace verilog
8 changes: 8 additions & 0 deletions verilog/tools/ls/verible-lsp-adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,13 @@ std::vector<verible::lsp::CodeAction> GenerateLinterCodeActions(
nlohmann::json CreateDocumentSymbolOutline(
const BufferTracker *tracker, const verible::lsp::DocumentSymbolParams &p,
bool kate_compatible_tags = true);

// Give a position in a document, return ranges in the buffer that should
// be hi-lit.
// Current implementation: if cursor is over a symbol, highlight all symbols
// with the same name (NB: Does _not_ take scoping into account yet).
std::vector<verible::lsp::DocumentHighlight> CreateHighlightRanges(
const BufferTracker *tracker,
const verible::lsp::DocumentHighlightParams &p);
} // namespace verilog
#endif // VERILOG_TOOLS_LS_VERIBLE_LSP_ADAPTER_H
18 changes: 12 additions & 6 deletions verilog/tools/ls/verilog_ls.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ static InitializeResult InitializeServer(const nlohmann::json &params) {
{"change", 2}, // Incremental updates
},
},
{"codeActionProvider", true}, // Autofixes for lint errors
{"documentSymbolProvider", true}, // Outline of file
{"codeActionProvider", true}, // Autofixes for lint errors
{"documentSymbolProvider", true}, // Symbol-outline of file
{"documentHighlightProvider", true}, // Highlight same symbol
};

return result;
Expand Down Expand Up @@ -133,22 +134,27 @@ int main(int argc, char *argv[]) {
// Exchange of capabilities.
dispatcher.AddRequestHandler("initialize", InitializeServer);

// Provide autofixes
dispatcher.AddRequestHandler(
dispatcher.AddRequestHandler( // Provide autofixes
"textDocument/codeAction",
[&parsed_buffers](const verible::lsp::CodeActionParams &p) {
return verilog::GenerateLinterCodeActions(
parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
});

// Provide outline
dispatcher.AddRequestHandler(
dispatcher.AddRequestHandler( // Provide document outline/index
"textDocument/documentSymbol",
[&parsed_buffers](const verible::lsp::DocumentSymbolParams &p) {
return verilog::CreateDocumentSymbolOutline(
parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
});

dispatcher.AddRequestHandler( // Highlight related symbols under cursor
"textDocument/documentHighlight",
[&parsed_buffers](const verible::lsp::DocumentHighlightParams &p) {
return verilog::CreateHighlightRanges(
parsed_buffers.FindBufferTrackerOrNull(p.textDocument.uri), p);
});

// The client sends a request to shut down. Use that to exit our loop.
bool shutdown_requested = false;
dispatcher.AddRequestHandler("shutdown",
Expand Down

0 comments on commit a2ae26e

Please sign in to comment.