aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorDaniel Gavin <danielgavin5@hotmail.com>2022-03-19 20:44:29 +0100
committerDaniel Gavin <danielgavin5@hotmail.com>2022-03-19 20:44:29 +0100
commitedcf80026173f9d20ca2df6f574640302bed4bdf (patch)
tree0954d648e812151403ce133f5b956219d455a3cb /src/server
parent06b76ac1ee9d8f607d944ce9757ebe40adefcf2a (diff)
Prepare for rename
Diffstat (limited to 'src/server')
-rw-r--r--src/server/caches.odin6
-rw-r--r--src/server/completion.odin68
-rw-r--r--src/server/documents.odin4
-rw-r--r--src/server/hover.odin10
-rw-r--r--src/server/inlay_hints.odin6
-rw-r--r--src/server/on_typing.odin1
-rw-r--r--src/server/rename.odin71
-rw-r--r--src/server/requests.odin47
-rw-r--r--src/server/semantic_tokens.odin16
-rw-r--r--src/server/types.odin38
10 files changed, 243 insertions, 24 deletions
diff --git a/src/server/caches.odin b/src/server/caches.odin
index 2bb4b7f..cc993c3 100644
--- a/src/server/caches.odin
+++ b/src/server/caches.odin
@@ -6,16 +6,18 @@ import "shared:common"
//Used in semantic tokens and inlay hints to handle the entire file being resolved.
FileResolveCache :: struct {
- files: map[string]map[uintptr]index.Symbol,
+ files: map[string]map[uintptr]index.SymbolAndNode,
}
file_resolve_cache: FileResolveCache
-resolve_entire_file :: proc(document: ^common.Document) {
+resolve_entire_file :: proc(document: ^common.Document) -> map[uintptr]index.SymbolAndNode{
if document.uri.uri not_in file_resolve_cache.files {
file_resolve_cache.files[document.uri.uri] = analysis.resolve_entire_file(
document,
common.scratch_allocator(document.allocator),
)
}
+
+ return file_resolve_cache.files[document.uri.uri];
}
diff --git a/src/server/completion.odin b/src/server/completion.odin
index 6e67e35..4f9d4d0 100644
--- a/src/server/completion.odin
+++ b/src/server/completion.odin
@@ -460,6 +460,9 @@ get_selector_completion :: proc(ast_context: ^analysis.AstContext, position_cont
case index.SymbolDynamicArrayValue:
list.isIncomplete = false
append_magic_dynamic_array_completion(position_context, selector, &items)
+ case index.SymbolMapValue:
+ list.isIncomplete = false
+ append_magic_map_completion(position_context, selector, &items)
}
list.items = items[:]
@@ -1229,6 +1232,50 @@ get_range_from_selection_start_to_dot :: proc(position_context: ^analysis.Docume
return {}, false
}
+append_magic_map_completion :: proc(position_context: ^analysis.DocumentPositionContext, symbol: index.Symbol, items: ^[dynamic]CompletionItem) {
+ range, ok := get_range_from_selection_start_to_dot(position_context)
+
+ if !ok {
+ return
+ }
+
+ remove_range := common.Range {
+ start = range.start,
+ end = range.end,
+ }
+
+ remove_edit := TextEdit {
+ range = remove_range,
+ newText = "",
+ }
+
+ additionalTextEdits := make([]TextEdit, 1, context.temp_allocator)
+ additionalTextEdits[0] = remove_edit
+
+ //for
+ {
+ item := CompletionItem {
+ label = "for",
+ kind = .Snippet,
+ detail = "for",
+ additionalTextEdits = additionalTextEdits,
+ textEdit = TextEdit {
+ newText = fmt.tprintf("for k, v in %v {{\n\t$0 \n}}", symbol.name),
+ range = {
+ start = range.end,
+ end = range.end,
+ },
+ },
+ insertTextFormat = .Snippet,
+ InsertTextMode = .adjustIndentation,
+ }
+
+ append(items, item)
+ }
+
+
+}
+
append_magic_dynamic_array_completion :: proc(position_context: ^analysis.DocumentPositionContext, symbol: index.Symbol, items: ^[dynamic]CompletionItem) {
range, ok := get_range_from_selection_start_to_dot(position_context)
@@ -1269,6 +1316,27 @@ append_magic_dynamic_array_completion :: proc(position_context: ^analysis.Docume
append(items, item)
}
+
+ //for
+ {
+ item := CompletionItem {
+ label = "for",
+ kind = .Snippet,
+ detail = "for",
+ additionalTextEdits = additionalTextEdits,
+ textEdit = TextEdit {
+ newText = fmt.tprintf("for i in %v {{\n\t$0 \n}}", symbol.name),
+ range = {
+ start = range.end,
+ end = range.end,
+ },
+ },
+ insertTextFormat = .Snippet,
+ InsertTextMode = .adjustIndentation,
+ }
+
+ append(items, item)
+ }
}
diff --git a/src/server/documents.odin b/src/server/documents.odin
index 3ac8cdc..0c18249 100644
--- a/src/server/documents.odin
+++ b/src/server/documents.odin
@@ -133,7 +133,7 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config,
/*
Function that applies changes to the given document through incremental syncronization
*/
-document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, config: ^common.Config, writer: ^Writer) -> common.Error {
+document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, version: Maybe(int), config: ^common.Config, writer: ^Writer) -> common.Error {
uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator)
if !parsed_ok {
@@ -142,6 +142,8 @@ document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumen
document := &document_storage.documents[uri.path]
+ document.version = version
+
if !document.client_owned {
log.errorf("Client called change on an document not opened: %v ", document.uri.path)
return .InvalidRequest
diff --git a/src/server/hover.odin b/src/server/hover.odin
index a5c3b5e..4286ee8 100644
--- a/src/server/hover.odin
+++ b/src/server/hover.odin
@@ -127,10 +127,10 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit
for name, i in v.names {
if strings.compare(name, field) == 0 {
if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok {
- symbol.name = name //TODO refractor - never set symbol name after creation - change writer_hover_content
- symbol.pkg = selector.name
+ symbol.name = name //TODO refractor - never set symbol name after creation - change writer_hover_content
+ symbol.pkg = selector.name
symbol.signature = common.node_to_string(v.types[i])
- hover.contents = write_hover_content(&ast_context, symbol)
+ hover.contents = write_hover_content(&ast_context, symbol)
return hover, true
}
}
@@ -147,8 +147,8 @@ get_hover_information :: proc(document: ^common.Document, position: common.Posit
}
}
} else if position_context.identifier != nil {
- ast_context.use_locals = true
- ast_context.use_globals = true
+ ast_context.use_locals = true
+ ast_context.use_globals = true
ast_context.current_package = ast_context.document_package
ident := position_context.identifier.derived.(^ast.Ident)^
diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin
index ae3d9a0..a5be9c2 100644
--- a/src/server/inlay_hints.odin
+++ b/src/server/inlay_hints.odin
@@ -8,7 +8,7 @@ import "shared:analysis"
import "shared:index"
//document
-get_inlay_hints :: proc(document: ^common.Document, symbols: map[uintptr]index.Symbol) -> ([]InlayHint, bool) {
+get_inlay_hints :: proc(document: ^common.Document, symbols: map[uintptr]index.SymbolAndNode) -> ([]InlayHint, bool) {
using analysis
hints := make([dynamic]InlayHint, context.temp_allocator)
@@ -57,8 +57,8 @@ get_inlay_hints :: proc(document: ^common.Document, symbols: map[uintptr]index.S
}
}
- if symbol, ok := symbols[cast(uintptr)node_call]; ok {
- if symbol_call, ok := symbol.value.(index.SymbolProcedureValue); ok {
+ if symbol_and_node, ok := symbols[cast(uintptr)node_call]; ok {
+ if symbol_call, ok := symbol_and_node.symbol.value.(index.SymbolProcedureValue); ok {
for arg in symbol_call.arg_types {
for name in arg.names {
if symbol_arg_count >= len(call.args) {
diff --git a/src/server/on_typing.odin b/src/server/on_typing.odin
new file mode 100644
index 0000000..abb4e43
--- /dev/null
+++ b/src/server/on_typing.odin
@@ -0,0 +1 @@
+package server
diff --git a/src/server/rename.odin b/src/server/rename.odin
new file mode 100644
index 0000000..b7d39ef
--- /dev/null
+++ b/src/server/rename.odin
@@ -0,0 +1,71 @@
+package server
+
+import "shared:common"
+import "shared:analysis"
+
+import "core:log"
+import "core:odin/ast"
+
+get_rename :: proc(document: ^common.Document, new_text: string, position: common.Position) -> (WorkspaceEdit, bool) {
+ using analysis
+
+ workspace: WorkspaceEdit
+
+ document_changes := make([dynamic]TextDocumentEdit, context.temp_allocator)
+
+ edits := make([dynamic]TextEdit, context.temp_allocator)
+
+ symbol_and_nodes := resolve_entire_file(document)
+
+ ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri)
+
+ position_context, ok := get_document_position_context(document, position, .Hover)
+
+ get_globals(document.ast, &ast_context)
+
+ if position_context.function != nil {
+ get_locals(document.ast, position_context.function, &ast_context, &position_context)
+ }
+
+ if position_context.identifier != nil {
+ ast_context.use_locals = true
+ ast_context.use_globals = true
+ ast_context.current_package = ast_context.document_package
+
+ ident := position_context.identifier.derived.(^ast.Ident)^
+
+ if resolved, ok := resolve_type_identifier(&ast_context, ident); ok {
+ for k, v in symbol_and_nodes {
+ if ident2, ok := v.node.derived.(^ast.Ident); ok {
+ log.error(ident2)
+ }
+ if ident2, ok := v.node.derived.(^ast.Ident); ok && resolved.pkg == v.symbol.pkg && ident2.name == ident.name {
+ edit := TextEdit {
+ newText = new_text,
+ range = common.get_token_range(v.node^, position_context.file.src),
+ }
+ append(&edits, edit)
+ }
+ }
+
+
+
+
+ }
+
+ }
+
+ document_change := TextDocumentEdit {
+ edits = edits[:],
+ textDocument = {
+ uri = document.uri.uri,
+ version = document.version,
+ },
+ }
+
+ append(&document_changes, document_change)
+
+ workspace.documentChanges = document_changes[:]
+
+ return workspace, true
+} \ No newline at end of file
diff --git a/src/server/requests.odin b/src/server/requests.odin
index 0c63e46..38e390f 100644
--- a/src/server/requests.odin
+++ b/src/server/requests.odin
@@ -261,6 +261,7 @@ call_map : map [string] proc(json.Value, RequestId, ^common.Config, ^Writer) ->
"textDocument/formatting" = request_format_document,
"odin/inlayHints" = request_inlay_hint,
"textDocument/documentLink" = request_document_links,
+ "textDocument/rename" = request_rename,
}
notification_map: map [string] bool = {
@@ -502,6 +503,7 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C
includeText = true,
},
},
+ renameProvider = false,
definitionProvider = true,
completionProvider = CompletionOptions {
resolveProvider = false,
@@ -665,9 +667,14 @@ request_signature_help :: proc (params: json.Value, id: RequestId, config: ^comm
return .InternalError
}
- response := make_response_message(params = help, id = id)
+ if len(help.signatures) == 0 {
+ response := make_response_message(params = nil, id = id)
+ send_response(response, writer)
+ } else {
+ response := make_response_message(params = help, id = id)
+ send_response(response, writer)
+ }
- send_response(response, writer)
return .None
}
@@ -745,7 +752,7 @@ notification_did_change :: proc (params: json.Value, id: RequestId, config: ^com
return .ParseError
}
- document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, config, writer)
+ document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, change_params.textDocument.version, config, writer)
return .None
}
@@ -1050,4 +1057,38 @@ request_document_links :: proc (params: json.Value, id: RequestId, config: ^comm
send_response(response, writer)
return .None
+}
+
+request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error {
+ params_object, ok := params.(json.Object)
+
+ if !ok {
+ return .ParseError
+ }
+
+ rename_param: RenameParams
+
+ if unmarshal(params, rename_param, context.temp_allocator) != .None {
+ return .ParseError
+ }
+
+ document := document_get(rename_param.textDocument.uri)
+
+ if document == nil {
+ return .InternalError
+ }
+
+ workspace_edit: WorkspaceEdit
+
+ workspace_edit, ok = get_rename(document, rename_param.newName, rename_param.position)
+
+ if !ok {
+ return .InternalError
+ }
+
+ response := make_response_message(params = workspace_edit, id = id)
+
+ send_response(response, writer)
+
+ return .None
} \ No newline at end of file
diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin
index 98f534b..5ae011d 100644
--- a/src/server/semantic_tokens.odin
+++ b/src/server/semantic_tokens.odin
@@ -78,7 +78,7 @@ SemanticTokens :: struct {
SemanticTokenBuilder :: struct {
current_start: int,
tokens: [dynamic]u32,
- symbols: map[uintptr]index.Symbol,
+ symbols: map[uintptr]index.SymbolAndNode,
selector: bool,
}
@@ -94,7 +94,7 @@ get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens {
}
}
-get_semantic_tokens :: proc(document: ^common.Document, range: common.Range, symbols: map[uintptr]index.Symbol) -> SemanticTokens {
+get_semantic_tokens :: proc(document: ^common.Document, range: common.Range, symbols: map[uintptr]index.SymbolAndNode) -> SemanticTokens {
using analysis
builder := make_token_builder()
@@ -172,13 +172,13 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context:
write_semantic_string(builder, node.pos, "..", ast_context.file.src, .Operator, .None)
visit(n.expr, builder, ast_context)
case ^Ident:
- if symbol, ok := builder.symbols[cast(uintptr)node]; ok {
- if symbol.type == .Variable {
+ if symbol_and_node, ok := builder.symbols[cast(uintptr)node]; ok {
+ if symbol_and_node.symbol.type == .Variable {
write_semantic_node(builder, node, ast_context.file.src, .Variable, .None)
return
}
- #partial switch v in symbol.value {
+ #partial switch v in symbol_and_node.symbol.value {
case index.SymbolPackageValue:
write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None)
case index.SymbolStructValue:
@@ -506,11 +506,11 @@ visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuil
builder.selector = true
}
- if symbol, ok := builder.symbols[cast(uintptr)selector]; ok {
- if symbol.type == .Variable {
+ if symbol_and_node, ok := builder.symbols[cast(uintptr)selector]; ok {
+ if symbol_and_node.symbol.type == .Variable {
write_semantic_node(builder, selector.field, ast_context.file.src, .Method, .None)
}
- #partial switch v in symbol.value {
+ #partial switch v in symbol_and_node.symbol.value {
case index.SymbolPackageValue:
write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None)
case index.SymbolStructValue:
diff --git a/src/server/types.odin b/src/server/types.odin
index 1440472..54168d7 100644
--- a/src/server/types.odin
+++ b/src/server/types.odin
@@ -28,6 +28,7 @@ ResponseParams :: union {
[]TextEdit,
[]InlayHint,
[]DocumentLink,
+ WorkspaceEdit,
}
ResponseMessage :: struct {
@@ -94,6 +95,7 @@ ServerCapabilities :: struct {
hoverProvider: bool,
documentFormattingProvider: bool,
inlayHintsProvider: bool,
+ renameProvider: bool,
documentLinkProvider: DocumentLinkOptions,
}
@@ -170,7 +172,8 @@ Version :: union {
}
VersionedTextDocumentIdentifier :: struct {
- uri: string,
+ uri: string,
+ version: int,
}
TextDocumentIdentifier :: struct {
@@ -416,4 +419,35 @@ DocumentLink :: struct {
DocumentLinkOptions :: struct {
resolveProvider: bool,
-} \ No newline at end of file
+}
+
+PrepareSupportDefaultBehavior :: enum {
+ Identifier = 1,
+}
+
+RenameClientCapabilities :: struct {
+ prepareSupport: bool,
+ prepareSupportDefaultBehavior: PrepareSupportDefaultBehavior,
+ honorsChangeAnnotations: bool,
+}
+
+RenameParams :: struct {
+ newName: string,
+ textDocument: TextDocumentIdentifier,
+ position: common.Position,
+}
+
+OptionalVersionedTextDocumentIdentifier :: struct {
+ uri: string,
+ version: Maybe(int),
+}
+
+TextDocumentEdit :: struct {
+ textDocument: OptionalVersionedTextDocumentIdentifier,
+ edits: []TextEdit,
+}
+
+WorkspaceEdit :: struct {
+ documentChanges: []TextDocumentEdit,
+}
+