@@ -5,6 +5,7 @@ module checker
55import strings
66import v.ast
77import os
8+ import token
89
910enum DetailKind {
1011 text = 1
@@ -43,77 +44,130 @@ struct Detail {
4344 insert_text_format ? int // 1 for PlainText, 2 for Snippet
4445}
4546
47+ fn (mut c Checker) get_fn_from_call_expr (node ast.CallExpr) ! ast.Fn {
48+ fn_name := node.name
49+ return if node.is_method {
50+ left_sym := c.table.sym (c.unwrap_generic (node.left_type))
51+ c.table.find_method (left_sym, fn_name) or {
52+ return error ('failed to find method "${fn_name} "' )
53+ }
54+ } else {
55+ c.table.find_fn (fn_name) or { return error ('failed to find fn "${fn_name} "' ) }
56+ }
57+ }
58+
4659// Autocomplete for function parameters `os.write_bytes(**path string, bytes []u8***)` etc
4760pub fn (mut c Checker) autocomplete_for_fn_call_expr (node ast.CallExpr) {
48- // Make sure this ident is on the same line and same file as request
49- same_line := c.pref.linfo.line_nr + 1 == node.pos.line_nr
50- if ! same_line {
51- return
52- }
53- if node.pos.file_idx < 0 {
61+ if c.pref.linfo.method != .signature_help {
5462 return
5563 }
56- if c.pref.linfo.path != c.table.filelist[ node.pos.file_idx] {
64+ if ! c. vls_is_the_node ( node.name_pos) {
5765 return
5866 }
59- col := c.pref.linfo.expr.all_after_last ('^' ).int ()
60- if node.name_pos.col + node.name_pos.len + 1 != col {
61- return
62- }
63- fn_name := node.name
64- f := if node.is_method {
65- left_sym := c.table.sym (c.unwrap_generic (node.left_type))
66- c.table.find_method (left_sym, fn_name) or {
67- println ('failed to find method "${fn_name} "' )
68- return
69- }
70- } else {
71- c.table.find_fn (fn_name) or {
72- println ('failed to find fn "${fn_name} "' )
73- return
74- }
67+ f := c.get_fn_from_call_expr (node) or {
68+ println (err)
69+ exit (1 )
7570 }
7671 res := c.build_fn_summary (f)
7772 println (res)
7873 exit (0 )
7974}
8075
81- fn (mut c Checker) ident_gotodef () {
82- mut ident_name := c.pref.linfo.expr.after ('gd^' ).trim_space ()
83- mod_name := ident_name.all_before_last ('.' )
84- resolved_mod_name := c.try_resolve_to_import_mod_name (mod_name)
85- if resolved_mod_name.len > 0 {
86- ident_name = resolved_mod_name + '.' + ident_name.all_after_last ('.' )
87- }
88- if f := c.table.find_fn (ident_name) {
89- println ('${f.file} :${f.pos.line_nr} :${f.pos.col} ' )
76+ fn (mut c Checker) ident_gotodef (node_ ast.Expr) {
77+ if c.pref.linfo.method != .definition {
78+ return
79+ }
80+ if ! c.vls_is_the_node (node_.pos ()) {
9081 return
9182 }
83+ mut node := unsafe { node_ }
84+ mut pos := token.Pos{}
85+ match mut node {
86+ ast.CallExpr {
87+ if ! c.vls_is_the_node (node.name_pos) {
88+ return
89+ }
90+ f := c.get_fn_from_call_expr (node) or {
91+ println (err)
92+ exit (1 )
93+ }
94+ pos = f.name_pos
95+ }
96+ ast.Ident {
97+ // global objects
98+ for _, obj in c.table.global_scope.objects {
99+ if obj is ast.ConstField && obj.name == node.name {
100+ pos = obj.pos
101+ break
102+ } else if obj is ast.GlobalField && obj.name == node.name {
103+ pos = obj.pos
104+ break
105+ } else if obj is ast.Var && obj.name == node.name {
106+ pos = obj.pos
107+ break
108+ }
109+ }
110+ // local objects
111+ if pos == token.Pos{} && ! isnil (c.fn_scope) {
112+ if obj := c.fn_scope.find_var (node.name) {
113+ pos = obj.pos
114+ }
115+ }
116+ //
117+ }
118+ ast.StructInit {
119+ if ! c.vls_is_the_node (node.name_pos) {
120+ return
121+ }
122+ mut info := c.table.sym (node.typ).info
123+ pos = match mut info {
124+ ast.Struct {
125+ info.name_pos
126+ }
127+ ast.Alias {
128+ info.name_pos
129+ }
130+ ast.SumType {
131+ info.name_pos
132+ }
133+ else {
134+ pos
135+ }
136+ }
137+ }
138+ ast.SelectorExpr {
139+ sym := c.table.sym (node.expr_type)
140+ f := c.table.find_field (sym, node.field_name) or {
141+ println ('failed to find field "${node.field_name} "' )
142+ exit (1 )
143+ }
144+ pos = f.pos
145+ }
146+ else {}
147+ }
148+ if pos.file_idx != - 1 {
149+ println ('${c.table.filelist[pos.file_idx]} :${pos.line_nr + 1} :${pos.col} ' )
150+ }
151+ exit (0 )
92152}
93153
94154// Autocomplete for `myvar. ...`, `os. ...`
95155fn (mut c Checker) ident_autocomplete (node ast.Ident) {
156+ if c.pref.linfo.method != .completion {
157+ return
158+ }
96159 // Mini LS hack (v -line-info "a.v:16")
97160 if c.pref.is_verbose {
98161 println (
99162 'checker.ident_autocomplete() info.line_nr=${c.pref.linfo.line_nr} node.line_nr=${node.pos.line_nr} ' +
100163 ' node.col=${node.pos.col} pwd="${os.getwd()} " file="${c.file.path} ", ' +
101- // ' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" expr="${c.pref.linfo.expr}"')
102- ' pref.linfo.path="${c.pref.linfo.path} " node.name="${node.name} " node.mod="${node.mod} " col="${c.pref.linfo.col} "' )
164+ ' pref.linfo.path="${c.pref.linfo.path} " node.name="${node.name} " node.mod="${node.mod} " col="${c.pref.linfo.col} "' )
103165 }
104166 if node.mod == 'builtin' {
105167 // User can't type in `builtin.func(` at all
106168 return
107169 }
108- // Make sure this ident is on the same line and same file as request
109- same_line := c.pref.linfo.line_nr == node.pos.line_nr
110- if ! same_line {
111- return
112- }
113- if node.pos.file_idx < 0 {
114- return
115- }
116- if c.pref.linfo.path != c.table.filelist[node.pos.file_idx] {
170+ if ! c.vls_is_the_node (node.pos) {
117171 return
118172 }
119173 check_name := if c.pref.linfo.col == node.pos.col {
@@ -142,7 +196,6 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
142196 c.module_autocomplete (mod_name)
143197 exit (0 )
144198 }
145-
146199 if node.kind == .unresolved {
147200 eprintln ('unresolved type, maybe "${node.name} " was not defined. otherwise this is a bug, should never happen; please report' )
148201 exit (1 )
@@ -196,8 +249,7 @@ fn (c &Checker) build_fn_summary(func ast.Fn) string {
196249 sb.writeln ('\t }]' )
197250 sb.writeln ('}],' )
198251 sb.writeln ('"activeSignature":0,' )
199- sb.writeln ('"activeParameter":0,' )
200- sb.writeln ('"_type":"SignatureHelp"' )
252+ sb.writeln ('"activeParameter":0' )
201253 sb.writeln ('}' )
202254 return sb.str ()
203255}
@@ -341,7 +393,7 @@ fn (c &Checker) vls_gen_type_details(mut details []Detail, sym ast.TypeSymbol) {
341393
342394fn (c &Checker) vls_write_details (details []Detail) {
343395 mut sb := strings.new_builder (details.len * 32 )
344- sb.writeln ('{"details" : [' )
396+ sb.writeln ('{"details": [' )
345397 for detail in details {
346398 sb.write_string ('{"kind":${int(detail.kind)} ,' )
347399 sb.write_string ('"label":"${detail.label} ",' )
@@ -386,3 +438,21 @@ fn (c &Checker) vls_map_v_kind_to_lsp_kind(kind ast.Kind) DetailKind {
386438 }
387439 return .text
388440}
441+
442+ fn (c &Checker) vls_is_the_node (pos token.Pos) bool {
443+ // Make sure this ident is on the same line and same file as request
444+ same_line := c.pref.linfo.line_nr == pos.line_nr
445+ if ! same_line {
446+ return false
447+ }
448+ if pos.file_idx < 0 {
449+ return false
450+ }
451+ if c.pref.linfo.path != c.table.filelist[pos.file_idx] {
452+ return false
453+ }
454+ if c.pref.linfo.col > pos.col + pos.len || c.pref.linfo.col < pos.col {
455+ return false
456+ }
457+ return true
458+ }
0 commit comments