feat: implicitly focus entry on no focus request sent (#262)

* feat: implicitly focus entry on no focus command sent

* dev: garden
This commit is contained in:
Myriad-Dreamin 2024-05-08 22:16:56 +08:00 committed by GitHub
parent ca5d8f61cc
commit d05c5012ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 74 additions and 12 deletions

View file

@ -330,7 +330,7 @@ impl CompileClientActor {
self.config = config;
}
pub fn change_entry(&mut self, path: Option<ImmutPath>) -> Result<(), Error> {
pub fn change_entry(&mut self, path: Option<ImmutPath>) -> Result<bool, Error> {
if path
.as_deref()
.is_some_and(|p| !p.is_absolute() && !p.starts_with("/untitled"))
@ -340,7 +340,7 @@ impl CompileClientActor {
let next_entry = self.config.determine_entry(path);
if next_entry == self.entry {
return Ok(());
return Ok(false);
}
let diag_group = &self.diag_group;
@ -373,7 +373,7 @@ impl CompileClientActor {
self.entry = next_entry;
Ok(())
Ok(true)
}
pub fn add_memory_changes(&self, event: MemoryEvent) {

View file

@ -205,6 +205,10 @@ pub struct TypstLanguageServer {
pub pinning: bool,
/// The client focusing file.
pub focusing: Option<ImmutPath>,
/// The client ever focused implicitly by activities.
pub ever_focusing_by_activities: bool,
/// The client ever sent manual focusing request.
pub ever_manual_focusing: bool,
// Configurations
/// User configuration from the editor.
@ -261,6 +265,8 @@ impl TypstLanguageServer {
}),
dedicates: Vec::new(),
shutdown_requested: false,
ever_focusing_by_activities: false,
ever_manual_focusing: false,
sema_tokens_registered: None,
formatter_registered: None,
config: Default::default(),
@ -822,10 +828,17 @@ impl TypstLanguageServer {
pub fn focus_document(&mut self, arguments: Vec<JsonValue>) -> LspResult<JsonValue> {
let new_entry = parse_path_or_null(arguments.first())?;
let update_result = self.focus_entry(new_entry.clone());
update_result.map_err(|err| internal_error(format!("could not focus file: {err}")))?;
if !self.ever_manual_focusing {
self.ever_manual_focusing = true;
log::info!("first manual focusing is coming");
}
info!("file focused: {entry:?}", entry = new_entry);
let ok = self.focus_entry(new_entry.clone());
let ok = ok.map_err(|err| internal_error(format!("could not focus file: {err}")))?;
if ok {
info!("file focused: {new_entry:?}");
}
Ok(JsonValue::Null)
}
@ -977,6 +990,9 @@ impl TypstLanguageServer {
let text = params.text_document.text;
self.create_source(path.clone(), text).unwrap();
// Focus after opening
self.implicit_focus_entry(|| Some(path.as_path().into()), 'o');
Ok(())
}
@ -1104,6 +1120,7 @@ impl TypstLanguageServer {
fn hover(&mut self, params: HoverParams) -> LspResult<Option<Hover>> {
let (path, position) = as_path_pos(params.text_document_position_params);
self.implicit_focus_entry(|| Some(path.as_path().into()), 'h');
run_query!(self.Hover(path, position))
}
@ -1113,6 +1130,7 @@ impl TypstLanguageServer {
) -> LspResult<Option<Vec<FoldingRange>>> {
let path = as_path(params.text_document);
let line_folding_only = self.const_config().doc_line_folding_only;
self.implicit_focus_entry(|| Some(path.as_path().into()), 'f');
run_query!(self.FoldingRange(path, line_folding_only))
}
@ -1138,6 +1156,7 @@ impl TypstLanguageServer {
params: SemanticTokensParams,
) -> LspResult<Option<SemanticTokensResult>> {
let path = as_path(params.text_document);
self.implicit_focus_entry(|| Some(path.as_path().into()), 't');
run_query!(self.SemanticTokensFull(path))
}
@ -1147,6 +1166,7 @@ impl TypstLanguageServer {
) -> LspResult<Option<SemanticTokensFullDeltaResult>> {
let path = as_path(params.text_document);
let previous_result_id = params.previous_result_id;
self.implicit_focus_entry(|| Some(path.as_path().into()), 't');
run_query!(self.SemanticTokensDelta(path, previous_result_id))
}

View file

@ -19,13 +19,11 @@ use crate::{actor::typ_client::CompileClientActor, compiler::CompileServer, Typs
impl CompileServer {
/// Focus main file to some path.
pub fn do_change_entry(&mut self, new_entry: Option<ImmutPath>) -> Result<(), Error> {
pub fn do_change_entry(&mut self, new_entry: Option<ImmutPath>) -> Result<bool, Error> {
self.compiler
.as_mut()
.unwrap()
.change_entry(new_entry.clone())?;
Ok(())
.change_entry(new_entry.clone())
}
}
@ -48,14 +46,58 @@ impl TypstLanguageServer {
}
/// Updates the primary (focusing) entry
pub fn focus_entry(&mut self, new_entry: Option<ImmutPath>) -> Result<(), Error> {
pub fn focus_entry(&mut self, new_entry: Option<ImmutPath>) -> Result<bool, Error> {
if self.pinning || self.config.compile.has_default_entry_path {
self.focusing = new_entry;
return Ok(());
return Ok(false);
}
self.primary.do_change_entry(new_entry.clone())
}
/// This is used for tracking activating document status if a client is not
/// performing any focus command request.
///
/// See https://github.com/microsoft/language-server-protocol/issues/718
///
/// we do want to focus the file implicitly by `textDocument/diagnostic`
/// (pullDiagnostics mode), as suggested by language-server-protocol#718,
/// however, this has poor support, e.g. since neovim 0.10.0.
pub fn implicit_focus_entry(
&mut self,
new_entry: impl FnOnce() -> Option<ImmutPath>,
site: char,
) {
if self.ever_manual_focusing {
return;
}
// didOpen
match site {
// foldingRange, hover, semanticTokens
'f' | 'h' | 't' => {
self.ever_focusing_by_activities = true;
}
// didOpen
_ => {
if self.ever_focusing_by_activities {
return;
}
}
}
let new_entry = new_entry();
let update_result = self.focus_entry(new_entry.clone());
match update_result {
Ok(true) => {
log::info!("file focused[implicit,{site}]: {new_entry:?}");
}
Err(err) => {
log::warn!("could not focus file: {err}");
}
Ok(false) => {}
}
}
}
#[derive(Debug, Clone)]