feat: use window/showDocument to show previewing document (#1450)

* feat: use `window/showDocument` to show previewing document

* feat: implement it

* feat: take focus
This commit is contained in:
Myriad-Dreamin 2025-03-17 17:52:59 +08:00 committed by GitHub
parent c65b69be26
commit 42fd5d3bc9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 71 additions and 3 deletions

View file

@ -78,6 +78,8 @@ pub struct Config {
pub formatter_indent_size: Option<u32>,
/// Whether to remove html from markup content in responses.
pub support_html_in_markdown: bool,
/// Whether to send show document requests with customized notification.
pub customized_show_document: bool,
/// Tinymist's default export target.
pub export_target: ExportTarget,
/// Tinymist's completion features.
@ -271,6 +273,7 @@ impl Config {
assign_config!(formatter_print_width := "formatterPrintWidth"?: Option<u32>);
assign_config!(formatter_indent_size := "formatterIndentSize"?: Option<u32>);
assign_config!(support_html_in_markdown := "supportHtmlInMarkdown"?: bool);
assign_config!(customized_show_document := "customizedShowDocument"?: bool);
assign_config!(export_target := "exportTarget"?: ExportTarget);
assign_config!(completion := "completion"?: CompletionFeat);
assign_config!(completion.trigger_suggest := "triggerSuggest"?: bool);

View file

@ -114,7 +114,11 @@ impl ServerState {
editor_tx,
memory_changes: HashMap::new(),
#[cfg(feature = "preview")]
preview: tool::preview::PreviewState::new(watchers, client.cast(|s| &mut s.preview)),
preview: tool::preview::PreviewState::new(
&config,
watchers,
client.cast(|s| &mut s.preview),
),
#[cfg(feature = "dap")]
debug: crate::dap::DebugState::default(),
ever_focusing_by_activities: false,

View file

@ -22,6 +22,7 @@ use serde::Serialize;
use serde_json::Value as JsonValue;
use sync_ls::just_ok;
use tinymist_assets::TYPST_PREVIEW_HTML;
use tinymist_query::{LspPosition, LspRange};
use tinymist_std::error::IgnoreLogging;
use tinymist_std::typst::TypstDocument;
use tokio::sync::{mpsc, oneshot};
@ -276,6 +277,8 @@ impl typst_preview::CompileView for PreviewCompileView {
range.start += off;
}
}
// todo: resolve untitled uri.
let filepath = world.path_for_id(span.id()?).ok()?.to_err().ok()?;
Some(DocToSrcJumpInfo {
filepath: filepath.to_string_lossy().to_string(),
@ -358,11 +361,17 @@ pub struct PreviewState {
preview_tx: mpsc::UnboundedSender<PreviewRequest>,
/// the watchers for the preview
pub(crate) watchers: ProjectPreviewState,
/// Whether to send show document requests with customized notification.
pub customized_show_document: bool,
}
impl PreviewState {
/// Create a new preview state.
pub fn new(watchers: ProjectPreviewState, client: TypedLspClient<PreviewState>) -> Self {
pub fn new(
config: &Config,
watchers: ProjectPreviewState,
client: TypedLspClient<PreviewState>,
) -> Self {
let (preview_tx, preview_rx) = mpsc::unbounded_channel();
client.handle.spawn(
@ -379,6 +388,7 @@ impl PreviewState {
client,
preview_tx,
watchers,
customized_show_document: config.customized_show_document,
}
}
@ -507,6 +517,7 @@ impl PreviewState {
// Forward preview responses to lsp client
let tid = task_id.clone();
let client = self.client.clone();
let customized_show_document = self.customized_show_document;
self.client.handle.spawn(async move {
let mut resp_rx = resp_rx;
while let Some(resp) = resp_rx.recv().await {
@ -518,7 +529,13 @@ impl PreviewState {
SyncEditorChanges(..) => {
log::warn!("PreviewTask({tid}): is sending SyncEditorChanges in lsp mode");
}
EditorScrollTo(s) => client.send_notification::<ScrollSource>(&s),
EditorScrollTo(s) => {
if customized_show_document {
client.send_notification::<ScrollSource>(&s)
} else {
send_show_document(&client, &s, &tid);
}
}
Outline(s) => client.send_notification::<NotifDocumentOutline>(&s),
}
}
@ -1022,6 +1039,48 @@ impl Notification for NotifDocumentOutline {
const METHOD: &'static str = "tinymist/documentOutline";
}
fn send_show_document(client: &TypedLspClient<PreviewState>, s: &DocToSrcJumpInfo, tid: &str) {
let range_start = s.start.map(|(l, c)| LspPosition {
line: l as u32,
character: c as u32,
});
let range_end = s.end.map(|(l, c)| LspPosition {
line: l as u32,
character: c as u32,
});
let range = match (range_start, range_end) {
(Some(start), Some(end)) => Some(LspRange { start, end }),
(Some(start), None) | (None, Some(start)) => Some(LspRange { start, end: start }),
_ => None,
};
// todo: resolve uri if any
let uri = match Url::from_file_path(Path::new(&s.filepath)) {
Ok(uri) => uri,
Err(e) => {
log::error!(
"PreviewTask({tid}): failed to convert path to URI: {e:?}, path {:?}",
s.filepath
);
return;
}
};
client.send_lsp_request::<lsp_types::request::ShowDocument>(
lsp_types::ShowDocumentParams {
uri,
external: None,
take_focus: Some(true),
selection: range,
},
|_, resp| {
if let Some(err) = resp.error {
log::error!("failed to send ShowDocument request: {err:?}");
}
},
);
}
/// Determine where to jump to based on a click in a frame.
pub fn jump_from_click(
world: &LspWorld,

View file

@ -40,6 +40,7 @@ function configureEditorAndLanguage(context: ExtensionContext, trait: TinymistTr
config.triggerSuggestAndParameterHints = true;
config.triggerParameterHints = true;
config.supportHtmlInMarkdown = true;
config.customizedShowDocument = true;
// Sets shared features
extensionState.features.preview = !isWeb && config.previewFeature === "enable";
extensionState.features.wordSeparator = config.configureDefaultWordSeparator !== "disable";

View file

@ -276,6 +276,7 @@
"triggerParameterHints": true,
"triggerSuggestAndParameterHints": true,
"supportHtmlInMarkdown": true,
"customizedShowDocument": true,
"experimentalFormatterMode": "disable"
},
"trace": "off"