3090 lines · 106.1 KB · Rust
RawDownload
pub use crate::{    diagnostic_set::DiagnosticSet,    highlight_map::{HighlightId, HighlightMap},    proto, BracketPair, Grammar, Language, LanguageConfig, LanguageRegistry, PLAIN_TEXT,};use crate::{    diagnostic_set::{DiagnosticEntry, DiagnosticGroup},    language_settings::{language_settings, LanguageSettings},    outline::OutlineItem,    syntax_map::{        SyntaxLayerInfo, SyntaxMap, SyntaxMapCapture, SyntaxMapCaptures, SyntaxSnapshot,        ToTreeSitterPoint,    },    CodeLabel, LanguageScope, Outline,};use anyhow::{anyhow, Result};pub use clock::ReplicaId;use futures::FutureExt as _;use gpui::{fonts::HighlightStyle, AppContext, Entity, ModelContext, Task};use lsp::LanguageServerId;use parking_lot::Mutex;use similar::{ChangeTag, TextDiff};use smallvec::SmallVec;use smol::future::yield_now;use std::{    any::Any,    cmp::{self, Ordering},    collections::BTreeMap,    ffi::OsStr,    future::Future,    iter::{self, Iterator, Peekable},    mem,    ops::{Deref, Range},    path::{Path, PathBuf},    str,    sync::Arc,    time::{Duration, Instant, SystemTime, UNIX_EPOCH},    vec,};use sum_tree::TreeMap;use text::operation_queue::OperationQueue;pub use text::{Buffer as TextBuffer, BufferSnapshot as TextBufferSnapshot, *};use theme::SyntaxTheme;#[cfg(any(test, feature = "test-support"))]use util::RandomCharIter;use util::{RangeExt, TryFutureExt as _}; #[cfg(any(test, feature = "test-support"))]pub use {tree_sitter_rust, tree_sitter_typescript}; pub use lsp::DiagnosticSeverity; pub struct Buffer {    text: TextBuffer,    diff_base: Option<String>,    git_diff: git::diff::BufferDiff,    file: Option<Arc<dyn File>>,    saved_version: clock::Global,    saved_version_fingerprint: RopeFingerprint,    saved_mtime: SystemTime,    transaction_depth: usize,    was_dirty_before_starting_transaction: Option<bool>,    language: Option<Arc<Language>>,    autoindent_requests: Vec<Arc<AutoindentRequest>>,    pending_autoindent: Option<Task<()>>,    sync_parse_timeout: Duration,    syntax_map: Mutex<SyntaxMap>,    parsing_in_background: bool,    parse_count: usize,    diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,    remote_selections: TreeMap<ReplicaId, SelectionSet>,    selections_update_count: usize,    diagnostics_update_count: usize,    diagnostics_timestamp: clock::Lamport,    file_update_count: usize,    git_diff_update_count: usize,    completion_triggers: Vec<String>,    completion_triggers_timestamp: clock::Lamport,    deferred_ops: OperationQueue<Operation>,} pub struct BufferSnapshot {    text: text::BufferSnapshot,    pub git_diff: git::diff::BufferDiff,    pub(crate) syntax: SyntaxSnapshot,    file: Option<Arc<dyn File>>,    diagnostics: SmallVec<[(LanguageServerId, DiagnosticSet); 2]>,    diagnostics_update_count: usize,    file_update_count: usize,    git_diff_update_count: usize,    remote_selections: TreeMap<ReplicaId, SelectionSet>,    selections_update_count: usize,    language: Option<Arc<Language>>,    parse_count: usize,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]pub struct IndentSize {    pub len: u32,    pub kind: IndentKind,} #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]pub enum IndentKind {    #[default]    Space,    Tab,} #[derive(Copy, Clone, PartialEq, Eq, Debug, Default)]pub enum CursorShape {    #[default]    Bar,    Block,    Underscore,    Hollow,} #[derive(Clone, Debug)]struct SelectionSet {    line_mode: bool,    cursor_shape: CursorShape,    selections: Arc<[Selection<Anchor>]>,    lamport_timestamp: clock::Lamport,} #[derive(Clone, Debug, PartialEq, Eq)]pub struct GroupId {    source: Arc<str>,    id: usize,} #[derive(Clone, Debug, PartialEq, Eq)]pub struct Diagnostic {    pub source: Option<String>,    pub code: Option<String>,    pub severity: DiagnosticSeverity,    pub message: String,    pub group_id: usize,    pub is_valid: bool,    pub is_primary: bool,    pub is_disk_based: bool,    pub is_unnecessary: bool,} #[derive(Clone, Debug)]pub struct Completion {    pub old_range: Range<Anchor>,    pub new_text: String,    pub label: CodeLabel,    pub server_id: LanguageServerId,    pub lsp_completion: lsp::CompletionItem,} #[derive(Clone, Debug)]pub struct CodeAction {    pub server_id: LanguageServerId,    pub range: Range<Anchor>,    pub lsp_action: lsp::CodeAction,} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Operation {    Buffer(text::Operation),     UpdateDiagnostics {        server_id: LanguageServerId,        diagnostics: Arc<[DiagnosticEntry<Anchor>]>,        lamport_timestamp: clock::Lamport,    },     UpdateSelections {        selections: Arc<[Selection<Anchor>]>,        lamport_timestamp: clock::Lamport,        line_mode: bool,        cursor_shape: CursorShape,    },     UpdateCompletionTriggers {        triggers: Vec<String>,        lamport_timestamp: clock::Lamport,    },} #[derive(Clone, Debug, PartialEq, Eq)]pub enum Event {    Operation(Operation),    Edited,    DirtyChanged,    Saved,    FileHandleChanged,    Reloaded,    DiffBaseChanged,    LanguageChanged,    Reparsed,    DiagnosticsUpdated,    Closed,} pub trait File: Send + Sync {    fn as_local(&self) -> Option<&dyn LocalFile>;     fn is_local(&self) -> bool {        self.as_local().is_some()    }     fn mtime(&self) -> SystemTime;     /// Returns the path of this file relative to the worktree's root directory.    fn path(&self) -> &Arc<Path>;     /// Returns the path of this file relative to the worktree's parent directory (this means it    /// includes the name of the worktree's root folder).    fn full_path(&self, cx: &AppContext) -> PathBuf;     /// Returns the last component of this handle's absolute path. If this handle refers to the root    /// of its worktree, then this method will return the name of the worktree itself.    fn file_name<'a>(&'a self, cx: &'a AppContext) -> &'a OsStr;     /// Returns the id of the worktree to which this file belongs.    ///    /// This is needed for looking up project-specific settings.    fn worktree_id(&self) -> usize;     fn is_deleted(&self) -> bool;     fn as_any(&self) -> &dyn Any;     fn to_proto(&self) -> rpc::proto::File;} pub trait LocalFile: File {    /// Returns the absolute path of this file.    fn abs_path(&self, cx: &AppContext) -> PathBuf;     fn load(&self, cx: &AppContext) -> Task<Result<String>>;     fn buffer_reloaded(        &self,        buffer_id: u64,        version: &clock::Global,        fingerprint: RopeFingerprint,        line_ending: LineEnding,        mtime: SystemTime,        cx: &mut AppContext,    );} #[derive(Clone, Debug)]pub enum AutoindentMode {    /// Indent each line of inserted text.    EachLine,    /// Apply the same indentation adjustment to all of the lines    /// in a given insertion.    Block {        /// The original indentation level of the first line of each        /// insertion, if it has been copied.        original_indent_columns: Vec<u32>,    },} #[derive(Clone)]struct AutoindentRequest {    before_edit: BufferSnapshot,    entries: Vec<AutoindentRequestEntry>,    is_block_mode: bool,} #[derive(Clone)]struct AutoindentRequestEntry {    /// A range of the buffer whose indentation should be adjusted.    range: Range<Anchor>,    /// Whether or not these lines should be considered brand new, for the    /// purpose of auto-indent. When text is not new, its indentation will    /// only be adjusted if the suggested indentation level has *changed*    /// since the edit was made.    first_line_is_new: bool,    indent_size: IndentSize,    original_indent_column: Option<u32>,} #[derive(Debug)]struct IndentSuggestion {    basis_row: u32,    delta: Ordering,    within_error: bool,} struct BufferChunkHighlights<'a> {    captures: SyntaxMapCaptures<'a>,    next_capture: Option<SyntaxMapCapture<'a>>,    stack: Vec<(usize, HighlightId)>,    highlight_maps: Vec<HighlightMap>,} pub struct BufferChunks<'a> {    range: Range<usize>,    chunks: text::Chunks<'a>,    diagnostic_endpoints: Peekable<vec::IntoIter<DiagnosticEndpoint>>,    error_depth: usize,    warning_depth: usize,    information_depth: usize,    hint_depth: usize,    unnecessary_depth: usize,    highlights: Option<BufferChunkHighlights<'a>>,} #[derive(Clone, Copy, Debug, Default)]pub struct Chunk<'a> {    pub text: &'a str,    pub syntax_highlight_id: Option<HighlightId>,    pub highlight_style: Option<HighlightStyle>,    pub diagnostic_severity: Option<DiagnosticSeverity>,    pub is_unnecessary: bool,    pub is_tab: bool,} pub struct Diff {    pub(crate) base_version: clock::Global,    line_ending: LineEnding,    edits: Vec<(Range<usize>, Arc<str>)>,} #[derive(Clone, Copy)]pub(crate) struct DiagnosticEndpoint {    offset: usize,    is_start: bool,    severity: DiagnosticSeverity,    is_unnecessary: bool,} #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug)]pub enum CharKind {    Punctuation,    Whitespace,    Word,} impl CharKind {    pub fn coerce_punctuation(self, treat_punctuation_as_word: bool) -> Self {        if treat_punctuation_as_word && self == CharKind::Punctuation {            CharKind::Word        } else {            self        }    }} impl Buffer {    pub fn new<T: Into<String>>(replica_id: ReplicaId, id: u64, base_text: T) -> Self {        Self::build(            TextBuffer::new(replica_id, id, base_text.into()),            None,            None,        )    }     pub fn remote(remote_id: u64, replica_id: ReplicaId, base_text: String) -> Self {        Self::build(            TextBuffer::new(replica_id, remote_id, base_text),            None,            None,        )    }     pub fn from_proto(        replica_id: ReplicaId,        message: proto::BufferState,        file: Option<Arc<dyn File>>,    ) -> Result<Self> {        let buffer = TextBuffer::new(replica_id, message.id, message.base_text);        let mut this = Self::build(            buffer,            message.diff_base.map(|text| text.into_boxed_str().into()),            file,        );        this.text.set_line_ending(proto::deserialize_line_ending(            rpc::proto::LineEnding::from_i32(message.line_ending)                .ok_or_else(|| anyhow!("missing line_ending"))?,        ));        this.saved_version = proto::deserialize_version(&message.saved_version);        this.saved_version_fingerprint =            proto::deserialize_fingerprint(&message.saved_version_fingerprint)?;        this.saved_mtime = message            .saved_mtime            .ok_or_else(|| anyhow!("invalid saved_mtime"))?            .into();        Ok(this)    }     pub fn to_proto(&self) -> proto::BufferState {        proto::BufferState {            id: self.remote_id(),            file: self.file.as_ref().map(|f| f.to_proto()),            base_text: self.base_text().to_string(),            diff_base: self.diff_base.as_ref().map(|h| h.to_string()),            line_ending: proto::serialize_line_ending(self.line_ending()) as i32,            saved_version: proto::serialize_version(&self.saved_version),            saved_version_fingerprint: proto::serialize_fingerprint(self.saved_version_fingerprint),            saved_mtime: Some(self.saved_mtime.into()),        }    }     pub fn serialize_ops(        &self,        since: Option<clock::Global>,        cx: &AppContext,    ) -> Task<Vec<proto::Operation>> {        let mut operations = Vec::new();        operations.extend(self.deferred_ops.iter().map(proto::serialize_operation));         operations.extend(self.remote_selections.iter().map(|(_, set)| {            proto::serialize_operation(&Operation::UpdateSelections {                selections: set.selections.clone(),                lamport_timestamp: set.lamport_timestamp,                line_mode: set.line_mode,                cursor_shape: set.cursor_shape,            })        }));         for (server_id, diagnostics) in &self.diagnostics {            operations.push(proto::serialize_operation(&Operation::UpdateDiagnostics {                lamport_timestamp: self.diagnostics_timestamp,                server_id: *server_id,                diagnostics: diagnostics.iter().cloned().collect(),            }));        }         operations.push(proto::serialize_operation(            &Operation::UpdateCompletionTriggers {                triggers: self.completion_triggers.clone(),                lamport_timestamp: self.completion_triggers_timestamp,            },        ));         let text_operations = self.text.operations().clone();        cx.background().spawn(async move {            let since = since.unwrap_or_default();            operations.extend(                text_operations                    .iter()                    .filter(|(_, op)| !since.observed(op.timestamp()))                    .map(|(_, op)| proto::serialize_operation(&Operation::Buffer(op.clone()))),            );            operations.sort_unstable_by_key(proto::lamport_timestamp_for_operation);            operations        })    }     pub fn with_language(mut self, language: Arc<Language>, cx: &mut ModelContext<Self>) -> Self {        self.set_language(Some(language), cx);        self    }     pub fn build(        buffer: TextBuffer,        diff_base: Option<String>,        file: Option<Arc<dyn File>>,    ) -> Self {        let saved_mtime = if let Some(file) = file.as_ref() {            file.mtime()        } else {            UNIX_EPOCH        };         Self {            saved_mtime,            saved_version: buffer.version(),            saved_version_fingerprint: buffer.as_rope().fingerprint(),            transaction_depth: 0,            was_dirty_before_starting_transaction: None,            text: buffer,            diff_base,            git_diff: git::diff::BufferDiff::new(),            file,            syntax_map: Mutex::new(SyntaxMap::new()),            parsing_in_background: false,            parse_count: 0,            sync_parse_timeout: Duration::from_millis(1),            autoindent_requests: Default::default(),            pending_autoindent: Default::default(),            language: None,            remote_selections: Default::default(),            selections_update_count: 0,            diagnostics: Default::default(),            diagnostics_update_count: 0,            diagnostics_timestamp: Default::default(),            file_update_count: 0,            git_diff_update_count: 0,            completion_triggers: Default::default(),            completion_triggers_timestamp: Default::default(),            deferred_ops: OperationQueue::new(),        }    }     pub fn snapshot(&self) -> BufferSnapshot {        let text = self.text.snapshot();        let mut syntax_map = self.syntax_map.lock();        syntax_map.interpolate(&text);        let syntax = syntax_map.snapshot();

Lines 1–500 of 3090.