Reopen file in Copilot language server when language or URI changes

This commit is contained in:
Antonio Scandurra 2023-04-19 14:27:26 +02:00
parent 672cf6b8c7
commit 34bcf6f072
4 changed files with 64 additions and 26 deletions

View file

@ -21,6 +21,7 @@ use settings::Settings;
use smol::{fs, io::BufReader, stream::StreamExt}; use smol::{fs, io::BufReader, stream::StreamExt};
use std::{ use std::{
ffi::OsString, ffi::OsString,
mem,
ops::Range, ops::Range,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
@ -148,7 +149,9 @@ impl Status {
struct RegisteredBuffer { struct RegisteredBuffer {
uri: lsp::Url, uri: lsp::Url,
snapshot: Option<(i32, BufferSnapshot)>, language_id: String,
snapshot: BufferSnapshot,
snapshot_version: i32,
_subscriptions: [gpui::Subscription; 2], _subscriptions: [gpui::Subscription; 2],
} }
@ -158,20 +161,15 @@ impl RegisteredBuffer {
buffer: &ModelHandle<Buffer>, buffer: &ModelHandle<Buffer>,
server: &LanguageServer, server: &LanguageServer,
cx: &AppContext, cx: &AppContext,
) -> Result<(i32, BufferSnapshot)> { ) -> Result<()> {
let buffer = buffer.read(cx); let buffer = buffer.read(cx);
let (version, prev_snapshot) = self let new_snapshot = buffer.snapshot();
.snapshot
.as_ref()
.ok_or_else(|| anyhow!("expected at least one snapshot"))?;
let next_snapshot = buffer.snapshot();
let content_changes = buffer let content_changes = buffer
.edits_since::<(PointUtf16, usize)>(prev_snapshot.version()) .edits_since::<(PointUtf16, usize)>(self.snapshot.version())
.map(|edit| { .map(|edit| {
let edit_start = edit.new.start.0; let edit_start = edit.new.start.0;
let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0); let edit_end = edit_start + (edit.old.end.0 - edit.old.start.0);
let new_text = next_snapshot let new_text = new_snapshot
.text_for_range(edit.new.start.1..edit.new.end.1) .text_for_range(edit.new.start.1..edit.new.end.1)
.collect(); .collect();
lsp::TextDocumentContentChangeEvent { lsp::TextDocumentContentChangeEvent {
@ -185,24 +183,21 @@ impl RegisteredBuffer {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if content_changes.is_empty() { if !content_changes.is_empty() {
Ok((*version, prev_snapshot.clone())) self.snapshot_version += 1;
} else { self.snapshot = new_snapshot;
let next_version = version + 1;
self.snapshot = Some((next_version, next_snapshot.clone()));
server.notify::<lsp::notification::DidChangeTextDocument>( server.notify::<lsp::notification::DidChangeTextDocument>(
lsp::DidChangeTextDocumentParams { lsp::DidChangeTextDocumentParams {
text_document: lsp::VersionedTextDocumentIdentifier::new( text_document: lsp::VersionedTextDocumentIdentifier::new(
self.uri.clone(), self.uri.clone(),
next_version, self.snapshot_version,
), ),
content_changes, content_changes,
}, },
)?; )?;
Ok((next_version, next_snapshot))
} }
Ok(())
} }
} }
@ -515,15 +510,16 @@ impl Copilot {
return; return;
} }
let uri: lsp::Url = format!("buffer://{}", buffer_id).parse().unwrap();
registered_buffers.entry(buffer.id()).or_insert_with(|| { registered_buffers.entry(buffer.id()).or_insert_with(|| {
let uri: lsp::Url = uri_for_buffer(buffer, cx);
let language_id = id_for_language(buffer.read(cx).language());
let snapshot = buffer.read(cx).snapshot(); let snapshot = buffer.read(cx).snapshot();
server server
.notify::<lsp::notification::DidOpenTextDocument>( .notify::<lsp::notification::DidOpenTextDocument>(
lsp::DidOpenTextDocumentParams { lsp::DidOpenTextDocumentParams {
text_document: lsp::TextDocumentItem { text_document: lsp::TextDocumentItem {
uri: uri.clone(), uri: uri.clone(),
language_id: id_for_language(buffer.read(cx).language()), language_id: language_id.clone(),
version: 0, version: 0,
text: snapshot.text(), text: snapshot.text(),
}, },
@ -533,7 +529,9 @@ impl Copilot {
RegisteredBuffer { RegisteredBuffer {
uri, uri,
snapshot: Some((0, snapshot)), language_id,
snapshot,
snapshot_version: 0,
_subscriptions: [ _subscriptions: [
cx.subscribe(buffer, |this, buffer, event, cx| { cx.subscribe(buffer, |this, buffer, event, cx| {
this.handle_buffer_event(buffer, event, cx).log_err(); this.handle_buffer_event(buffer, event, cx).log_err();
@ -575,6 +573,31 @@ impl Copilot {
}, },
)?; )?;
} }
language::Event::FileHandleChanged | language::Event::LanguageChanged => {
let new_language_id = id_for_language(buffer.read(cx).language());
let new_uri = uri_for_buffer(&buffer, cx);
if new_uri != registered_buffer.uri
|| new_language_id != registered_buffer.language_id
{
let old_uri = mem::replace(&mut registered_buffer.uri, new_uri);
registered_buffer.language_id = new_language_id;
server.notify::<lsp::notification::DidCloseTextDocument>(
lsp::DidCloseTextDocumentParams {
text_document: lsp::TextDocumentIdentifier::new(old_uri),
},
)?;
server.notify::<lsp::notification::DidOpenTextDocument>(
lsp::DidOpenTextDocumentParams {
text_document: lsp::TextDocumentItem::new(
registered_buffer.uri.clone(),
registered_buffer.language_id.clone(),
registered_buffer.snapshot_version,
registered_buffer.snapshot.text(),
),
},
)?;
}
}
_ => {} _ => {}
} }
} }
@ -659,6 +682,10 @@ impl Copilot {
} => { } => {
if matches!(status, SignInStatus::Authorized { .. }) { if matches!(status, SignInStatus::Authorized { .. }) {
if let Some(registered_buffer) = registered_buffers.get_mut(&buffer.id()) { if let Some(registered_buffer) = registered_buffers.get_mut(&buffer.id()) {
if let Err(error) = registered_buffer.report_changes(buffer, &server, cx) {
return Task::ready(Err(error));
}
(server.clone(), registered_buffer) (server.clone(), registered_buffer)
} else { } else {
return Task::ready(Err(anyhow!( return Task::ready(Err(anyhow!(
@ -671,11 +698,9 @@ impl Copilot {
} }
}; };
let (version, snapshot) = match registered_buffer.report_changes(buffer, &server, cx) {
Ok((version, snapshot)) => (version, snapshot),
Err(error) => return Task::ready(Err(error)),
};
let uri = registered_buffer.uri.clone(); let uri = registered_buffer.uri.clone();
let snapshot = registered_buffer.snapshot.clone();
let version = registered_buffer.snapshot_version;
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let position = position.to_point_utf16(&snapshot); let position = position.to_point_utf16(&snapshot);
let language = snapshot.language_at(position); let language = snapshot.language_at(position);
@ -784,6 +809,14 @@ fn id_for_language(language: Option<&Arc<Language>>) -> String {
} }
} }
fn uri_for_buffer(buffer: &ModelHandle<Buffer>, cx: &AppContext) -> lsp::Url {
if let Some(file) = buffer.read(cx).file().and_then(|file| file.as_local()) {
lsp::Url::from_file_path(file.abs_path(cx)).unwrap()
} else {
format!("buffer://{}", buffer.id()).parse().unwrap()
}
}
async fn clear_copilot_dir() { async fn clear_copilot_dir() {
remove_matching(&paths::COPILOT_DIR, |_| true).await remove_matching(&paths::COPILOT_DIR, |_| true).await
} }

View file

@ -6643,6 +6643,7 @@ impl Editor {
multi_buffer::Event::DiagnosticsUpdated => { multi_buffer::Event::DiagnosticsUpdated => {
self.refresh_active_diagnostics(cx); self.refresh_active_diagnostics(cx);
} }
multi_buffer::Event::LanguageChanged => {}
} }
} }

View file

@ -64,6 +64,7 @@ pub enum Event {
}, },
Edited, Edited,
Reloaded, Reloaded,
LanguageChanged,
Reparsed, Reparsed,
Saved, Saved,
FileHandleChanged, FileHandleChanged,
@ -1302,6 +1303,7 @@ impl MultiBuffer {
language::Event::Saved => Event::Saved, language::Event::Saved => Event::Saved,
language::Event::FileHandleChanged => Event::FileHandleChanged, language::Event::FileHandleChanged => Event::FileHandleChanged,
language::Event::Reloaded => Event::Reloaded, language::Event::Reloaded => Event::Reloaded,
language::Event::LanguageChanged => Event::LanguageChanged,
language::Event::Reparsed => Event::Reparsed, language::Event::Reparsed => Event::Reparsed,
language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated, language::Event::DiagnosticsUpdated => Event::DiagnosticsUpdated,
language::Event::Closed => Event::Closed, language::Event::Closed => Event::Closed,

View file

@ -187,6 +187,7 @@ pub enum Event {
Saved, Saved,
FileHandleChanged, FileHandleChanged,
Reloaded, Reloaded,
LanguageChanged,
Reparsed, Reparsed,
DiagnosticsUpdated, DiagnosticsUpdated,
Closed, Closed,
@ -536,6 +537,7 @@ impl Buffer {
self.syntax_map.lock().clear(); self.syntax_map.lock().clear();
self.language = language; self.language = language;
self.reparse(cx); self.reparse(cx);
cx.emit(Event::LanguageChanged);
} }
pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) { pub fn set_language_registry(&mut self, language_registry: Arc<LanguageRegistry>) {