aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDamian Tarnawski <gthetarnav@gmail.com>2025-07-05 00:09:54 +0200
committerDamian Tarnawski <gthetarnav@gmail.com>2025-07-05 00:09:54 +0200
commit2a37eeda1f681c7b0d0eb29b32e43cf3d7f5d374 (patch)
tree7b706b4526a3dae206f87a66a9b2f671cf2f588b /src
parent384aaa75affae6fdceca2811ddd9a0b57d842e2d (diff)
Better handle inlay hints with named params passed not in order
Diffstat (limited to 'src')
-rw-r--r--src/common/position.odin39
-rw-r--r--src/server/inlay_hints.odin189
2 files changed, 114 insertions, 114 deletions
diff --git a/src/common/position.odin b/src/common/position.odin
index 1eecfdc..ca3976a 100644
--- a/src/common/position.odin
+++ b/src/common/position.odin
@@ -3,6 +3,7 @@ package common
import "core:fmt"
import "core:log"
import "core:odin/ast"
+import "core:odin/tokenizer"
import "core:strings"
import "core:unicode/utf8"
@@ -101,31 +102,31 @@ go_backwards_to_endline :: proc(offset: int, document_text: []u8) -> int {
return index + 1
}
-/*
- Get the range of a token in utf16 space
-*/
-get_token_range :: proc(node: ast.Node, document_text: string) -> Range {
- range: Range
-
- pos_offset := min(len(document_text) - 1, node.pos.offset)
- end_offset := min(len(document_text) - 1, node.end.offset)
+token_pos_to_position :: proc(pos: tokenizer.Pos, document_text: string) -> (position: Position) {
+ pos_offset := min(len(document_text) - 1, pos.offset)
offset := go_backwards_to_endline(pos_offset, transmute([]u8)document_text)
-
+
if offset < 0 {
- offset := 0
- log.errorf("Failed to find offset in get_token_range: %v", node)
+ offset = 0
+ log.errorf("Failed to find offset in token_pos_to_position: %v", pos)
}
- range.start.line = node.pos.line - 1
- range.start.character = get_character_offset_u8_to_u16(node.pos.column - 1, transmute([]u8)document_text[offset:])
-
- offset = go_backwards_to_endline(end_offset - 1, transmute([]u8)document_text)
-
- range.end.line = node.end.line - 1
- range.end.character = get_character_offset_u8_to_u16(node.end.column - 1, transmute([]u8)document_text[offset:])
+ return {
+ line = pos.line-1,
+ character = get_character_offset_u8_to_u16(pos.column-1, transmute([]u8)document_text[offset:]),
+ }
+}
- return range
+/*
+ Get the range of a token in utf16 space
+*/
+get_token_range :: proc(node: ast.Node, document_text: string) -> (range: Range) {
+ range.start = token_pos_to_position(node.pos, document_text)
+ end_pos := node.end
+ end_pos.offset -= 1
+ range.end = token_pos_to_position(end_pos, document_text)
+ return
}
get_absolute_range :: proc(range: Range, document_text: []u8) -> (AbsoluteRange, bool) {
diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin
index e4cea54..6dc155d 100644
--- a/src/server/inlay_hints.odin
+++ b/src/server/inlay_hints.odin
@@ -57,124 +57,123 @@ get_inlay_hints :: proc(
loop: for node_call in &data.calls {
- symbol_arg_count := 0
- is_selector_call := false
+
is_ellipsis := false
has_added_default := false
call := node_call.derived.(^ast.Call_Expr)
- if selector, ok := call.expr.derived.(^ast.Selector_Expr); ok && selector.op.kind == .Arrow_Right {
- is_selector_call = true
+ selector, is_selector_call := call.expr.derived.(^ast.Selector_Expr)
+ is_selector_call &&= selector.op.kind == .Arrow_Right
+
+ end_pos := common.token_pos_to_position(call.close, string(document.text))
+
+ symbol_and_node := symbols[cast(uintptr)call.expr] or_continue
+ symbol_call := symbol_and_node.symbol.value.(SymbolProcedureValue) or_continue
+
+ positional_arg_idx := 0
+
+ expr_name :: proc (node: ^ast.Node) -> (name: string, ok: bool) {
+ #partial switch v in node.derived {
+ case ^ast.Ident:
+ return v.name, true
+ case ^ast.Poly_Type:
+ ident := v.type.derived.(^ast.Ident) or_return
+ return ident.name, true
+ case:
+ return
+ }
}
+
+ for arg, arg_type_idx in symbol_call.arg_types {
+ if arg_type_idx == 0 && is_selector_call {
+ continue
+ }
- if symbol_and_node, ok := symbols[cast(uintptr)call.expr]; ok {
- if symbol_call, ok := symbol_and_node.symbol.value.(SymbolProcedureValue); ok {
- for arg, i in symbol_call.arg_types {
- if i == 0 && is_selector_call {
- continue
- }
-
- for name in arg.names {
- label := ""
- is_current_ellipsis := false
-
- if arg.type != nil {
- if ellipsis, ok := arg.type.derived.(^ast.Ellipsis); ok {
- is_current_ellipsis = true
- }
- }
-
- #partial switch v in name.derived {
- case ^ast.Ident:
- label = v.name
- case ^ast.Poly_Type:
- if ident, ok := v.type.derived.(^ast.Ident); ok {
- label = ident.name
- } else {
- continue loop
- }
- case:
- continue loop
- }
+ for name, name_idx in arg.names {
- if is_ellipsis || symbol_arg_count >= len(call.args) {
- if arg.default_value == nil {
- continue loop
- }
+ arg_call_idx := arg_type_idx + name_idx
+ if is_selector_call do arg_call_idx -= 1
- if !config.enable_inlay_hints_default_params {
- continue loop
- }
-
- value := node_to_string(arg.default_value)
+ label := expr_name(name) or_continue loop
- call_range := common.get_token_range(call, string(document.text))
+ is_provided_named, is_provided_positional: bool
+ call_arg: ^ast.Expr
- position: common.Position
- position = call_range.end
- position.character -= 1
+ for a, a_i in call.args[positional_arg_idx:] {
+ call_arg_idx := a_i + positional_arg_idx
+ // provided as named
+ if field_value, ok := a.derived.(^ast.Field_Value); ok {
+ ident := field_value.field.derived.(^ast.Ident) or_break
+ if ident.name == label {
+ is_provided_named = true
+ call_arg = a
+ }
+ break
+ } // provided as positional
+ else if arg_call_idx == call_arg_idx {
+ is_provided_positional = true
+ positional_arg_idx += 1
+ call_arg = a
+ break
+ }
+ }
- needs_leading_comma := i > 0
+ if is_ellipsis || (!is_provided_named && !is_provided_positional) {
+ // This parameter is not provided, so it should use default value
+ if arg.default_value == nil {
+ continue loop
+ }
- if !has_added_default && needs_leading_comma {
- till_end := string(document.text[:call.close.offset])
- #reverse for ch in till_end {
- switch ch {
- case ' ', '\t', '\n':
- continue
- case ',':
- needs_leading_comma = false
- }
- break
- }
- }
+ if !config.enable_inlay_hints_default_params {
+ continue loop
+ }
- hint := InlayHint {
- kind = .Parameter,
- label = fmt.tprintf("%s%v = %v", needs_leading_comma ? ", " : "", label, value),
- position = position,
- }
- append(&hints, hint)
+ value := node_to_string(arg.default_value)
- has_added_default = true
- } else if config.enable_inlay_hints_params {
+ needs_leading_comma := arg_call_idx > 0
- // if is already provided as a named argument
- if _, ok := call.args[symbol_arg_count].derived.(^ast.Field_Value); ok {
- symbol_arg_count += 1
+ if !has_added_default && needs_leading_comma {
+ till_end := string(document.text[:call.close.offset])
+ #reverse for ch in till_end {
+ switch ch {
+ case ' ', '\t', '\n':
continue
+ case ',':
+ needs_leading_comma = false
}
-
- // if the arg name and param name are the same, don't add it.
- same_name: bool
- #partial switch v in call.args[symbol_arg_count].derived_expr {
- case ^ast.Ident:
- same_name = label == v.name
- case ^ast.Poly_Type:
- if ident, ok := v.type.derived.(^ast.Ident); ok {
- same_name = label == ident.name
- }
- }
-
- if !same_name {
- range := common.get_token_range(call.args[symbol_arg_count], string(document.text))
- hint := InlayHint {
- kind = .Parameter,
- label = fmt.tprintf("%v = ", label),
- position = range.start,
- }
- append(&hints, hint)
- }
+ break
}
+ }
- if is_current_ellipsis {
- is_ellipsis = true
+ hint := InlayHint {
+ kind = .Parameter,
+ label = fmt.tprintf("%s%v = %v", needs_leading_comma ? ", " : "", label, value),
+ position = end_pos,
+ }
+ append(&hints, hint)
+
+ has_added_default = true
+ } else if config.enable_inlay_hints_params && is_provided_positional && !is_provided_named {
+ // This parameter is provided via positional argument, show parameter hint
+
+ // if the arg name and param name are the same, don't add it.
+ call_arg_name, _ := expr_name(call_arg)
+ if call_arg_name != label {
+ range := common.get_token_range(call_arg, string(document.text))
+ hint := InlayHint {
+ kind = .Parameter,
+ label = fmt.tprintf("%v = ", label),
+ position = range.start,
}
-
- symbol_arg_count += 1
+ append(&hints, hint)
}
}
+
+ if arg.type != nil {
+ _, is_current_ellipsis := arg.type.derived.(^ast.Ellipsis)
+ is_ellipsis ||= is_current_ellipsis
+ }
}
}
}