Файли
openidea/src-tauri/src/commands/doc.rs
T
xdpan1234таxdpan1234 0a70b0af01 fix(vcs): open comparisons in independently resizable native windows (#818)
Compare with Local, Compare Versions and the other revision comparisons open in a separate window that belongs to their project window. The window can be moved outside the main window, resized from its edges and corners, and shows the full diff. Edits made there and in the project window are mirrored both ways.

Root cause of #798: the comparison was an in-window dialog with a fixed size.

Settings and comparison windows now share one auxiliary-window mechanism (`AuxKind`, `open_auxiliary_window`). It handles labels, the title bar, placement over the parent, event forwarding, document-edit mirroring, menu routing, closing together with the parent, and remembered geometry per kind.

Co-authored-by: xdpan1234 <[email protected]>
2026-11-04 12:27:45 +08:00

164 рядки
6.1 KiB
Rust

//! IPC commands of `ide_host::ops::doc` (the shared implementation).
use crate::state::AppState;
use ide_core::{ChangeSet, DocId, IdeResult, OutlineItem, Range};
#[allow(unused_imports)]
pub use ide_host::ops::doc::*;
use ide_language::{FoldRange, SyntaxHighlights};
use ide_text::LineEnding;
use ide_workspace::{DocumentInfo, HistoryEntry};
use std::path::PathBuf;
use tauri::{Manager, State, Window};
/// Opens a document. Async: reading and decoding a large file must not block
/// the main thread (synchronous commands run on it).
#[tauri::command]
#[specta::specta]
pub async fn doc_open(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult<DocumentInfo> {
ide_host::ops::doc::open(&state.host, window.label(), path).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_close(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<()> {
let host = state.host.clone();
let window = window.label().to_owned();
blocking(move || ide_host::ops::doc::close(&host, &window, doc)).await
}
/// Applies a CodeMirror change set; returns the new version. Rejects with
/// `outOfSync` when `base_version` is stale; the UI then calls `doc_snapshot`.
#[tauri::command]
#[specta::specta]
pub async fn doc_edit(
window: Window,
state: State<'_, AppState>,
doc: DocId,
base_version: u32,
changes: ChangeSet,
) -> IdeResult<u32> {
let host = state.host.clone();
let label = window.label().to_owned();
let peers = crate::events::document_edit_peers(window.app_handle(), &label);
let mirrored = (!peers.is_empty()).then(|| changes.changes.clone());
let version = blocking(move || ide_host::ops::doc::edit(&host, &label, doc, base_version, changes)).await?;
if let Some(changes) = mirrored {
crate::events::emit_document_edit(window.app_handle(), peers, doc, base_version, version, changes);
}
Ok(version)
}
#[tauri::command]
#[specta::specta]
pub async fn doc_save(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<()> {
ide_host::ops::doc::save(&state.host, window.label(), doc).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_save_all(window: Window, state: State<'_, AppState>) -> IdeResult<()> {
ide_host::ops::doc::save_all(&state.host, window.label()).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_sync_from_disk(window: Window, state: State<'_, AppState>) -> IdeResult<()> {
ide_host::ops::doc::sync_from_disk(&state.host, window.label()).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_snapshot(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<DocumentInfo> {
ide_host::ops::doc::snapshot(&state.host, window.label(), doc).await
}
/// Opens a read-only virtual document (see `lsp_virtual_document`) as an
/// editor buffer, so syntax features and language-server requests work in it.
#[tauri::command]
#[specta::specta]
pub async fn doc_open_virtual(window: Window, state: State<'_, AppState>, uri: String) -> IdeResult<DocumentInfo> {
ide_host::ops::doc::doc_open_virtual(&state.host, window.label(), uri).await
}
/// The CodeMirror mode `path` gets when opened (`DocumentInfo::ui_mode`),
/// without opening it: previews of closed files.
#[tauri::command]
#[specta::specta]
pub async fn doc_ui_mode(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult<Option<String>> {
ide_host::ops::doc::doc_ui_mode(&state.host, window.label(), path).await
}
/// "Reload with Encoding" (`reload`) or "Convert to Encoding"; returns the new encoding label.
#[tauri::command]
#[specta::specta]
pub async fn doc_set_encoding(
window: Window,
state: State<'_, AppState>,
doc: DocId,
encoding: String,
reload: bool,
) -> IdeResult<String> {
ide_host::ops::doc::doc_set_encoding(&state.host, window.label(), doc, encoding, reload).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_set_line_ending(
window: Window,
state: State<'_, AppState>,
doc: DocId,
line_ending: LineEnding,
) -> IdeResult<()> {
let host = state.host.clone();
let window = window.label().to_owned();
blocking(move || ide_host::ops::doc::doc_set_line_ending(&host, &window, doc, line_ending)).await
}
/// Structure view: LSP document symbols when available (with tree-sitter
/// visibility), tree-sitter otherwise.
/// Tree-sitter answers come from the per-document tree cache (incremental
/// re-parse); large documents get no syntax structure.
#[tauri::command]
#[specta::specta]
pub async fn doc_outline(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<Vec<OutlineItem>> {
ide_host::ops::doc::doc_outline(&state.host, window.label(), doc).await
}
#[tauri::command]
#[specta::specta]
pub async fn doc_folding(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<Vec<FoldRange>> {
ide_host::ops::doc::doc_folding(&state.host, window.label(), doc).await
}
/// Tree-sitter highlighting for languages the UI has no CodeMirror mode for;
/// empty when the grammar has no highlights query or the document is large.
#[tauri::command]
#[specta::specta]
pub async fn doc_highlights(window: Window, state: State<'_, AppState>, doc: DocId) -> IdeResult<SyntaxHighlights> {
ide_host::ops::doc::doc_highlights(&state.host, window.label(), doc).await
}
/// Extend Selection (⌥↑): syntax ranges around `offset`, innermost first.
/// Large documents fall back to word / line / document ranges.
#[tauri::command]
#[specta::specta]
pub async fn doc_selection_ranges(
window: Window,
state: State<'_, AppState>,
doc: DocId,
offset: u32,
) -> IdeResult<Vec<Range>> {
ide_host::ops::doc::doc_selection_ranges(&state.host, window.label(), doc, offset).await
}
#[tauri::command]
#[specta::specta]
pub fn history_list(window: Window, state: State<'_, AppState>, path: PathBuf) -> IdeResult<Vec<HistoryEntry>> {
ide_host::ops::doc::history_list(&state.host, window.label(), path)
}
#[tauri::command]
#[specta::specta]
pub fn history_content(window: Window, state: State<'_, AppState>, id: String) -> IdeResult<String> {
ide_host::ops::doc::history_content(&state.host, window.label(), id)
}