Skip to content

Commit a428376

Browse files
Refactor: Move SyncWorkspace from Session into ServerState (#7166)
## Description * Moves `SyncWorkspace` ownership from individual `Session` instances to a single, global instance within `ServerState`. * `SyncWorkspace` is now initialized once when the LSP server starts, creating a single temporary workspace clone. Also removes the `resync` function. This was causing the server and the IDE to fall out of sync with each other. For example, if you have 2 panels open and then save a file in one of the tabs but have unsaved changes in the other tab then those changes would not be reflected in the temp memory folder. This meant everything would be out of sync. We already are syncing everything on each keystroke per file so this fn was not necessary in the first place. This PR is a precursor to #7139 part of #7111 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [ ] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers. --------- Co-authored-by: zees-dev <[email protected]>
1 parent 0e3d949 commit a428376

File tree

23 files changed

+1199
-605
lines changed

23 files changed

+1199
-605
lines changed

sway-core/src/semantic_analysis/namespace/package.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ pub struct Package {
1313
// The contents of the package being compiled.
1414
root_module: Module,
1515
// Program id for the package.
16-
program_id: ProgramId,
16+
pub program_id: ProgramId,
1717
// True if the current package is a contract, false otherwise.
1818
is_contract_package: bool,
1919
// The external dependencies of the current package. Note that an external package is

sway-lsp/benches/lsp_benchmarks/compile.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use codspeed_criterion_compat::{black_box, criterion_group, Criterion};
2+
use forc_pkg::manifest::{GenericManifestFile, ManifestFile};
3+
use lsp_types::Url;
24
use std::sync::Arc;
35
use sway_core::Engines;
46
use sway_lsp::core::session;
@@ -7,13 +9,16 @@ use tokio::runtime::Runtime;
79
const NUM_DID_CHANGE_ITERATIONS: usize = 10;
810

911
fn benchmarks(c: &mut Criterion) {
10-
let (uri, session, _) = Runtime::new()
12+
let (uri, session, state) = Runtime::new()
1113
.unwrap()
1214
.block_on(async { black_box(super::compile_test_project().await) });
1315

16+
let sync = state.sync_workspace.get().unwrap();
1417
let build_plan = session
1518
.build_plan_cache
16-
.get_or_update(&session.sync.manifest_path(), || session::build_plan(&uri))
19+
.get_or_update(&sync.workspace_manifest_path(), || {
20+
session::build_plan(&uri)
21+
})
1722
.unwrap();
1823

1924
let mut lsp_mode = Some(sway_core::LspConfig {
@@ -35,9 +40,12 @@ fn benchmarks(c: &mut Criterion) {
3540
let results =
3641
black_box(session::compile(&build_plan, &engines, None, lsp_mode.as_ref()).unwrap());
3742
let session = Arc::new(session::Session::new());
43+
let member_path = sync.member_path(&uri).unwrap();
44+
3845
b.iter(|| {
3946
let _ = black_box(
4047
session::traverse(
48+
member_path.clone(),
4149
results.clone(),
4250
&engines,
4351
session.clone(),
@@ -59,6 +67,36 @@ fn benchmarks(c: &mut Criterion) {
5967
}
6068
})
6169
});
70+
71+
let examples_workspace_dir = super::sway_workspace_dir().join("examples");
72+
let member_manifests = ManifestFile::from_dir(examples_workspace_dir)
73+
.unwrap()
74+
.member_manifests()
75+
.unwrap();
76+
c.bench_function("open_all_example_workspace_members", |b| {
77+
b.iter(|| {
78+
let engines = Engines::default();
79+
for package_manifest in member_manifests.values() {
80+
let dir = Url::from_file_path(
81+
package_manifest
82+
.path()
83+
.parent()
84+
.unwrap()
85+
.join("src/main.sw"),
86+
)
87+
.unwrap();
88+
let build_plan = session::build_plan(&dir).unwrap();
89+
let _ = black_box(
90+
session::compile(&build_plan, &engines, None, lsp_mode.as_ref()).unwrap(),
91+
);
92+
}
93+
})
94+
});
95+
96+
// Remove the temp dir after the benchmarks are done
97+
Runtime::new()
98+
.unwrap()
99+
.block_on(async { sync.remove_temp_dir() });
62100
}
63101

64102
criterion_group! {

sway-lsp/benches/lsp_benchmarks/mod.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,36 @@ pub mod token_map;
44

55
use lsp_types::Url;
66
use std::{path::PathBuf, sync::Arc};
7-
use sway_lsp::core::{
8-
document::Documents,
9-
session::{self, Session},
7+
use sway_lsp::{
8+
core::session::{self, Session},
9+
server_state::ServerState,
1010
};
1111

12-
pub async fn compile_test_project() -> (Url, Arc<Session>, Documents) {
12+
pub async fn compile_test_project() -> (Url, Arc<Session>, ServerState) {
13+
// Load the test project
14+
let uri = Url::from_file_path(benchmark_dir().join("src/main.sw")).unwrap();
15+
let state = ServerState::default();
1316
let session = Arc::new(Session::new());
14-
let documents = Documents::new();
17+
let sync = state.get_or_init_global_sync_workspace(&uri).await.unwrap();
18+
let temp_uri = sync.workspace_to_temp_url(&uri).unwrap();
19+
1520
let lsp_mode = Some(sway_core::LspConfig {
1621
optimized_build: false,
1722
file_versions: Default::default(),
1823
});
19-
// Load the test project
20-
let uri = Url::from_file_path(benchmark_dir().join("src/main.sw")).unwrap();
21-
documents.handle_open_file(&uri).await;
24+
25+
state.documents.handle_open_file(&temp_uri).await;
2226
// Compile the project
2327
session::parse_project(
24-
&uri,
28+
&temp_uri,
2529
&session.engines.read(),
2630
None,
2731
lsp_mode,
2832
session.clone(),
33+
&sync,
2934
)
3035
.unwrap();
31-
(uri, session, documents)
36+
(temp_uri, session, state)
3237
}
3338

3439
pub fn sway_workspace_dir() -> PathBuf {

sway-lsp/benches/lsp_benchmarks/requests.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use sway_lsp::{
99
use tokio::runtime::Runtime;
1010

1111
fn benchmarks(c: &mut Criterion) {
12-
let (uri, session, documents) = Runtime::new()
12+
let (uri, session, state) = Runtime::new()
1313
.unwrap()
1414
.block_on(async { black_box(super::compile_test_project().await) });
15+
let sync = state.sync_workspace.get().unwrap();
1516
let config = sway_lsp::config::Config::default();
1617
let keyword_docs = KeywordDocs::new();
1718
let position = Position::new(1717, 24);
@@ -46,6 +47,7 @@ fn benchmarks(c: &mut Criterion) {
4647
&uri,
4748
position,
4849
LspClient::default(),
50+
sync,
4951
)
5052
})
5153
});
@@ -55,11 +57,11 @@ fn benchmarks(c: &mut Criterion) {
5557
});
5658

5759
c.bench_function("find_all_references", |b| {
58-
b.iter(|| session.token_references(&uri, position))
60+
b.iter(|| session.token_references(&uri, position, sync))
5961
});
6062

6163
c.bench_function("goto_definition", |b| {
62-
b.iter(|| session.token_definition_response(&uri, position))
64+
b.iter(|| session.token_definition_response(&uri, position, sync))
6365
});
6466

6567
c.bench_function("inlay_hints", |b| {
@@ -74,7 +76,7 @@ fn benchmarks(c: &mut Criterion) {
7476
});
7577

7678
c.bench_function("prepare_rename", |b| {
77-
b.iter(|| capabilities::rename::prepare_rename(session.clone(), &uri, position))
79+
b.iter(|| capabilities::rename::prepare_rename(session.clone(), &uri, position, sync))
7880
});
7981

8082
c.bench_function("rename", |b| {
@@ -84,6 +86,7 @@ fn benchmarks(c: &mut Criterion) {
8486
"new_token_name".to_string(),
8587
&uri,
8688
position,
89+
sync,
8790
)
8891
})
8992
});
@@ -108,12 +111,19 @@ fn benchmarks(c: &mut Criterion) {
108111
text: "\n".to_string(),
109112
}],
110113
};
111-
b.iter(|| capabilities::on_enter::on_enter(&config.on_enter, &documents, &uri, &params))
114+
b.iter(|| {
115+
capabilities::on_enter::on_enter(&config.on_enter, &state.documents, &uri, &params)
116+
})
112117
});
113118

114119
c.bench_function("format", |b| {
115-
b.iter(|| capabilities::formatting::format_text(&documents, &uri))
120+
b.iter(|| capabilities::formatting::format_text(&state.documents, &uri))
116121
});
122+
123+
// Remove the temp dir after the benchmarks are done
124+
Runtime::new()
125+
.unwrap()
126+
.block_on(async { sync.remove_temp_dir() });
117127
}
118128

119129
criterion_group! {

sway-lsp/benches/lsp_benchmarks/token_map.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use lsp_types::Position;
33
use tokio::runtime::Runtime;
44

55
fn benchmarks(c: &mut Criterion) {
6-
let (uri, session, _) = Runtime::new()
6+
let (uri, session, state) = Runtime::new()
77
.unwrap()
88
.block_on(async { black_box(super::compile_test_project().await) });
9+
let sync = state.sync_workspace.get().unwrap();
910
let engines = session.engines.read();
1011
let position = Position::new(1716, 24);
1112

@@ -42,6 +43,11 @@ fn benchmarks(c: &mut Criterion) {
4243
.parent_decl_at_position(&engines, &uri, position)
4344
})
4445
});
46+
47+
// Remove the temp dir after the benchmarks are done
48+
Runtime::new()
49+
.unwrap()
50+
.block_on(async { sync.remove_temp_dir() });
4551
}
4652

4753
criterion_group! {

sway-lsp/src/capabilities/hover/hover_link_contents.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
core::{session::Session, token::get_range_from_span},
2+
core::{session::Session, sync::SyncWorkspace, token::get_range_from_span},
33
utils::document::get_url_from_span,
44
};
55
use std::sync::Arc;
@@ -30,15 +30,17 @@ pub struct HoverLinkContents<'a> {
3030
pub implementations: Vec<Span>,
3131
session: Arc<Session>,
3232
engines: &'a Engines,
33+
sync: &'a SyncWorkspace,
3334
}
3435

3536
impl<'a> HoverLinkContents<'a> {
36-
pub fn new(session: Arc<Session>, engines: &'a Engines) -> Self {
37+
pub fn new(session: Arc<Session>, engines: &'a Engines, sync: &'a SyncWorkspace) -> Self {
3738
Self {
3839
related_types: Vec::new(),
3940
implementations: Vec::new(),
4041
session,
4142
engines,
43+
sync,
4244
}
4345
}
4446

@@ -77,7 +79,7 @@ impl<'a> HoverLinkContents<'a> {
7779
/// Adds a single type to the list of related types.
7880
fn add_related_type(&mut self, name: String, span: &Span, callpath: CallPath) {
7981
if let Ok(mut uri) = get_url_from_span(self.engines.se(), span) {
80-
let converted_url = self.session.sync.temp_to_workspace_url(&uri);
82+
let converted_url = self.sync.temp_to_workspace_url(&uri);
8183
if let Ok(url) = converted_url {
8284
uri = url;
8385
}
@@ -133,10 +135,7 @@ impl<'a> HoverLinkContents<'a> {
133135
all_spans.append(&mut impl_spans);
134136
all_spans.dedup();
135137
for span in &all_spans {
136-
let span_result = self
137-
.session
138-
.sync
139-
.temp_to_workspace_span(self.engines.se(), span);
138+
let span_result = self.sync.temp_to_workspace_span(self.engines.se(), span);
140139
if let Ok(span) = span_result {
141140
self.implementations.push(span);
142141
}

sway-lsp/src/capabilities/hover/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub(crate) mod hover_link_contents;
22

33
use self::hover_link_contents::HoverLinkContents;
44
use crate::config::LspClient;
5+
use crate::core::sync::SyncWorkspace;
56
use crate::{
67
core::{
78
session::Session,
@@ -26,6 +27,7 @@ pub fn hover_data(
2627
url: &Url,
2728
position: Position,
2829
client_config: LspClient,
30+
sync: &SyncWorkspace,
2931
) -> Option<lsp_types::Hover> {
3032
let t = session.token_map().token_at_position(url, position)?;
3133
let (ident, token) = t.pair();
@@ -61,6 +63,7 @@ pub fn hover_data(
6163
decl_token,
6264
&decl_ident.name,
6365
client_config.clone(),
66+
sync,
6467
)
6568
}
6669
// The `TypeInfo` of the token does not contain an `Ident`. In this case,
@@ -71,6 +74,7 @@ pub fn hover_data(
7174
token,
7275
&ident.name,
7376
client_config.clone(),
77+
sync,
7478
),
7579
};
7680

@@ -131,6 +135,7 @@ fn hover_format(
131135
token: &Token,
132136
ident_name: &str,
133137
client_config: LspClient,
138+
sync: &SyncWorkspace,
134139
) -> lsp_types::HoverContents {
135140
let decl_engine = engines.de();
136141
let doc_comment = format_doc_attributes(engines, token);
@@ -141,7 +146,7 @@ fn hover_format(
141146
};
142147

143148
// Used to collect all the information we need to generate links for the hover component.
144-
let mut hover_link_contents = HoverLinkContents::new(session, engines);
149+
let mut hover_link_contents = HoverLinkContents::new(session, engines, sync);
145150

146151
let sway_block = token
147152
.as_typed()

sway-lsp/src/capabilities/rename.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::{
22
core::{
33
session::Session,
4+
sync::SyncWorkspace,
45
token::{SymbolKind, Token, TokenIdent, TypedAstToken},
56
token_map::TokenMapExt,
67
},
@@ -19,6 +20,7 @@ pub fn rename(
1920
new_name: String,
2021
url: &Url,
2122
position: Position,
23+
sync: &SyncWorkspace,
2224
) -> Result<WorkspaceEdit, LanguageServerError> {
2325
let _p = tracing::trace_span!("rename").entered();
2426
// Make sure the new name is not a keyword or a literal int type
@@ -76,7 +78,7 @@ pub fn rename(
7678
}
7779
if let Some(path) = &ident.path {
7880
let url = get_url_from_path(path).ok()?;
79-
if let Some(url) = session.sync.to_workspace_url(url) {
81+
if let Some(url) = sync.to_workspace_url(url) {
8082
let edit = TextEdit::new(range, new_name.clone());
8183
return Some((url, vec![edit]));
8284
};
@@ -102,6 +104,7 @@ pub fn prepare_rename(
102104
session: Arc<Session>,
103105
url: &Url,
104106
position: Position,
107+
sync: &SyncWorkspace,
105108
) -> Result<PrepareRenameResponse, LanguageServerError> {
106109
let t = session
107110
.token_map()
@@ -111,7 +114,7 @@ pub fn prepare_rename(
111114

112115
// Only let through tokens that are in the users workspace.
113116
// tokens that are external to the users workspace cannot be renamed.
114-
let _ = is_token_in_workspace(&session, &session.engines.read(), token)?;
117+
let _ = is_token_in_workspace(&session.engines.read(), token, sync)?;
115118

116119
// Make sure we don't allow renaming of tokens that
117120
// are keywords or intrinsics.
@@ -147,16 +150,16 @@ fn formatted_name(ident: &TokenIdent) -> String {
147150

148151
/// Checks if the token is in the users workspace.
149152
fn is_token_in_workspace(
150-
session: &Arc<Session>,
151153
engines: &Engines,
152154
token: &Token,
155+
sync: &SyncWorkspace,
153156
) -> Result<bool, LanguageServerError> {
154157
let decl_ident = token
155158
.declared_token_ident(engines)
156159
.ok_or(RenameError::TokenNotFound)?;
157160

158161
// Check the span of the tokens definitions to determine if it's in the users workspace.
159-
let temp_path = &session.sync.temp_dir()?;
162+
let temp_path = &sync.temp_dir()?;
160163
if let Some(path) = &decl_ident.path {
161164
if !path.starts_with(temp_path) {
162165
return Err(LanguageServerError::RenameError(

0 commit comments

Comments
 (0)