Skip to content

Commit db66120

Browse files
committed
vls: autocomplete for module functions: e.g. os. ...
1 parent 71d32ea commit db66120

3 files changed

Lines changed: 72 additions & 6 deletions

File tree

‎vlib/v/checker/autocomplete.v‎

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,39 @@ fn abs(a int) int {
1818
return a
1919
}
2020

21+
pub fn (mut c Checker) run_ac(ast_file &ast.File) {
22+
}
23+
2124
fn (mut c Checker) ident_autocomplete(node ast.Ident) {
2225
// Mini LS hack (v -line-info "a.v:16")
2326
if c.pref.is_verbose {
2427
println(
2528
'checker.ident_autocomplete() info.line_nr=${c.pref.linfo.line_nr} node.line_nr=${node.pos.line_nr} ' +
2629
' node.col=${node.pos.col} pwd="${os.getwd()}" file="${c.file.path}", ' +
2730
//' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" expr="${c.pref.linfo.expr}"')
28-
' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" col="${c.pref.linfo.col}"')
31+
' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" node.mod="${node.mod}" col="${c.pref.linfo.col}"')
2932
}
3033
// Make sure this ident is on the same line as requeste, in the same file, and has the same name
3134
same_line := node.pos.line_nr in [c.pref.linfo.line_nr - 1, c.pref.linfo.line_nr + 1, c.pref.linfo.line_nr]
3235
if !same_line {
3336
return
3437
}
35-
// same_name := c.pref.linfo.expr == node.name
3638
same_col := abs(c.pref.linfo.col - node.pos.col) < 3
37-
// if !same_name {
3839
if !same_col {
3940
return
4041
}
4142
abs_path := os.join_path(os.getwd(), c.file.path)
4243
if c.pref.linfo.path !in [c.file.path, abs_path] {
4344
return
4445
}
46+
// Module autocomplete
47+
// `os. ...`
48+
if node.name == '' && node.mod != 'builtin' {
49+
c.module_autocomplete(node)
50+
return
51+
} else if node.name == '' && node.mod == 'builtin' {
52+
return
53+
}
4554
mut sb := strings.new_builder(10)
4655
if node.kind == .unresolved {
4756
// println(node)
@@ -67,6 +76,7 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
6776
*/
6877

6978
mut fields := []ACFieldMethod{cap: 10}
79+
mut methods := []ACFieldMethod{cap: 10}
7080
if sym.kind == .struct {
7181
// Add fields, but only if it's a struct.
7282
struct_info := sym.info as ast.Struct
@@ -85,11 +95,13 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
8595
fields << ACFieldMethod{'cap', 'int'}
8696
}
8797
// array_info := sym.info as ast.Array
98+
} else if sym.kind == .string {
99+
fields << ACFieldMethod{'len', 'int'}
88100
}
89101
// Aliases and other types can have methods, add them
90102
for method in sym.methods {
91103
method_ret_type := c.table.sym(method.return_type)
92-
fields << ACFieldMethod{build_method_summary(method), method_ret_type.name}
104+
methods << ACFieldMethod{build_method_summary(method), method_ret_type.name}
93105
}
94106
fields.sort(a.name < b.name)
95107
for i, field in fields {
@@ -99,6 +111,14 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
99111
sb.writeln(', ')
100112
}
101113
}
114+
sb.writeln('\n\t], "methods":[')
115+
116+
for i, method in methods {
117+
sb.write_string('\t\t"${method.name}:${method.typ}"')
118+
if i < methods.len - 1 {
119+
sb.writeln(', ')
120+
}
121+
}
102122
sb.writeln('\n\t]\n}')
103123
res := sb.str().trim_space()
104124
if res != '' {
@@ -108,12 +128,39 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
108128
}
109129
}
110130

131+
fn (mut c Checker) module_autocomplete(node ast.Ident) {
132+
mut sb := strings.new_builder(10)
133+
// println(c.table.fns)
134+
sb.writeln('{"methods":[')
135+
prefix := node.mod + '.'
136+
mut empty := true
137+
for _, f in c.table.fns {
138+
mut name := f.name
139+
if name.starts_with(prefix) {
140+
empty = false
141+
if name.contains('__static__') {
142+
name = name.replace('__static__', '.')
143+
}
144+
name = name.after('.') // The user already typed `mod.`, so suggest the name without module
145+
sb.writeln('"${name}:int" ,')
146+
}
147+
}
148+
if !empty {
149+
sb.go_back(2) // remove final ,
150+
}
151+
sb.writeln(']}')
152+
println(sb.str().trim_space())
153+
}
154+
111155
fn build_method_summary(method ast.Fn) string {
112156
mut s := method.name + '('
113157
for i, param in method.params {
158+
if i == 0 {
159+
continue
160+
}
114161
s += param.name
115162
if i < method.params.len - 1 {
116-
s += ','
163+
s += ', '
117164
}
118165
}
119166
return s + ')'

‎vlib/v/checker/checker.v‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) {
444444
abs_path := os.join_path(os.getwd(), file.path).replace('/./', '/') // TODO: join_path shouldn't have /./
445445
if abs_path == c.pref.linfo.path {
446446
c.check_files([ast_files[i]])
447+
c.run_ac(ast_files[i])
447448
exit(0)
448449
}
449450
}
@@ -4054,7 +4055,8 @@ fn (mut c Checker) resolve_var_fn(func &ast.Fn, mut node ast.Ident, name string)
40544055

40554056
fn (mut c Checker) ident(mut node ast.Ident) ast.Type {
40564057
if c.pref.linfo.is_running {
4057-
// Mini LS hack (v -line-info "a.v:16")
4058+
// LS hack (v -line-info "a.v:16")
4059+
// TODO perf $if
40584060
c.ident_autocomplete(node)
40594061
}
40604062
// TODO: move this

‎vlib/v/parser/parser.v‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,8 +1490,25 @@ fn (mut p Parser) name_expr() ast.Expr {
14901490
// prepend the full import
14911491
mod = p.imports[p.tok.lit]
14921492
}
1493+
if p.pref.linfo.is_running {
1494+
// VLS autocomplete for module fns: `os...`
1495+
// TODO perf $if
1496+
// p.module_autocomplete(node)
1497+
}
1498+
line_nr := p.tok.line_nr
14931499
p.next()
14941500
p.check(.dot)
1501+
if p.is_vls && p.tok.line_nr != line_nr {
1502+
// The user typed `os.`, we have to display all possible `os` functions.
1503+
// Turn this name expression into an Ident, since that is what expected
1504+
// by `Checker.ident_autocomplete()`
1505+
return ast.Ident{
1506+
name: ''
1507+
mod: mod
1508+
pos: p.prev_tok.pos()
1509+
}
1510+
}
1511+
14951512
p.expr_mod = mod
14961513
}
14971514
lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 {

0 commit comments

Comments
 (0)