Skip to content

Commit aee35f1

Browse files
authored
Merge pull request #98 from dfinance/remove-event-handling
"Remove event" handling
2 parents f9fcabe + 2223059 commit aee35f1

File tree

6 files changed

+130
-35
lines changed

6 files changed

+130
-35
lines changed

crates/dialects/src/base.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ pub trait Dialect {
125125
file: MoveFile,
126126
deps: &[MoveFile],
127127
sender: ProvidedAccountAddress,
128-
) -> Result<(CompiledScript, Vec<CompiledModule>), ExecCompilerError> {
128+
) -> Result<(Option<CompiledScript>, Vec<CompiledModule>), ExecCompilerError> {
129129
let (mut script_defs, modules_defs, project_offsets_map) =
130130
self.parse_files(file, deps, &sender)?;
131131
script_defs.extend(modules_defs);
@@ -149,6 +149,8 @@ pub trait Dialect {
149149

150150
let (compiled_script, compiled_modules) =
151151
self.check_and_generate_bytecode(script, deps, sender.clone())?;
152+
let compiled_script =
153+
compiled_script.expect("compile_and_run should always be called with the script");
152154

153155
let network_state = prepare_fake_network_state(compiled_modules, genesis_write_set);
154156

crates/dialects/src/lang/executor.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,18 @@ pub fn vm_status_into_exec_status(vm_status: VMStatus) -> ExecutionError {
2525

2626
pub fn generate_bytecode(
2727
program: PreBytecodeProgram,
28-
) -> Result<(CompiledScript, Vec<CompiledModule>), Vec<Error>> {
29-
let mut units = to_bytecode::translate::program(program)?;
30-
let script = match units.remove(units.len() - 1) {
31-
CompiledUnit::Script { script, .. } => script,
32-
CompiledUnit::Module { .. } => unreachable!(),
33-
};
34-
let modules = units
35-
.into_iter()
36-
.map(|unit| match unit {
37-
CompiledUnit::Module { module, .. } => module,
38-
CompiledUnit::Script { .. } => unreachable!(),
39-
})
40-
.collect();
41-
Ok((script, modules))
28+
) -> Result<(Option<CompiledScript>, Vec<CompiledModule>), Vec<Error>> {
29+
let units = to_bytecode::translate::program(program)?;
30+
31+
let mut gen_script = None;
32+
let mut gen_modules = vec![];
33+
for unit in units {
34+
match unit {
35+
CompiledUnit::Module { module, .. } => gen_modules.push(module),
36+
CompiledUnit::Script { script, .. } => gen_script = Some(script),
37+
}
38+
}
39+
Ok((gen_script, gen_modules))
4240
}
4341

4442
pub fn serialize_script(script: CompiledScript) -> Result<Vec<u8>> {

crates/integration_tests/tests/test_lsp.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
use lsp_server::{Connection, Message, Notification, Request, RequestId, Response};
22
use lsp_types::request::{Initialize, Shutdown};
33
use lsp_types::{
4-
ClientCapabilities, DidChangeConfigurationParams, InitializeParams, InitializedParams,
4+
ClientCapabilities, DidChangeConfigurationParams, DidChangeWatchedFilesParams,
5+
FileChangeType, FileEvent, InitializeParams, InitializedParams, Url,
56
};
67

78
use analysis::config::Config;
89

910
use dialects::DialectName;
1011

11-
use integration_tests::config;
12+
use integration_tests::{config, get_script_path};
1213

13-
use lsp_types::notification::{DidChangeConfiguration, Initialized};
14+
use lsp_types::notification::{DidChangeConfiguration, DidChangeWatchedFiles, Initialized};
1415

1516
use move_language_server::global_state::{initialize_new_global_state, GlobalState};
16-
use move_language_server::main_loop::{main_loop, notification_new, request_new};
17+
use move_language_server::main_loop::{
18+
main_loop, notification_new, request_new, FileSystemEvent,
19+
};
1720
use move_language_server::server::run_server;
1821

1922
const SHUTDOWN_REQ_ID: u64 = 10;
@@ -58,20 +61,28 @@ fn response(req_id: usize, contents: serde_json::Value) -> Message {
5861
trait MessageType {
5962
fn into_request(self) -> Request;
6063
fn into_response(self) -> Response;
64+
fn into_notification(self) -> Notification;
6165
}
6266

6367
impl MessageType for Message {
6468
fn into_request(self) -> Request {
6569
match self {
6670
Message::Request(req) => req,
67-
_ => panic!(),
71+
_ => panic!("not a request"),
6872
}
6973
}
7074

7175
fn into_response(self) -> Response {
7276
match self {
7377
Message::Response(resp) => resp,
74-
_ => panic!(),
78+
_ => panic!("not a response"),
79+
}
80+
}
81+
82+
fn into_notification(self) -> Notification {
83+
match self {
84+
Message::Notification(notification) => notification,
85+
_ => panic!("not a notification"),
7586
}
7687
}
7788
}
@@ -115,13 +126,18 @@ fn test_server_initialization() {
115126
assert_eq!(init_finished_resp.id, RequestId::from(1));
116127
assert_eq!(
117128
init_finished_resp.result.unwrap()["capabilities"]["textDocumentSync"],
118-
1
129+
serde_json::json!({"change": 1, "openClose": true})
119130
);
120-
let shutdown_req = client_conn.receiver.try_recv().unwrap();
131+
let registration_req = client_conn.receiver.try_recv().unwrap().into_request();
132+
assert_eq!(registration_req.method, "client/registerCapability");
121133
assert_eq!(
122-
shutdown_req.into_response().id,
123-
RequestId::from(SHUTDOWN_REQ_ID)
134+
registration_req.params["registrations"][0]["method"],
135+
"workspace/didChangeWatchedFiles"
124136
);
137+
138+
let shutdown_resp = client_conn.receiver.try_recv().unwrap().into_response();
139+
assert_eq!(shutdown_resp.id, RequestId::from(SHUTDOWN_REQ_ID));
140+
125141
client_conn.receiver.try_recv().unwrap_err();
126142
}
127143

@@ -157,3 +173,31 @@ fn test_server_config_change() {
157173
);
158174
assert_eq!(global_state.config().dialect_name, DialectName::DFinance);
159175
}
176+
177+
#[test]
178+
fn test_removed_file_not_present_in_the_diagnostics() {
179+
let (client_conn, server_conn) = Connection::memory();
180+
181+
let script_text = r"script {
182+
use 0x0::Unknown;
183+
fun main() {}
184+
}";
185+
let script_file = (get_script_path(), script_text.to_string());
186+
187+
let mut global_state = global_state(config!());
188+
global_state.update_from_events(vec![FileSystemEvent::AddFile(script_file)]);
189+
190+
let delete_event = FileEvent::new(
191+
Url::from_file_path(get_script_path()).unwrap(),
192+
FileChangeType::Deleted,
193+
);
194+
let files_changed_notification =
195+
notification::<DidChangeWatchedFiles>(DidChangeWatchedFilesParams {
196+
changes: vec![delete_event],
197+
});
198+
send_messages(&client_conn, vec![files_changed_notification]);
199+
200+
main_loop(&mut global_state, &server_conn).unwrap();
201+
202+
assert!(global_state.analysis().db().available_files.is_empty());
203+
}

crates/move-language-server/src/global_state.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,17 @@ impl GlobalState {
6464
}
6565

6666
pub fn initialize_new_global_state(config: Config) -> GlobalState {
67-
let mut fs_events = vec![];
67+
let mut initial_fs_events = vec![];
6868
match &config.stdlib_folder {
6969
Some(folder) => {
7070
for file in io::load_move_files(vec![folder.clone()]).unwrap() {
71-
fs_events.push(FileSystemEvent::AddFile(file));
71+
initial_fs_events.push(FileSystemEvent::AddFile(file));
7272
}
7373
}
7474
None => {}
7575
}
7676
for file in io::load_move_files(config.modules_folders.clone()).unwrap() {
77-
fs_events.push(FileSystemEvent::AddFile(file));
77+
initial_fs_events.push(FileSystemEvent::AddFile(file));
7878
}
79-
GlobalState::new(config, fs_events)
79+
GlobalState::new(config, initial_fs_events)
8080
}

crates/move-language-server/src/main_loop.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use anyhow::Result;
66
use crossbeam_channel::{unbounded, Sender};
77
use lsp_server::{Connection, Message, Notification, Request, RequestId, Response};
88
use lsp_types::notification::{
9-
DidChangeConfiguration, DidChangeTextDocument, DidCloseTextDocument, DidOpenTextDocument,
10-
PublishDiagnostics, ShowMessage,
9+
DidChangeConfiguration, DidChangeTextDocument, DidChangeWatchedFiles, DidCloseTextDocument,
10+
DidOpenTextDocument, PublishDiagnostics, ShowMessage,
1111
};
1212
use lsp_types::request::WorkspaceConfiguration;
1313
use lsp_types::{
@@ -370,6 +370,23 @@ fn on_notification(
370370
}
371371
Err(not) => not,
372372
};
373+
let not = match notification_cast::<DidChangeWatchedFiles>(not) {
374+
Ok(params) => {
375+
for file_event in params.changes {
376+
let uri = file_event.uri;
377+
let fpath = uri
378+
.to_file_path()
379+
.map_err(|_| anyhow::anyhow!("invalid uri: {}", uri))?;
380+
let fpath = leaked_fpath(fpath);
381+
loop_state.opened_files.remove(fpath);
382+
fs_events_sender
383+
.send(FileSystemEvent::RemoveFile(fpath))
384+
.unwrap();
385+
}
386+
return Ok(());
387+
}
388+
Err(not) => not,
389+
};
373390
if not.method.starts_with("$/") {
374391
return Ok(());
375392
}

crates/move-language-server/src/server.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
use std::path::PathBuf;
22

33
use anyhow::Result;
4-
use lsp_server::{Connection, ProtocolError};
5-
use lsp_types::{ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind};
4+
use lsp_server::{Connection, ProtocolError, RequestId};
5+
use lsp_types::{
6+
DidChangeWatchedFilesRegistrationOptions, FileSystemWatcher, RegistrationParams,
7+
ServerCapabilities, TextDocumentSyncCapability, TextDocumentSyncKind,
8+
TextDocumentSyncOptions, WatchKind,
9+
};
610
use serde::de::DeserializeOwned;
711

812
use analysis::config::Config;
913

1014
use crate::global_state::initialize_new_global_state;
1115
use crate::main_loop;
16+
use crate::main_loop::request_new;
1217

1318
fn move_language_server_capabilities() -> ServerCapabilities {
1419
ServerCapabilities {
15-
text_document_sync: Some(TextDocumentSyncCapability::Kind(TextDocumentSyncKind::Full)),
20+
text_document_sync: Some(TextDocumentSyncCapability::Options(
21+
TextDocumentSyncOptions {
22+
open_close: Some(true),
23+
change: Some(TextDocumentSyncKind::Full),
24+
..TextDocumentSyncOptions::default()
25+
},
26+
)),
1627
..ServerCapabilities::default()
1728
}
1829
}
@@ -45,13 +56,36 @@ pub fn parse_initialize_params(init_params: serde_json::Value) -> Result<(PathBu
4556
Ok((root, config))
4657
}
4758

59+
fn register_for_file_changes(connection: &Connection) {
60+
let move_files_watcher = FileSystemWatcher {
61+
glob_pattern: "**/*.move".to_string(),
62+
kind: Some(WatchKind::Delete),
63+
};
64+
let registration_options = DidChangeWatchedFilesRegistrationOptions {
65+
watchers: vec![move_files_watcher],
66+
};
67+
let registration = lsp_types::Registration {
68+
id: "workspace/didChangeWatchedFiles".to_string(),
69+
method: "workspace/didChangeWatchedFiles".to_string(),
70+
register_options: Some(serde_json::to_value(registration_options).unwrap()),
71+
};
72+
let registration_req = request_new::<lsp_types::request::RegisterCapability>(
73+
RequestId::from(1),
74+
RegistrationParams {
75+
registrations: vec![registration],
76+
},
77+
);
78+
connection.sender.send(registration_req.into()).unwrap();
79+
}
80+
4881
pub fn run_server(connection: &Connection) -> Result<()> {
4982
let init_params = initialize_server(connection)?;
5083
let (_, config) = parse_initialize_params(init_params)?;
5184
log::info!("Initialization is finished");
5285

86+
register_for_file_changes(connection);
87+
5388
let mut global_state = initialize_new_global_state(config);
54-
dbg!(&global_state.config());
5589
main_loop::main_loop(&mut global_state, connection)
5690
}
5791

0 commit comments

Comments
 (0)