mirror of
https://github.com/vlang/v.git
synced 2025-09-13 14:32:26 +03:00
vls: improve and simplify autocomplete; remove the scanner hack
Some checks are pending
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run
Some checks are pending
Graphics CI / gg-regressions (push) Waiting to run
vlib modules CI / build-module-docs (push) Waiting to run
native backend CI / native-backend-ubuntu (push) Waiting to run
native backend CI / native-backend-windows (push) Waiting to run
Shy and PV CI / v-compiles-puzzle-vibes (push) Waiting to run
Sanitized CI / sanitize-undefined-clang (push) Waiting to run
Sanitized CI / sanitize-undefined-gcc (push) Waiting to run
Sanitized CI / tests-sanitize-address-clang (push) Waiting to run
Sanitized CI / sanitize-address-msvc (push) Waiting to run
Sanitized CI / sanitize-address-gcc (push) Waiting to run
Sanitized CI / sanitize-memory-clang (push) Waiting to run
sdl CI / v-compiles-sdl-examples (push) Waiting to run
Time CI / time-linux (push) Waiting to run
Time CI / time-macos (push) Waiting to run
Time CI / time-windows (push) Waiting to run
toml CI / toml-module-pass-external-test-suites (push) Waiting to run
Tools CI / tools-linux (tcc) (push) Waiting to run
Tools CI / tools-linux (clang) (push) Waiting to run
Tools CI / tools-linux (gcc) (push) Waiting to run
Tools CI / tools-macos (clang) (push) Waiting to run
Tools CI / tools-windows (gcc) (push) Waiting to run
Tools CI / tools-windows (msvc) (push) Waiting to run
Tools CI / tools-windows (tcc) (push) Waiting to run
Tools CI / tools-docker-ubuntu-musl (push) Waiting to run
vab CI / vab-compiles-v-examples (push) Waiting to run
vab CI / v-compiles-os-android (push) Waiting to run
wasm backend CI / wasm-backend (ubuntu-22.04) (push) Waiting to run
wasm backend CI / wasm-backend (windows-2022) (push) Waiting to run
This commit is contained in:
parent
963e3e8ae2
commit
9391b7c234
9 changed files with 86 additions and 40 deletions
|
@ -11,19 +11,31 @@ struct ACFieldMethod {
|
||||||
typ string
|
typ string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn abs(a int) int {
|
||||||
|
if a < 0 {
|
||||||
|
return -a
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
fn (mut c Checker) ident_autocomplete(node ast.Ident) {
|
fn (mut c Checker) ident_autocomplete(node ast.Ident) {
|
||||||
// Mini LS hack (v -line-info "a.v:16")
|
// Mini LS hack (v -line-info "a.v:16")
|
||||||
println(
|
if c.pref.is_verbose {
|
||||||
'checker.ident() info.line_nr=${c.pref.linfo.line_nr} node.line_nr=${node.pos.line_nr} ' +
|
println(
|
||||||
' pwd="${os.getwd()}" file="${c.file.path}", ' +
|
'checker.ident_autocomplete() info.line_nr=${c.pref.linfo.line_nr} node.line_nr=${node.pos.line_nr} ' +
|
||||||
' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" expr="${c.pref.linfo.expr}"')
|
' node.col=${node.pos.col} pwd="${os.getwd()}" file="${c.file.path}", ' +
|
||||||
|
//' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" expr="${c.pref.linfo.expr}"')
|
||||||
|
' pref.linfo.path="${c.pref.linfo.path}" node.name="${node.name}" col="${c.pref.linfo.col}"')
|
||||||
|
}
|
||||||
// Make sure this ident is on the same line as requeste, in the same file, and has the same name
|
// Make sure this ident is on the same line as requeste, in the same file, and has the same name
|
||||||
same_line := node.pos.line_nr in [c.pref.linfo.line_nr - 1, c.pref.linfo.line_nr + 1, c.pref.linfo.line_nr]
|
same_line := node.pos.line_nr in [c.pref.linfo.line_nr - 1, c.pref.linfo.line_nr + 1, c.pref.linfo.line_nr]
|
||||||
if !same_line {
|
if !same_line {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
same_name := c.pref.linfo.expr == node.name
|
// same_name := c.pref.linfo.expr == node.name
|
||||||
if !same_name {
|
same_col := abs(c.pref.linfo.col - node.pos.col) < 3
|
||||||
|
// if !same_name {
|
||||||
|
if !same_col {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
abs_path := os.join_path(os.getwd(), c.file.path)
|
abs_path := os.join_path(os.getwd(), c.file.path)
|
||||||
|
@ -39,9 +51,14 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
|
||||||
sym := c.table.sym(c.unwrap_generic(node.obj.typ))
|
sym := c.table.sym(c.unwrap_generic(node.obj.typ))
|
||||||
// sb.writeln('VAR ${node.name}:${sym.name} ${node.pos.line_nr}')
|
// sb.writeln('VAR ${node.name}:${sym.name} ${node.pos.line_nr}')
|
||||||
nt := '${node.name}:${sym.name}'
|
nt := '${node.name}:${sym.name}'
|
||||||
|
sb.writeln('{')
|
||||||
if !c.pref.linfo.vars_printed[nt] { // avoid dups
|
if !c.pref.linfo.vars_printed[nt] { // avoid dups
|
||||||
sb.writeln('===')
|
// sb.writeln('===')
|
||||||
sb.writeln('VAR ${nt}') //${node.name}:${sym.name}')
|
// sb.writeln('VAR ${nt}') //${node.name}:${sym.name}')
|
||||||
|
sb.writeln('\t"name":"${node.name}",')
|
||||||
|
sb.writeln('\t"type":"${sym.name}",')
|
||||||
|
sb.writeln('\t"fields":[')
|
||||||
|
|
||||||
// print_backtrace()
|
// print_backtrace()
|
||||||
/*
|
/*
|
||||||
if sym.kind == .alias {
|
if sym.kind == .alias {
|
||||||
|
@ -75,9 +92,14 @@ fn (mut c Checker) ident_autocomplete(node ast.Ident) {
|
||||||
fields << ACFieldMethod{build_method_summary(method), method_ret_type.name}
|
fields << ACFieldMethod{build_method_summary(method), method_ret_type.name}
|
||||||
}
|
}
|
||||||
fields.sort(a.name < b.name)
|
fields.sort(a.name < b.name)
|
||||||
for field in fields {
|
for i, field in fields {
|
||||||
sb.writeln('${field.name}:${field.typ}')
|
// sb.writeln('${field.name}:${field.typ}')
|
||||||
|
sb.write_string('\t\t"${field.name}:${field.typ}"')
|
||||||
|
if i < fields.len - 1 {
|
||||||
|
sb.writeln(', ')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sb.writeln('\n\t]\n}')
|
||||||
res := sb.str().trim_space()
|
res := sb.str().trim_space()
|
||||||
if res != '' {
|
if res != '' {
|
||||||
println(res)
|
println(res)
|
||||||
|
|
|
@ -430,12 +430,13 @@ pub fn (mut c Checker) check_files(ast_files []&ast.File) {
|
||||||
// After the main checker run, run the line info check, print line info, and exit (if it's present)
|
// After the main checker run, run the line info check, print line info, and exit (if it's present)
|
||||||
if !c.pref.linfo.is_running && c.pref.line_info != '' { //'' && c.pref.linfo.line_nr == 0 {
|
if !c.pref.linfo.is_running && c.pref.line_info != '' { //'' && c.pref.linfo.line_nr == 0 {
|
||||||
// c.do_line_info(c.pref.line_info, ast_files)
|
// c.do_line_info(c.pref.line_info, ast_files)
|
||||||
println('setting is_running=true, pref.path=${c.pref.linfo.path} curdir' + os.getwd())
|
// println('setting is_running=true, pref.path=${c.pref.linfo.path} curdir' + os.getwd())
|
||||||
c.pref.linfo.is_running = true
|
c.pref.linfo.is_running = true
|
||||||
|
// println('linfo path=${c.pref.linfo.path}')
|
||||||
for i, file in ast_files {
|
for i, file in ast_files {
|
||||||
// println(file.path)
|
// println(file.path)
|
||||||
if file.path == c.pref.linfo.path {
|
if file.path == c.pref.linfo.path {
|
||||||
println('running c.check_files')
|
// println('running c.check_files')
|
||||||
c.check_files([ast_files[i]])
|
c.check_files([ast_files[i]])
|
||||||
exit(0)
|
exit(0)
|
||||||
} else if file.path.starts_with('./') {
|
} else if file.path.starts_with('./') {
|
||||||
|
|
|
@ -2635,6 +2635,13 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
if p.disallow_declarations_in_script_mode() {
|
if p.disallow_declarations_in_script_mode() {
|
||||||
return ast.SumTypeDecl{}
|
return ast.SumTypeDecl{}
|
||||||
}
|
}
|
||||||
|
if p.is_vls && p.tok.is_key() {
|
||||||
|
// End parsing after `type ` in vls mode to avoid lots of junk errors
|
||||||
|
// If next token is a key, the type wasn't finished
|
||||||
|
p.error('expecting type name')
|
||||||
|
p.should_abort = true
|
||||||
|
return ast.AliasTypeDecl{}
|
||||||
|
}
|
||||||
mut name := p.check_name()
|
mut name := p.check_name()
|
||||||
mut language := ast.Language.v
|
mut language := ast.Language.v
|
||||||
if name.len == 1 && name[0].is_capital() {
|
if name.len == 1 && name[0].is_capital() {
|
||||||
|
|
|
@ -125,6 +125,16 @@ fn (mut p Parser) struct_decl(is_anon bool) ast.StructDecl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p.check(.lcbr)
|
p.check(.lcbr)
|
||||||
|
// if p.is_vls && p.tok.kind == .key_struct { // p.tok.is_key() {
|
||||||
|
if p.is_vls && p.tok.is_key() {
|
||||||
|
// End parsing after `struct Foo {` in vls mode to avoid lots of junk errors
|
||||||
|
// If next token after { is a key, the struct wasn't finished
|
||||||
|
p.error('expected `}` to finish a struct definition')
|
||||||
|
p.should_abort = true
|
||||||
|
return ast.StructDecl{
|
||||||
|
name: name
|
||||||
|
}
|
||||||
|
}
|
||||||
pre_comments << p.eat_comments()
|
pre_comments << p.eat_comments()
|
||||||
mut i := 0
|
mut i := 0
|
||||||
for p.tok.kind != .rcbr {
|
for p.tok.kind != .rcbr {
|
||||||
|
|
|
@ -4,7 +4,7 @@ module pref
|
||||||
|
|
||||||
fn (mut p Preferences) parse_line_info(line string) {
|
fn (mut p Preferences) parse_line_info(line string) {
|
||||||
// println("parse_line_info '${line}'")
|
// println("parse_line_info '${line}'")
|
||||||
format_err := 'wrong format, use `-line-info "file.v:24:expr_to_look_up"'
|
format_err := 'wrong format, use `-line-info "file.v:24:7"'
|
||||||
vals := line.split(':')
|
vals := line.split(':')
|
||||||
if vals.len != 3 {
|
if vals.len != 3 {
|
||||||
eprintln(format_err)
|
eprintln(format_err)
|
||||||
|
@ -12,7 +12,8 @@ fn (mut p Preferences) parse_line_info(line string) {
|
||||||
}
|
}
|
||||||
file_name := vals[0]
|
file_name := vals[0]
|
||||||
line_nr := vals[1].int() - 1
|
line_nr := vals[1].int() - 1
|
||||||
expr := vals[2]
|
col := vals[2].int() - 1
|
||||||
|
// expr := vals[2]
|
||||||
if !file_name.ends_with('.v') || line_nr == -1 {
|
if !file_name.ends_with('.v') || line_nr == -1 {
|
||||||
eprintln(format_err)
|
eprintln(format_err)
|
||||||
return
|
return
|
||||||
|
@ -20,20 +21,7 @@ fn (mut p Preferences) parse_line_info(line string) {
|
||||||
p.linfo = LineInfo{
|
p.linfo = LineInfo{
|
||||||
line_nr: line_nr
|
line_nr: line_nr
|
||||||
path: file_name
|
path: file_name
|
||||||
expr: expr
|
// expr: expr
|
||||||
|
col: col
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_line_info_expr_to_program_text(raw_text string, linfo LineInfo) string {
|
|
||||||
lines := raw_text.split('\n')
|
|
||||||
lines_before := lines[..linfo.line_nr].join('\n')
|
|
||||||
mut expr := linfo.expr
|
|
||||||
if !expr.contains('.') {
|
|
||||||
// Single variable, `foo` => `foo.xx`
|
|
||||||
// expr += '.xxx'
|
|
||||||
// expr = '_ = ' + expr
|
|
||||||
expr = 'println(' + expr + ')'
|
|
||||||
}
|
|
||||||
lines_after := lines[linfo.line_nr..].join('\n')
|
|
||||||
return lines_before + '\n' + expr + '\n' + lines_after
|
|
||||||
}
|
|
||||||
|
|
|
@ -264,9 +264,10 @@ pub mut:
|
||||||
|
|
||||||
pub struct LineInfo {
|
pub struct LineInfo {
|
||||||
pub mut:
|
pub mut:
|
||||||
line_nr int // a quick single file run when called with v -line-info (contains line nr to inspect)
|
line_nr int // a quick single file run when called with v -line-info (contains line nr to inspect)
|
||||||
path string // same, but stores the path being parsed
|
path string // same, but stores the path being parsed
|
||||||
expr string // "foo" or "foo.bar" V code (expression) which needs autocomplete
|
// expr string // "foo" or "foo.bar" V code (expression) which needs autocomplete
|
||||||
|
col int
|
||||||
is_running bool // so that line info is fetched only on the second checker run
|
is_running bool // so that line info is fetched only on the second checker run
|
||||||
vars_printed map[string]bool // to avoid dups
|
vars_printed map[string]bool // to avoid dups
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,14 +111,7 @@ pub fn new_scanner_file(file_path string, comments_mode CommentsMode, pref_ &pre
|
||||||
if !os.is_file(file_path) {
|
if !os.is_file(file_path) {
|
||||||
return error('${file_path} is not a .v file')
|
return error('${file_path} is not a .v file')
|
||||||
}
|
}
|
||||||
mut raw_text := util.read_file(file_path) or { return err }
|
raw_text := util.read_file(file_path) or { return err }
|
||||||
if pref_.line_info != '' {
|
|
||||||
// Add line info expr to the scanner text
|
|
||||||
abs_path := os.join_path(os.getwd(), file_path)
|
|
||||||
if pref_.linfo.path in [file_path, abs_path] {
|
|
||||||
raw_text = pref.add_line_info_expr_to_program_text(raw_text, pref_.linfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mut s := &Scanner{
|
mut s := &Scanner{
|
||||||
pref: pref_
|
pref: pref_
|
||||||
text: raw_text
|
text: raw_text
|
||||||
|
|
|
@ -390,6 +390,10 @@ pub fn (t Token) is_next_to(pre_token Token) bool {
|
||||||
return t.pos - pre_token.pos == pre_token.len
|
return t.pos - pre_token.pos == pre_token.len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn (t Token) is_key() bool {
|
||||||
|
return int(t.kind) > int(Kind.keyword_beg) && int(t.kind) < int(Kind.keyword_end)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn (t Token) str() string {
|
pub fn (t Token) str() string {
|
||||||
mut s := t.kind.str()
|
mut s := t.kind.str()
|
||||||
if s.len == 0 {
|
if s.len == 0 {
|
||||||
|
|
20
vlib/v/token/token_test.v
Normal file
20
vlib/v/token/token_test.v
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
|
||||||
|
// Use of this source code is governed by an MIT license
|
||||||
|
// that can be found in the LICENSE file.
|
||||||
|
module token
|
||||||
|
|
||||||
|
fn test_is_key() {
|
||||||
|
// Test that tokens with keyword kinds return true.
|
||||||
|
assert Token{
|
||||||
|
kind: .key_as
|
||||||
|
}.is_key()
|
||||||
|
assert Token{
|
||||||
|
kind: .key_fn
|
||||||
|
}.is_key()
|
||||||
|
assert Token{
|
||||||
|
kind: .key_mut
|
||||||
|
}.is_key()
|
||||||
|
assert !Token{
|
||||||
|
kind: .name
|
||||||
|
}.is_key()
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue