Skip to content

Commit da76b20

Browse files
authored
diagnostics: improve compiler path handling and add ProjectResolver (#173)
1 parent 236d51b commit da76b20

File tree

7 files changed

+102
-28
lines changed

7 files changed

+102
-28
lines changed

src/server/diagnostics.v

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ pub fn (mut ls LanguageServer) run_diagnostics_in_bg(uri lsp.DocumentUri) {
1515

1616
pub fn (mut ls LanguageServer) run_diagnostics(uri lsp.DocumentUri) {
1717
watch := time.new_stopwatch(auto_start: true)
18+
project_root := ls.project_resolver.resolve(uri)
1819
ls.reporter.clear(uri)
19-
ls.reporter.run_all_inspections(uri)
20+
ls.reporter.run_all_inspections(uri, project_root)
2021
ls.reporter.publish(mut ls.writer, uri)
2122

2223
loglib.with_fields({
@@ -31,11 +32,11 @@ mut:
3132
reports map[lsp.DocumentUri][]inspections.Report
3233
}
3334

34-
fn (mut d DiagnosticReporter) run_all_inspections(uri lsp.DocumentUri) {
35+
fn (mut d DiagnosticReporter) run_all_inspections(uri lsp.DocumentUri, project_root string) {
3536
mut source := compiler.CompilerReportsSource{
3637
compiler_path: d.compiler_path
3738
}
38-
d.reports[uri] = source.process(uri)
39+
d.reports[uri] = source.process(uri, project_root)
3940
}
4041

4142
fn (mut d DiagnosticReporter) clear(uri lsp.DocumentUri) {

src/server/features_did_change_watched_files.v

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ module server
22

33
import lsp
44
import loglib
5+
import os
56

67
pub fn (mut ls LanguageServer) did_change_watched_files(params lsp.DidChangeWatchedFilesParams) {
78
changes := params.changes
89
mut is_rename := false
10+
mut structure_changed := false
911

1012
// NOTE:
1113
// 1. Renaming a file returns two events: one "created" event for the
@@ -17,6 +19,12 @@ pub fn (mut ls LanguageServer) did_change_watched_files(params lsp.DidChangeWatc
1719
// but with no "deleted" event prior to it.
1820
for i, change in changes {
1921
change_uri := change.uri.normalize()
22+
23+
filename := os.file_name(change_uri.path())
24+
if filename == 'v.mod' || filename == '.git' {
25+
structure_changed = true
26+
}
27+
2028
match change.typ {
2129
.created {
2230
if next_change := changes[i + 1] {
@@ -75,4 +83,13 @@ pub fn (mut ls LanguageServer) did_change_watched_files(params lsp.DidChangeWatc
7583

7684
ls.client.log_message(change.str(), .info)
7785
}
86+
87+
if structure_changed {
88+
loglib.info('Project structure changed, clearing project root cache')
89+
ls.project_resolver.clear()
90+
91+
for uri, _ in ls.opened_files {
92+
ls.run_diagnostics_in_bg(uri)
93+
}
94+
}
7895
}

src/server/general.v

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import server.protocol
1313
import server.semantic
1414
import server.progress
1515
import server.intentions
16+
import server.workspace
1617

1718
// initialize sends the server capabilities to the client
1819
pub fn (mut ls LanguageServer) initialize(params lsp.InitializeParams, mut wr ResponseWriter) lsp.InitializeResult {
@@ -23,6 +24,7 @@ pub fn (mut ls LanguageServer) initialize(params lsp.InitializeParams, mut wr Re
2324

2425
ls.root_uri = params.root_uri
2526
ls.status = .initialized
27+
ls.project_resolver = workspace.ProjectResolver.new(ls.root_uri.path())
2628

2729
ls.progress.support_work_done_progress = params.capabilities.window.work_done_progress
2830
options := params.initialization_options

src/server/inspections/compiler/CompilerReportsSource.v

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub:
88
compiler_path string
99
}
1010

11-
pub fn (mut c CompilerReportsSource) process(uri lsp.DocumentUri) []inspections.Report {
12-
reports := exec_compiler_diagnostics(c.compiler_path, uri) or { return [] }
11+
pub fn (mut c CompilerReportsSource) process(uri lsp.DocumentUri, project_root string) []inspections.Report {
12+
reports := exec_compiler_diagnostics(c.compiler_path, uri, project_root) or { return [] }
1313
return reports
1414
}

src/server/inspections/compiler/utils.v

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,12 @@ fn parse_compiler_diagnostic(msg string) ?inspections.Report {
5757
}
5858
}
5959

60-
fn exec_compiler_diagnostics(compiler_path string, uri lsp.DocumentUri) ?[]inspections.Report {
61-
dir_path := uri.dir_path()
60+
fn exec_compiler_diagnostics(compiler_path string, uri lsp.DocumentUri, project_root string) ?[]inspections.Report {
6261
filepath := uri.path()
63-
is_module := !filepath.ends_with('.vv')
64-
input_path := if is_module { dir_path } else { filepath }
62+
is_script := filepath.ends_with('.vsh') || filepath.ends_with('.vv')
6563

66-
res := os.execute('${compiler_path} -enable-globals -shared -check ${input_path}')
64+
check_target := if is_script { filepath } else { project_root }
65+
res := os.execute('${compiler_path} -enable-globals -shared -check ${check_target}')
6766

6867
if res.exit_code == 0 {
6968
return none
@@ -72,6 +71,7 @@ fn exec_compiler_diagnostics(compiler_path string, uri lsp.DocumentUri) ?[]inspe
7271
output_lines := res.output.split_into_lines().map(term.strip_ansi(it))
7372
errors := split_lines_to_errors(output_lines)
7473

74+
current_file_abs := os.real_path(filepath)
7575
mut reports := []inspections.Report{}
7676

7777
for error in errors {
@@ -82,29 +82,14 @@ fn exec_compiler_diagnostics(compiler_path string, uri lsp.DocumentUri) ?[]inspe
8282
continue
8383
}
8484

85-
file_dir_path := os.dir(report.filepath)
86-
87-
report_filepath := if os.is_abs_path(file_dir_path) {
88-
// do nothing
89-
report.filepath
90-
} else if file_dir_path == '..' {
91-
os.join_path_single(dir_path, report.filepath)
92-
} else if start_idx := dir_path.last_index(file_dir_path) {
93-
// reported file appears to be in a subdirectory of dir_path
94-
dir_path[..start_idx] + report.filepath
95-
} else {
96-
// reported file appears to be in a parent directory of dir_path
97-
os.join_path_single(dir_path, report.filepath)
98-
}
99-
100-
// ignore errors in other files
101-
if report_filepath != uri.path() {
85+
report_file_abs := os.real_path(report.filepath)
86+
if os.to_slash(report_file_abs) != os.to_slash(current_file_abs) {
10287
continue
10388
}
10489

10590
reports << inspections.Report{
10691
...report
107-
filepath: report_filepath
92+
filepath: filepath
10893
}
10994
}
11095
return reports

src/server/language_server.v

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import loglib
1111
import server.progress
1212
import server.protocol
1313
import server.intentions
14+
import server.workspace
1415

1516
pub enum ServerStatus {
1617
off
@@ -77,6 +78,8 @@ pub mut:
7778
progress &progress.Tracker = unsafe { nil }
7879
// indexing_mng is used to manage indexing.
7980
indexing_mng analyzer.IndexingManager
81+
// project_resolver is used to resolve the project root for a given file.
82+
project_resolver &workspace.ProjectResolver = unsafe { nil }
8083
}
8184

8285
pub fn LanguageServer.new(indexing analyzer.IndexingManager) &LanguageServer {
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
module workspace
2+
3+
import os
4+
import lsp
5+
6+
pub struct ProjectResolver {
7+
workspace_root string
8+
mut:
9+
cache shared map[string]string
10+
}
11+
12+
pub fn ProjectResolver.new(workspace_root string) &ProjectResolver {
13+
return &ProjectResolver{
14+
workspace_root: os.real_path(workspace_root)
15+
cache: map[string]string{}
16+
}
17+
}
18+
19+
pub fn (mut p ProjectResolver) resolve(uri lsp.DocumentUri) string {
20+
filepath := os.real_path(uri.path())
21+
dir := os.dir(filepath)
22+
23+
rlock p.cache {
24+
if cached := p.cache[dir] {
25+
return cached
26+
}
27+
}
28+
29+
root := p.find_root(dir)
30+
31+
lock p.cache {
32+
p.cache[dir] = root
33+
}
34+
35+
return root
36+
}
37+
38+
pub fn (mut p ProjectResolver) clear() {
39+
lock p.cache {
40+
p.cache.clear()
41+
}
42+
}
43+
44+
fn (p &ProjectResolver) find_root(start_dir string) string {
45+
mut curr := start_dir
46+
home_dir := os.home_dir()
47+
48+
for {
49+
if os.exists(os.join_path(curr, 'v.mod')) || os.is_dir(os.join_path(curr, '.git'))
50+
|| curr == p.workspace_root {
51+
return curr
52+
}
53+
54+
parent := os.dir(curr)
55+
if curr == home_dir || parent == curr {
56+
break
57+
}
58+
curr = parent
59+
}
60+
61+
return if start_dir.starts_with(p.workspace_root) {
62+
p.workspace_root
63+
} else {
64+
start_dir
65+
}
66+
}

0 commit comments

Comments
 (0)