inlay_hint_cache.rs

   1use std::{
   2    cmp,
   3    ops::{ControlFlow, Range},
   4    sync::Arc,
   5    time::Duration,
   6};
   7
   8use crate::{
   9    display_map::Inlay, Anchor, Editor, ExcerptId, InlayId, MultiBuffer, MultiBufferSnapshot,
  10};
  11use anyhow::Context;
  12use clock::Global;
  13use futures::future;
  14use gpui::{Model, ModelContext, Task, ViewContext};
  15use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
  16use parking_lot::RwLock;
  17use project::{InlayHint, ResolveState};
  18
  19use collections::{hash_map, HashMap, HashSet};
  20use language::language_settings::InlayHintSettings;
  21use smol::lock::Semaphore;
  22use sum_tree::Bias;
  23use text::{ToOffset, ToPoint};
  24use util::post_inc;
  25
  26pub struct InlayHintCache {
  27    hints: HashMap<ExcerptId, Arc<RwLock<CachedExcerptHints>>>,
  28    allowed_hint_kinds: HashSet<Option<InlayHintKind>>,
  29    version: usize,
  30    pub(super) enabled: bool,
  31    update_tasks: HashMap<ExcerptId, TasksForRanges>,
  32    lsp_request_limiter: Arc<Semaphore>,
  33}
  34
  35#[derive(Debug)]
  36struct TasksForRanges {
  37    tasks: Vec<Task<()>>,
  38    sorted_ranges: Vec<Range<language::Anchor>>,
  39}
  40
  41#[derive(Debug)]
  42pub struct CachedExcerptHints {
  43    version: usize,
  44    buffer_version: Global,
  45    buffer_id: u64,
  46    ordered_hints: Vec<InlayId>,
  47    hints_by_id: HashMap<InlayId, InlayHint>,
  48}
  49
  50#[derive(Debug, Clone, Copy)]
  51pub enum InvalidationStrategy {
  52    RefreshRequested,
  53    BufferEdited,
  54    None,
  55}
  56
  57#[derive(Debug, Default)]
  58pub struct InlaySplice {
  59    pub to_remove: Vec<InlayId>,
  60    pub to_insert: Vec<Inlay>,
  61}
  62
  63#[derive(Debug)]
  64struct ExcerptHintsUpdate {
  65    excerpt_id: ExcerptId,
  66    remove_from_visible: Vec<InlayId>,
  67    remove_from_cache: HashSet<InlayId>,
  68    add_to_cache: Vec<InlayHint>,
  69}
  70
  71#[derive(Debug, Clone, Copy)]
  72struct ExcerptQuery {
  73    buffer_id: u64,
  74    excerpt_id: ExcerptId,
  75    cache_version: usize,
  76    invalidate: InvalidationStrategy,
  77    reason: &'static str,
  78}
  79
  80impl InvalidationStrategy {
  81    fn should_invalidate(&self) -> bool {
  82        matches!(
  83            self,
  84            InvalidationStrategy::RefreshRequested | InvalidationStrategy::BufferEdited
  85        )
  86    }
  87}
  88
  89impl TasksForRanges {
  90    fn new(query_ranges: QueryRanges, task: Task<()>) -> Self {
  91        let mut sorted_ranges = Vec::new();
  92        sorted_ranges.extend(query_ranges.before_visible);
  93        sorted_ranges.extend(query_ranges.visible);
  94        sorted_ranges.extend(query_ranges.after_visible);
  95        Self {
  96            tasks: vec![task],
  97            sorted_ranges,
  98        }
  99    }
 100
 101    fn update_cached_tasks(
 102        &mut self,
 103        buffer_snapshot: &BufferSnapshot,
 104        query_ranges: QueryRanges,
 105        invalidate: InvalidationStrategy,
 106        spawn_task: impl FnOnce(QueryRanges) -> Task<()>,
 107    ) {
 108        let query_ranges = if invalidate.should_invalidate() {
 109            self.tasks.clear();
 110            self.sorted_ranges.clear();
 111            query_ranges
 112        } else {
 113            let mut non_cached_query_ranges = query_ranges;
 114            non_cached_query_ranges.before_visible = non_cached_query_ranges
 115                .before_visible
 116                .into_iter()
 117                .flat_map(|query_range| {
 118                    self.remove_cached_ranges_from_query(buffer_snapshot, query_range)
 119                })
 120                .collect();
 121            non_cached_query_ranges.visible = non_cached_query_ranges
 122                .visible
 123                .into_iter()
 124                .flat_map(|query_range| {
 125                    self.remove_cached_ranges_from_query(buffer_snapshot, query_range)
 126                })
 127                .collect();
 128            non_cached_query_ranges.after_visible = non_cached_query_ranges
 129                .after_visible
 130                .into_iter()
 131                .flat_map(|query_range| {
 132                    self.remove_cached_ranges_from_query(buffer_snapshot, query_range)
 133                })
 134                .collect();
 135            non_cached_query_ranges
 136        };
 137
 138        if !query_ranges.is_empty() {
 139            self.tasks.push(spawn_task(query_ranges));
 140        }
 141    }
 142
 143    fn remove_cached_ranges_from_query(
 144        &mut self,
 145        buffer_snapshot: &BufferSnapshot,
 146        query_range: Range<language::Anchor>,
 147    ) -> Vec<Range<language::Anchor>> {
 148        let mut ranges_to_query = Vec::new();
 149        let mut latest_cached_range = None::<&mut Range<language::Anchor>>;
 150        for cached_range in self
 151            .sorted_ranges
 152            .iter_mut()
 153            .skip_while(|cached_range| {
 154                cached_range
 155                    .end
 156                    .cmp(&query_range.start, buffer_snapshot)
 157                    .is_lt()
 158            })
 159            .take_while(|cached_range| {
 160                cached_range
 161                    .start
 162                    .cmp(&query_range.end, buffer_snapshot)
 163                    .is_le()
 164            })
 165        {
 166            match latest_cached_range {
 167                Some(latest_cached_range) => {
 168                    if latest_cached_range.end.offset.saturating_add(1) < cached_range.start.offset
 169                    {
 170                        ranges_to_query.push(latest_cached_range.end..cached_range.start);
 171                        cached_range.start = latest_cached_range.end;
 172                    }
 173                }
 174                None => {
 175                    if query_range
 176                        .start
 177                        .cmp(&cached_range.start, buffer_snapshot)
 178                        .is_lt()
 179                    {
 180                        ranges_to_query.push(query_range.start..cached_range.start);
 181                        cached_range.start = query_range.start;
 182                    }
 183                }
 184            }
 185            latest_cached_range = Some(cached_range);
 186        }
 187
 188        match latest_cached_range {
 189            Some(latest_cached_range) => {
 190                if latest_cached_range.end.offset.saturating_add(1) < query_range.end.offset {
 191                    ranges_to_query.push(latest_cached_range.end..query_range.end);
 192                    latest_cached_range.end = query_range.end;
 193                }
 194            }
 195            None => {
 196                ranges_to_query.push(query_range.clone());
 197                self.sorted_ranges.push(query_range);
 198                self.sorted_ranges
 199                    .sort_by(|range_a, range_b| range_a.start.cmp(&range_b.start, buffer_snapshot));
 200            }
 201        }
 202
 203        ranges_to_query
 204    }
 205
 206    fn invalidate_range(&mut self, buffer: &BufferSnapshot, range: &Range<language::Anchor>) {
 207        self.sorted_ranges = self
 208            .sorted_ranges
 209            .drain(..)
 210            .filter_map(|mut cached_range| {
 211                if cached_range.start.cmp(&range.end, buffer).is_gt()
 212                    || cached_range.end.cmp(&range.start, buffer).is_lt()
 213                {
 214                    Some(vec![cached_range])
 215                } else if cached_range.start.cmp(&range.start, buffer).is_ge()
 216                    && cached_range.end.cmp(&range.end, buffer).is_le()
 217                {
 218                    None
 219                } else if range.start.cmp(&cached_range.start, buffer).is_ge()
 220                    && range.end.cmp(&cached_range.end, buffer).is_le()
 221                {
 222                    Some(vec![
 223                        cached_range.start..range.start,
 224                        range.end..cached_range.end,
 225                    ])
 226                } else if cached_range.start.cmp(&range.start, buffer).is_ge() {
 227                    cached_range.start = range.end;
 228                    Some(vec![cached_range])
 229                } else {
 230                    cached_range.end = range.start;
 231                    Some(vec![cached_range])
 232                }
 233            })
 234            .flatten()
 235            .collect();
 236    }
 237}
 238
 239impl InlayHintCache {
 240    pub fn new(inlay_hint_settings: InlayHintSettings) -> Self {
 241        Self {
 242            allowed_hint_kinds: inlay_hint_settings.enabled_inlay_hint_kinds(),
 243            enabled: inlay_hint_settings.enabled,
 244            hints: HashMap::default(),
 245            update_tasks: HashMap::default(),
 246            version: 0,
 247            lsp_request_limiter: Arc::new(Semaphore::new(MAX_CONCURRENT_LSP_REQUESTS)),
 248        }
 249    }
 250
 251    pub fn update_settings(
 252        &mut self,
 253        multi_buffer: &Model<MultiBuffer>,
 254        new_hint_settings: InlayHintSettings,
 255        visible_hints: Vec<Inlay>,
 256        cx: &mut ViewContext<Editor>,
 257    ) -> ControlFlow<Option<InlaySplice>> {
 258        let new_allowed_hint_kinds = new_hint_settings.enabled_inlay_hint_kinds();
 259        match (self.enabled, new_hint_settings.enabled) {
 260            (false, false) => {
 261                self.allowed_hint_kinds = new_allowed_hint_kinds;
 262                ControlFlow::Break(None)
 263            }
 264            (true, true) => {
 265                if new_allowed_hint_kinds == self.allowed_hint_kinds {
 266                    ControlFlow::Break(None)
 267                } else {
 268                    let new_splice = self.new_allowed_hint_kinds_splice(
 269                        multi_buffer,
 270                        &visible_hints,
 271                        &new_allowed_hint_kinds,
 272                        cx,
 273                    );
 274                    if new_splice.is_some() {
 275                        self.version += 1;
 276                        self.allowed_hint_kinds = new_allowed_hint_kinds;
 277                    }
 278                    ControlFlow::Break(new_splice)
 279                }
 280            }
 281            (true, false) => {
 282                self.enabled = new_hint_settings.enabled;
 283                self.allowed_hint_kinds = new_allowed_hint_kinds;
 284                if self.hints.is_empty() {
 285                    ControlFlow::Break(None)
 286                } else {
 287                    self.clear();
 288                    ControlFlow::Break(Some(InlaySplice {
 289                        to_remove: visible_hints.iter().map(|inlay| inlay.id).collect(),
 290                        to_insert: Vec::new(),
 291                    }))
 292                }
 293            }
 294            (false, true) => {
 295                self.enabled = new_hint_settings.enabled;
 296                self.allowed_hint_kinds = new_allowed_hint_kinds;
 297                ControlFlow::Continue(())
 298            }
 299        }
 300    }
 301
 302    pub fn spawn_hint_refresh(
 303        &mut self,
 304        reason: &'static str,
 305        excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
 306        invalidate: InvalidationStrategy,
 307        cx: &mut ViewContext<Editor>,
 308    ) -> Option<InlaySplice> {
 309        if !self.enabled {
 310            return None;
 311        }
 312
 313        let mut invalidated_hints = Vec::new();
 314        if invalidate.should_invalidate() {
 315            self.update_tasks
 316                .retain(|task_excerpt_id, _| excerpts_to_query.contains_key(task_excerpt_id));
 317            self.hints.retain(|cached_excerpt, cached_hints| {
 318                let retain = excerpts_to_query.contains_key(cached_excerpt);
 319                if !retain {
 320                    invalidated_hints.extend(cached_hints.read().ordered_hints.iter().copied());
 321                }
 322                retain
 323            });
 324        }
 325        if excerpts_to_query.is_empty() && invalidated_hints.is_empty() {
 326            return None;
 327        }
 328
 329        let cache_version = self.version + 1;
 330        cx.spawn(|editor, mut cx| async move {
 331            editor
 332                .update(&mut cx, |editor, cx| {
 333                    spawn_new_update_tasks(
 334                        editor,
 335                        reason,
 336                        excerpts_to_query,
 337                        invalidate,
 338                        cache_version,
 339                        cx,
 340                    )
 341                })
 342                .ok();
 343        })
 344        .detach();
 345
 346        if invalidated_hints.is_empty() {
 347            None
 348        } else {
 349            Some(InlaySplice {
 350                to_remove: invalidated_hints,
 351                to_insert: Vec::new(),
 352            })
 353        }
 354    }
 355
 356    fn new_allowed_hint_kinds_splice(
 357        &self,
 358        multi_buffer: &Model<MultiBuffer>,
 359        visible_hints: &[Inlay],
 360        new_kinds: &HashSet<Option<InlayHintKind>>,
 361        cx: &mut ViewContext<Editor>,
 362    ) -> Option<InlaySplice> {
 363        let old_kinds = &self.allowed_hint_kinds;
 364        if new_kinds == old_kinds {
 365            return None;
 366        }
 367
 368        let mut to_remove = Vec::new();
 369        let mut to_insert = Vec::new();
 370        let mut shown_hints_to_remove = visible_hints.iter().fold(
 371            HashMap::<ExcerptId, Vec<(Anchor, InlayId)>>::default(),
 372            |mut current_hints, inlay| {
 373                current_hints
 374                    .entry(inlay.position.excerpt_id)
 375                    .or_default()
 376                    .push((inlay.position, inlay.id));
 377                current_hints
 378            },
 379        );
 380
 381        let multi_buffer = multi_buffer.read(cx);
 382        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 383
 384        for (excerpt_id, excerpt_cached_hints) in &self.hints {
 385            let shown_excerpt_hints_to_remove =
 386                shown_hints_to_remove.entry(*excerpt_id).or_default();
 387            let excerpt_cached_hints = excerpt_cached_hints.read();
 388            let mut excerpt_cache = excerpt_cached_hints.ordered_hints.iter().fuse().peekable();
 389            shown_excerpt_hints_to_remove.retain(|(shown_anchor, shown_hint_id)| {
 390                let Some(buffer) = shown_anchor
 391                    .buffer_id
 392                    .and_then(|buffer_id| multi_buffer.buffer(buffer_id))
 393                else {
 394                    return false;
 395                };
 396                let buffer_snapshot = buffer.read(cx).snapshot();
 397                loop {
 398                    match excerpt_cache.peek() {
 399                        Some(&cached_hint_id) => {
 400                            let cached_hint = &excerpt_cached_hints.hints_by_id[cached_hint_id];
 401                            if cached_hint_id == shown_hint_id {
 402                                excerpt_cache.next();
 403                                return !new_kinds.contains(&cached_hint.kind);
 404                            }
 405
 406                            match cached_hint
 407                                .position
 408                                .cmp(&shown_anchor.text_anchor, &buffer_snapshot)
 409                            {
 410                                cmp::Ordering::Less | cmp::Ordering::Equal => {
 411                                    if !old_kinds.contains(&cached_hint.kind)
 412                                        && new_kinds.contains(&cached_hint.kind)
 413                                    {
 414                                        to_insert.push(Inlay::hint(
 415                                            cached_hint_id.id(),
 416                                            multi_buffer_snapshot.anchor_in_excerpt(
 417                                                *excerpt_id,
 418                                                cached_hint.position,
 419                                            ),
 420                                            &cached_hint,
 421                                        ));
 422                                    }
 423                                    excerpt_cache.next();
 424                                }
 425                                cmp::Ordering::Greater => return true,
 426                            }
 427                        }
 428                        None => return true,
 429                    }
 430                }
 431            });
 432
 433            for cached_hint_id in excerpt_cache {
 434                let maybe_missed_cached_hint = &excerpt_cached_hints.hints_by_id[cached_hint_id];
 435                let cached_hint_kind = maybe_missed_cached_hint.kind;
 436                if !old_kinds.contains(&cached_hint_kind) && new_kinds.contains(&cached_hint_kind) {
 437                    to_insert.push(Inlay::hint(
 438                        cached_hint_id.id(),
 439                        multi_buffer_snapshot
 440                            .anchor_in_excerpt(*excerpt_id, maybe_missed_cached_hint.position),
 441                        &maybe_missed_cached_hint,
 442                    ));
 443                }
 444            }
 445        }
 446
 447        to_remove.extend(
 448            shown_hints_to_remove
 449                .into_values()
 450                .flatten()
 451                .map(|(_, hint_id)| hint_id),
 452        );
 453        if to_remove.is_empty() && to_insert.is_empty() {
 454            None
 455        } else {
 456            Some(InlaySplice {
 457                to_remove,
 458                to_insert,
 459            })
 460        }
 461    }
 462
 463    pub fn remove_excerpts(&mut self, excerpts_removed: Vec<ExcerptId>) -> Option<InlaySplice> {
 464        let mut to_remove = Vec::new();
 465        for excerpt_to_remove in excerpts_removed {
 466            self.update_tasks.remove(&excerpt_to_remove);
 467            if let Some(cached_hints) = self.hints.remove(&excerpt_to_remove) {
 468                let cached_hints = cached_hints.read();
 469                to_remove.extend(cached_hints.ordered_hints.iter().copied());
 470            }
 471        }
 472        if to_remove.is_empty() {
 473            None
 474        } else {
 475            self.version += 1;
 476            Some(InlaySplice {
 477                to_remove,
 478                to_insert: Vec::new(),
 479            })
 480        }
 481    }
 482
 483    pub fn clear(&mut self) {
 484        if !self.update_tasks.is_empty() || !self.hints.is_empty() {
 485            self.version += 1;
 486        }
 487        self.update_tasks.clear();
 488        self.hints.clear();
 489    }
 490
 491    pub fn hint_by_id(&self, excerpt_id: ExcerptId, hint_id: InlayId) -> Option<InlayHint> {
 492        self.hints
 493            .get(&excerpt_id)?
 494            .read()
 495            .hints_by_id
 496            .get(&hint_id)
 497            .cloned()
 498    }
 499
 500    pub fn hints(&self) -> Vec<InlayHint> {
 501        let mut hints = Vec::new();
 502        for excerpt_hints in self.hints.values() {
 503            let excerpt_hints = excerpt_hints.read();
 504            hints.extend(
 505                excerpt_hints
 506                    .ordered_hints
 507                    .iter()
 508                    .map(|id| &excerpt_hints.hints_by_id[id])
 509                    .cloned(),
 510            );
 511        }
 512        hints
 513    }
 514
 515    pub fn version(&self) -> usize {
 516        self.version
 517    }
 518
 519    pub fn spawn_hint_resolve(
 520        &self,
 521        buffer_id: u64,
 522        excerpt_id: ExcerptId,
 523        id: InlayId,
 524        cx: &mut ViewContext<'_, Editor>,
 525    ) {
 526        if let Some(excerpt_hints) = self.hints.get(&excerpt_id) {
 527            let mut guard = excerpt_hints.write();
 528            if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
 529                if let ResolveState::CanResolve(server_id, _) = &cached_hint.resolve_state {
 530                    let hint_to_resolve = cached_hint.clone();
 531                    let server_id = *server_id;
 532                    cached_hint.resolve_state = ResolveState::Resolving;
 533                    drop(guard);
 534                    cx.spawn(|editor, mut cx| async move {
 535                        let resolved_hint_task = editor.update(&mut cx, |editor, cx| {
 536                            editor
 537                                .buffer()
 538                                .read(cx)
 539                                .buffer(buffer_id)
 540                                .and_then(|buffer| {
 541                                    let project = editor.project.as_ref()?;
 542                                    Some(project.update(cx, |project, cx| {
 543                                        project.resolve_inlay_hint(
 544                                            hint_to_resolve,
 545                                            buffer,
 546                                            server_id,
 547                                            cx,
 548                                        )
 549                                    }))
 550                                })
 551                        })?;
 552                        if let Some(resolved_hint_task) = resolved_hint_task {
 553                            let mut resolved_hint =
 554                                resolved_hint_task.await.context("hint resolve task")?;
 555                            editor.update(&mut cx, |editor, _| {
 556                                todo!()
 557                                // if let Some(excerpt_hints) =
 558                                //     editor.inlay_hint_cache.hints.get(&excerpt_id)
 559                                // {
 560                                //     let mut guard = excerpt_hints.write();
 561                                //     if let Some(cached_hint) = guard.hints_by_id.get_mut(&id) {
 562                                //         if cached_hint.resolve_state == ResolveState::Resolving {
 563                                //             resolved_hint.resolve_state = ResolveState::Resolved;
 564                                //             *cached_hint = resolved_hint;
 565                                //         }
 566                                //     }
 567                                // }
 568                            })?;
 569                        }
 570
 571                        anyhow::Ok(())
 572                    })
 573                    .detach_and_log_err(cx);
 574                }
 575            }
 576        }
 577    }
 578}
 579
 580fn spawn_new_update_tasks(
 581    editor: &mut Editor,
 582    reason: &'static str,
 583    excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
 584    invalidate: InvalidationStrategy,
 585    update_cache_version: usize,
 586    cx: &mut ViewContext<'_, Editor>,
 587) {
 588    todo!("old version below");
 589}
 590//     let visible_hints = Arc::new(editor.visible_inlay_hints(cx));
 591//     for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
 592//         excerpts_to_query
 593//     {
 594//         if excerpt_visible_range.is_empty() {
 595//             continue;
 596//         }
 597//         let buffer = excerpt_buffer.read(cx);
 598//         let buffer_id = buffer.remote_id();
 599//         let buffer_snapshot = buffer.snapshot();
 600//         if buffer_snapshot
 601//             .version()
 602//             .changed_since(&new_task_buffer_version)
 603//         {
 604//             continue;
 605//         }
 606
 607//         let cached_excerpt_hints = editor.inlay_hint_cache.hints.get(&excerpt_id).cloned();
 608//         if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
 609//             let cached_excerpt_hints = cached_excerpt_hints.read();
 610//             let cached_buffer_version = &cached_excerpt_hints.buffer_version;
 611//             if cached_excerpt_hints.version > update_cache_version
 612//                 || cached_buffer_version.changed_since(&new_task_buffer_version)
 613//             {
 614//                 continue;
 615//             }
 616//         };
 617
 618//         let (multi_buffer_snapshot, Some(query_ranges)) =
 619//             editor.buffer.update(cx, |multi_buffer, cx| {
 620//                 (
 621//                     multi_buffer.snapshot(cx),
 622//                     determine_query_ranges(
 623//                         multi_buffer,
 624//                         excerpt_id,
 625//                         &excerpt_buffer,
 626//                         excerpt_visible_range,
 627//                         cx,
 628//                     ),
 629//                 )
 630//             })
 631//         else {
 632//             return;
 633//         };
 634//         let query = ExcerptQuery {
 635//             buffer_id,
 636//             excerpt_id,
 637//             cache_version: update_cache_version,
 638//             invalidate,
 639//             reason,
 640//         };
 641
 642//         let new_update_task = |query_ranges| {
 643//             new_update_task(
 644//                 query,
 645//                 query_ranges,
 646//                 multi_buffer_snapshot,
 647//                 buffer_snapshot.clone(),
 648//                 Arc::clone(&visible_hints),
 649//                 cached_excerpt_hints,
 650//                 Arc::clone(&editor.inlay_hint_cache.lsp_request_limiter),
 651//                 cx,
 652//             )
 653//         };
 654
 655//         match editor.inlay_hint_cache.update_tasks.entry(excerpt_id) {
 656//             hash_map::Entry::Occupied(mut o) => {
 657//                 o.get_mut().update_cached_tasks(
 658//                     &buffer_snapshot,
 659//                     query_ranges,
 660//                     invalidate,
 661//                     new_update_task,
 662//                 );
 663//             }
 664//             hash_map::Entry::Vacant(v) => {
 665//                 v.insert(TasksForRanges::new(
 666//                     query_ranges.clone(),
 667//                     new_update_task(query_ranges),
 668//                 ));
 669//             }
 670//         }
 671//     }
 672// }
 673
 674#[derive(Debug, Clone)]
 675struct QueryRanges {
 676    before_visible: Vec<Range<language::Anchor>>,
 677    visible: Vec<Range<language::Anchor>>,
 678    after_visible: Vec<Range<language::Anchor>>,
 679}
 680
 681impl QueryRanges {
 682    fn is_empty(&self) -> bool {
 683        self.before_visible.is_empty() && self.visible.is_empty() && self.after_visible.is_empty()
 684    }
 685}
 686
 687fn determine_query_ranges(
 688    multi_buffer: &mut MultiBuffer,
 689    excerpt_id: ExcerptId,
 690    excerpt_buffer: &Model<Buffer>,
 691    excerpt_visible_range: Range<usize>,
 692    cx: &mut ModelContext<'_, MultiBuffer>,
 693) -> Option<QueryRanges> {
 694    let full_excerpt_range = multi_buffer
 695        .excerpts_for_buffer(excerpt_buffer, cx)
 696        .into_iter()
 697        .find(|(id, _)| id == &excerpt_id)
 698        .map(|(_, range)| range.context)?;
 699    let buffer = excerpt_buffer.read(cx);
 700    let snapshot = buffer.snapshot();
 701    let excerpt_visible_len = excerpt_visible_range.end - excerpt_visible_range.start;
 702
 703    let visible_range = if excerpt_visible_range.start == excerpt_visible_range.end {
 704        return None;
 705    } else {
 706        vec![
 707            buffer.anchor_before(snapshot.clip_offset(excerpt_visible_range.start, Bias::Left))
 708                ..buffer.anchor_after(snapshot.clip_offset(excerpt_visible_range.end, Bias::Right)),
 709        ]
 710    };
 711
 712    let full_excerpt_range_end_offset = full_excerpt_range.end.to_offset(&snapshot);
 713    let after_visible_range_start = excerpt_visible_range
 714        .end
 715        .saturating_add(1)
 716        .min(full_excerpt_range_end_offset)
 717        .min(buffer.len());
 718    let after_visible_range = if after_visible_range_start == full_excerpt_range_end_offset {
 719        Vec::new()
 720    } else {
 721        let after_range_end_offset = after_visible_range_start
 722            .saturating_add(excerpt_visible_len)
 723            .min(full_excerpt_range_end_offset)
 724            .min(buffer.len());
 725        vec![
 726            buffer.anchor_before(snapshot.clip_offset(after_visible_range_start, Bias::Left))
 727                ..buffer.anchor_after(snapshot.clip_offset(after_range_end_offset, Bias::Right)),
 728        ]
 729    };
 730
 731    let full_excerpt_range_start_offset = full_excerpt_range.start.to_offset(&snapshot);
 732    let before_visible_range_end = excerpt_visible_range
 733        .start
 734        .saturating_sub(1)
 735        .max(full_excerpt_range_start_offset);
 736    let before_visible_range = if before_visible_range_end == full_excerpt_range_start_offset {
 737        Vec::new()
 738    } else {
 739        let before_range_start_offset = before_visible_range_end
 740            .saturating_sub(excerpt_visible_len)
 741            .max(full_excerpt_range_start_offset);
 742        vec![
 743            buffer.anchor_before(snapshot.clip_offset(before_range_start_offset, Bias::Left))
 744                ..buffer.anchor_after(snapshot.clip_offset(before_visible_range_end, Bias::Right)),
 745        ]
 746    };
 747
 748    Some(QueryRanges {
 749        before_visible: before_visible_range,
 750        visible: visible_range,
 751        after_visible: after_visible_range,
 752    })
 753}
 754
 755const MAX_CONCURRENT_LSP_REQUESTS: usize = 5;
 756const INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS: u64 = 400;
 757
 758fn new_update_task(
 759    query: ExcerptQuery,
 760    query_ranges: QueryRanges,
 761    multi_buffer_snapshot: MultiBufferSnapshot,
 762    buffer_snapshot: BufferSnapshot,
 763    visible_hints: Arc<Vec<Inlay>>,
 764    cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
 765    lsp_request_limiter: Arc<Semaphore>,
 766    cx: &mut ViewContext<'_, Editor>,
 767) -> Task<()> {
 768    todo!()
 769    // cx.spawn(|editor, mut cx| async move {
 770    //     let closure_cx = cx.clone();
 771    //     let fetch_and_update_hints = |invalidate, range| {
 772    //         fetch_and_update_hints(
 773    //             editor.clone(),
 774    //             multi_buffer_snapshot.clone(),
 775    //             buffer_snapshot.clone(),
 776    //             Arc::clone(&visible_hints),
 777    //             cached_excerpt_hints.as_ref().map(Arc::clone),
 778    //             query,
 779    //             invalidate,
 780    //             range,
 781    //             Arc::clone(&lsp_request_limiter),
 782    //             closure_cx.clone(),
 783    //         )
 784    //     };
 785    //     let visible_range_update_results = future::join_all(query_ranges.visible.into_iter().map(
 786    //         |visible_range| async move {
 787    //             (
 788    //                 visible_range.clone(),
 789    //                 fetch_and_update_hints(query.invalidate.should_invalidate(), visible_range)
 790    //                     .await,
 791    //             )
 792    //         },
 793    //     ))
 794    //     .await;
 795
 796    //     let hint_delay = cx.background().timer(Duration::from_millis(
 797    //         INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS,
 798    //     ));
 799
 800    //     let mut query_range_failed = |range: &Range<language::Anchor>, e: anyhow::Error| {
 801    //         log::error!("inlay hint update task for range {range:?} failed: {e:#}");
 802    //         editor
 803    //             .update(&mut cx, |editor, _| {
 804    //                 if let Some(task_ranges) = editor
 805    //                     .inlay_hint_cache
 806    //                     .update_tasks
 807    //                     .get_mut(&query.excerpt_id)
 808    //                 {
 809    //                     task_ranges.invalidate_range(&buffer_snapshot, &range);
 810    //                 }
 811    //             })
 812    //             .ok()
 813    //     };
 814
 815    //     for (range, result) in visible_range_update_results {
 816    //         if let Err(e) = result {
 817    //             query_range_failed(&range, e);
 818    //         }
 819    //     }
 820
 821    //     hint_delay.await;
 822    //     let invisible_range_update_results = future::join_all(
 823    //         query_ranges
 824    //             .before_visible
 825    //             .into_iter()
 826    //             .chain(query_ranges.after_visible.into_iter())
 827    //             .map(|invisible_range| async move {
 828    //                 (
 829    //                     invisible_range.clone(),
 830    //                     fetch_and_update_hints(false, invisible_range).await,
 831    //                 )
 832    //             }),
 833    //     )
 834    //     .await;
 835    //     for (range, result) in invisible_range_update_results {
 836    //         if let Err(e) = result {
 837    //             query_range_failed(&range, e);
 838    //         }
 839    //     }
 840    // })
 841}
 842
 843// async fn fetch_and_update_hints(
 844//     editor: gpui::WeakView<Editor>,
 845//     multi_buffer_snapshot: MultiBufferSnapshot,
 846//     buffer_snapshot: BufferSnapshot,
 847//     visible_hints: Arc<Vec<Inlay>>,
 848//     cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
 849//     query: ExcerptQuery,
 850//     invalidate: bool,
 851//     fetch_range: Range<language::Anchor>,
 852//     lsp_request_limiter: Arc<Semaphore>,
 853//     mut cx: gpui::AsyncAppContext,
 854// ) -> anyhow::Result<()> {
 855//     let (lsp_request_guard, got_throttled) = if query.invalidate.should_invalidate() {
 856//         (None, false)
 857//     } else {
 858//         match lsp_request_limiter.try_acquire() {
 859//             Some(guard) => (Some(guard), false),
 860//             None => (Some(lsp_request_limiter.acquire().await), true),
 861//         }
 862//     };
 863//     let fetch_range_to_log =
 864//         fetch_range.start.to_point(&buffer_snapshot)..fetch_range.end.to_point(&buffer_snapshot);
 865//     let inlay_hints_fetch_task = editor
 866//         .update(&mut cx, |editor, cx| {
 867//             if got_throttled {
 868//                 let query_not_around_visible_range = match editor.excerpt_visible_offsets(None, cx).remove(&query.excerpt_id) {
 869//                     Some((_, _, current_visible_range)) => {
 870//                         let visible_offset_length = current_visible_range.len();
 871//                         let double_visible_range = current_visible_range
 872//                             .start
 873//                             .saturating_sub(visible_offset_length)
 874//                             ..current_visible_range
 875//                                 .end
 876//                                 .saturating_add(visible_offset_length)
 877//                                 .min(buffer_snapshot.len());
 878//                         !double_visible_range
 879//                             .contains(&fetch_range.start.to_offset(&buffer_snapshot))
 880//                             && !double_visible_range
 881//                                 .contains(&fetch_range.end.to_offset(&buffer_snapshot))
 882//                     },
 883//                     None => true,
 884//                 };
 885//                 if query_not_around_visible_range {
 886//                     log::trace!("Fetching inlay hints for range {fetch_range_to_log:?} got throttled and fell off the current visible range, skipping.");
 887//                     if let Some(task_ranges) = editor
 888//                         .inlay_hint_cache
 889//                         .update_tasks
 890//                         .get_mut(&query.excerpt_id)
 891//                     {
 892//                         task_ranges.invalidate_range(&buffer_snapshot, &fetch_range);
 893//                     }
 894//                     return None;
 895//                 }
 896//             }
 897//             editor
 898//                 .buffer()
 899//                 .read(cx)
 900//                 .buffer(query.buffer_id)
 901//                 .and_then(|buffer| {
 902//                     let project = editor.project.as_ref()?;
 903//                     Some(project.update(cx, |project, cx| {
 904//                         project.inlay_hints(buffer, fetch_range.clone(), cx)
 905//                     }))
 906//                 })
 907//         })
 908//         .ok()
 909//         .flatten();
 910//     let new_hints = match inlay_hints_fetch_task {
 911//         Some(fetch_task) => {
 912//             log::debug!(
 913//                 "Fetching inlay hints for range {fetch_range_to_log:?}, reason: {query_reason}, invalidate: {invalidate}",
 914//                 query_reason = query.reason,
 915//             );
 916//             log::trace!(
 917//                 "Currently visible hints: {visible_hints:?}, cached hints present: {}",
 918//                 cached_excerpt_hints.is_some(),
 919//             );
 920//             fetch_task.await.context("inlay hint fetch task")?
 921//         }
 922//         None => return Ok(()),
 923//     };
 924//     drop(lsp_request_guard);
 925//     log::debug!(
 926//         "Fetched {} hints for range {fetch_range_to_log:?}",
 927//         new_hints.len()
 928//     );
 929//     log::trace!("Fetched hints: {new_hints:?}");
 930
 931//     let background_task_buffer_snapshot = buffer_snapshot.clone();
 932//     let backround_fetch_range = fetch_range.clone();
 933//     let new_update = cx
 934//         .background()
 935//         .spawn(async move {
 936//             calculate_hint_updates(
 937//                 query.excerpt_id,
 938//                 invalidate,
 939//                 backround_fetch_range,
 940//                 new_hints,
 941//                 &background_task_buffer_snapshot,
 942//                 cached_excerpt_hints,
 943//                 &visible_hints,
 944//             )
 945//         })
 946//         .await;
 947//     if let Some(new_update) = new_update {
 948//         log::debug!(
 949//             "Applying update for range {fetch_range_to_log:?}: remove from editor: {}, remove from cache: {}, add to cache: {}",
 950//             new_update.remove_from_visible.len(),
 951//             new_update.remove_from_cache.len(),
 952//             new_update.add_to_cache.len()
 953//         );
 954//         log::trace!("New update: {new_update:?}");
 955//         editor
 956//             .update(&mut cx, |editor, cx| {
 957//                 apply_hint_update(
 958//                     editor,
 959//                     new_update,
 960//                     query,
 961//                     invalidate,
 962//                     buffer_snapshot,
 963//                     multi_buffer_snapshot,
 964//                     cx,
 965//                 );
 966//             })
 967//             .ok();
 968//     }
 969//     Ok(())
 970// }
 971
 972fn calculate_hint_updates(
 973    excerpt_id: ExcerptId,
 974    invalidate: bool,
 975    fetch_range: Range<language::Anchor>,
 976    new_excerpt_hints: Vec<InlayHint>,
 977    buffer_snapshot: &BufferSnapshot,
 978    cached_excerpt_hints: Option<Arc<RwLock<CachedExcerptHints>>>,
 979    visible_hints: &[Inlay],
 980) -> Option<ExcerptHintsUpdate> {
 981    let mut add_to_cache = Vec::<InlayHint>::new();
 982    let mut excerpt_hints_to_persist = HashMap::default();
 983    for new_hint in new_excerpt_hints {
 984        if !contains_position(&fetch_range, new_hint.position, buffer_snapshot) {
 985            continue;
 986        }
 987        let missing_from_cache = match &cached_excerpt_hints {
 988            Some(cached_excerpt_hints) => {
 989                let cached_excerpt_hints = cached_excerpt_hints.read();
 990                match cached_excerpt_hints
 991                    .ordered_hints
 992                    .binary_search_by(|probe| {
 993                        cached_excerpt_hints.hints_by_id[probe]
 994                            .position
 995                            .cmp(&new_hint.position, buffer_snapshot)
 996                    }) {
 997                    Ok(ix) => {
 998                        let mut missing_from_cache = true;
 999                        for id in &cached_excerpt_hints.ordered_hints[ix..] {
1000                            let cached_hint = &cached_excerpt_hints.hints_by_id[id];
1001                            if new_hint
1002                                .position
1003                                .cmp(&cached_hint.position, buffer_snapshot)
1004                                .is_gt()
1005                            {
1006                                break;
1007                            }
1008                            if cached_hint == &new_hint {
1009                                excerpt_hints_to_persist.insert(*id, cached_hint.kind);
1010                                missing_from_cache = false;
1011                            }
1012                        }
1013                        missing_from_cache
1014                    }
1015                    Err(_) => true,
1016                }
1017            }
1018            None => true,
1019        };
1020        if missing_from_cache {
1021            add_to_cache.push(new_hint);
1022        }
1023    }
1024
1025    let mut remove_from_visible = Vec::new();
1026    let mut remove_from_cache = HashSet::default();
1027    if invalidate {
1028        remove_from_visible.extend(
1029            visible_hints
1030                .iter()
1031                .filter(|hint| hint.position.excerpt_id == excerpt_id)
1032                .map(|inlay_hint| inlay_hint.id)
1033                .filter(|hint_id| !excerpt_hints_to_persist.contains_key(hint_id)),
1034        );
1035
1036        if let Some(cached_excerpt_hints) = &cached_excerpt_hints {
1037            let cached_excerpt_hints = cached_excerpt_hints.read();
1038            remove_from_cache.extend(
1039                cached_excerpt_hints
1040                    .ordered_hints
1041                    .iter()
1042                    .filter(|cached_inlay_id| {
1043                        !excerpt_hints_to_persist.contains_key(cached_inlay_id)
1044                    })
1045                    .copied(),
1046            );
1047        }
1048    }
1049
1050    if remove_from_visible.is_empty() && remove_from_cache.is_empty() && add_to_cache.is_empty() {
1051        None
1052    } else {
1053        Some(ExcerptHintsUpdate {
1054            excerpt_id,
1055            remove_from_visible,
1056            remove_from_cache,
1057            add_to_cache,
1058        })
1059    }
1060}
1061
1062fn contains_position(
1063    range: &Range<language::Anchor>,
1064    position: language::Anchor,
1065    buffer_snapshot: &BufferSnapshot,
1066) -> bool {
1067    range.start.cmp(&position, buffer_snapshot).is_le()
1068        && range.end.cmp(&position, buffer_snapshot).is_ge()
1069}
1070
1071fn apply_hint_update(
1072    editor: &mut Editor,
1073    new_update: ExcerptHintsUpdate,
1074    query: ExcerptQuery,
1075    invalidate: bool,
1076    buffer_snapshot: BufferSnapshot,
1077    multi_buffer_snapshot: MultiBufferSnapshot,
1078    cx: &mut ViewContext<'_, Editor>,
1079) {
1080    todo!("old implementation commented below")
1081}
1082//     let cached_excerpt_hints = editor
1083//         .inlay_hint_cache
1084//         .hints
1085//         .entry(new_update.excerpt_id)
1086//         .or_insert_with(|| {
1087//             Arc::new(RwLock::new(CachedExcerptHints {
1088//                 version: query.cache_version,
1089//                 buffer_version: buffer_snapshot.version().clone(),
1090//                 buffer_id: query.buffer_id,
1091//                 ordered_hints: Vec::new(),
1092//                 hints_by_id: HashMap::default(),
1093//             }))
1094//         });
1095//     let mut cached_excerpt_hints = cached_excerpt_hints.write();
1096//     match query.cache_version.cmp(&cached_excerpt_hints.version) {
1097//         cmp::Ordering::Less => return,
1098//         cmp::Ordering::Greater | cmp::Ordering::Equal => {
1099//             cached_excerpt_hints.version = query.cache_version;
1100//         }
1101//     }
1102
1103//     let mut cached_inlays_changed = !new_update.remove_from_cache.is_empty();
1104//     cached_excerpt_hints
1105//         .ordered_hints
1106//         .retain(|hint_id| !new_update.remove_from_cache.contains(hint_id));
1107//     cached_excerpt_hints
1108//         .hints_by_id
1109//         .retain(|hint_id, _| !new_update.remove_from_cache.contains(hint_id));
1110//     let mut splice = InlaySplice {
1111//         to_remove: new_update.remove_from_visible,
1112//         to_insert: Vec::new(),
1113//     };
1114//     for new_hint in new_update.add_to_cache {
1115//         let insert_position = match cached_excerpt_hints
1116//             .ordered_hints
1117//             .binary_search_by(|probe| {
1118//                 cached_excerpt_hints.hints_by_id[probe]
1119//                     .position
1120//                     .cmp(&new_hint.position, &buffer_snapshot)
1121//             }) {
1122//             Ok(i) => {
1123//                 let mut insert_position = Some(i);
1124//                 for id in &cached_excerpt_hints.ordered_hints[i..] {
1125//                     let cached_hint = &cached_excerpt_hints.hints_by_id[id];
1126//                     if new_hint
1127//                         .position
1128//                         .cmp(&cached_hint.position, &buffer_snapshot)
1129//                         .is_gt()
1130//                     {
1131//                         break;
1132//                     }
1133//                     if cached_hint.text() == new_hint.text() {
1134//                         insert_position = None;
1135//                         break;
1136//                     }
1137//                 }
1138//                 insert_position
1139//             }
1140//             Err(i) => Some(i),
1141//         };
1142
1143//         if let Some(insert_position) = insert_position {
1144//             let new_inlay_id = post_inc(&mut editor.next_inlay_id);
1145//             if editor
1146//                 .inlay_hint_cache
1147//                 .allowed_hint_kinds
1148//                 .contains(&new_hint.kind)
1149//             {
1150//                 let new_hint_position =
1151//                     multi_buffer_snapshot.anchor_in_excerpt(query.excerpt_id, new_hint.position);
1152//                 splice
1153//                     .to_insert
1154//                     .push(Inlay::hint(new_inlay_id, new_hint_position, &new_hint));
1155//             }
1156//             let new_id = InlayId::Hint(new_inlay_id);
1157//             cached_excerpt_hints.hints_by_id.insert(new_id, new_hint);
1158//             cached_excerpt_hints
1159//                 .ordered_hints
1160//                 .insert(insert_position, new_id);
1161//             cached_inlays_changed = true;
1162//         }
1163//     }
1164//     cached_excerpt_hints.buffer_version = buffer_snapshot.version().clone();
1165//     drop(cached_excerpt_hints);
1166
1167//     if invalidate {
1168//         let mut outdated_excerpt_caches = HashSet::default();
1169//         for (excerpt_id, excerpt_hints) in &editor.inlay_hint_cache().hints {
1170//             let excerpt_hints = excerpt_hints.read();
1171//             if excerpt_hints.buffer_id == query.buffer_id
1172//                 && excerpt_id != &query.excerpt_id
1173//                 && buffer_snapshot
1174//                     .version()
1175//                     .changed_since(&excerpt_hints.buffer_version)
1176//             {
1177//                 outdated_excerpt_caches.insert(*excerpt_id);
1178//                 splice
1179//                     .to_remove
1180//                     .extend(excerpt_hints.ordered_hints.iter().copied());
1181//             }
1182//         }
1183//         cached_inlays_changed |= !outdated_excerpt_caches.is_empty();
1184//         editor
1185//             .inlay_hint_cache
1186//             .hints
1187//             .retain(|excerpt_id, _| !outdated_excerpt_caches.contains(excerpt_id));
1188//     }
1189
1190//     let InlaySplice {
1191//         to_remove,
1192//         to_insert,
1193//     } = splice;
1194//     let displayed_inlays_changed = !to_remove.is_empty() || !to_insert.is_empty();
1195//     if cached_inlays_changed || displayed_inlays_changed {
1196//         editor.inlay_hint_cache.version += 1;
1197//     }
1198//     if displayed_inlays_changed {
1199//         editor.splice_inlay_hints(to_remove, to_insert, cx)
1200//     }
1201// }
1202
1203// #[cfg(test)]
1204// pub mod tests {
1205//     use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
1206
1207//     use crate::{
1208//         scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
1209//         serde_json::json,
1210//         ExcerptRange,
1211//     };
1212//     use futures::StreamExt;
1213//     use gpui::{executor::Deterministic, TestAppContext, View};
1214//     use itertools::Itertools;
1215//     use language::{
1216//         language_settings::AllLanguageSettingsContent, FakeLspAdapter, Language, LanguageConfig,
1217//     };
1218//     use lsp::FakeLanguageServer;
1219//     use parking_lot::Mutex;
1220//     use project::{FakeFs, Project};
1221//     use settings::SettingsStore;
1222//     use text::{Point, ToPoint};
1223//     use workspace::Workspace;
1224
1225//     use crate::editor_tests::update_test_language_settings;
1226
1227//     use super::*;
1228
1229//     #[gpui::test]
1230//     async fn test_basic_cache_update_with_duplicate_hints(cx: &mut gpui::TestAppContext) {
1231//         let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
1232//         init_test(cx, |settings| {
1233//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1234//                 enabled: true,
1235//                 show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
1236//                 show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
1237//                 show_other_hints: allowed_hint_kinds.contains(&None),
1238//             })
1239//         });
1240
1241//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
1242//         let lsp_request_count = Arc::new(AtomicU32::new(0));
1243//         fake_server
1244//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
1245//                 let task_lsp_request_count = Arc::clone(&lsp_request_count);
1246//                 async move {
1247//                     assert_eq!(
1248//                         params.text_document.uri,
1249//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
1250//                     );
1251//                     let current_call_id =
1252//                         Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
1253//                     let mut new_hints = Vec::with_capacity(2 * current_call_id as usize);
1254//                     for _ in 0..2 {
1255//                         let mut i = current_call_id;
1256//                         loop {
1257//                             new_hints.push(lsp::InlayHint {
1258//                                 position: lsp::Position::new(0, i),
1259//                                 label: lsp::InlayHintLabel::String(i.to_string()),
1260//                                 kind: None,
1261//                                 text_edits: None,
1262//                                 tooltip: None,
1263//                                 padding_left: None,
1264//                                 padding_right: None,
1265//                                 data: None,
1266//                             });
1267//                             if i == 0 {
1268//                                 break;
1269//                             }
1270//                             i -= 1;
1271//                         }
1272//                     }
1273
1274//                     Ok(Some(new_hints))
1275//                 }
1276//             })
1277//             .next()
1278//             .await;
1279//         cx.foreground().run_until_parked();
1280
1281//         let mut edits_made = 1;
1282//         editor.update(cx, |editor, cx| {
1283//             let expected_hints = vec!["0".to_string()];
1284//             assert_eq!(
1285//                 expected_hints,
1286//                 cached_hint_labels(editor),
1287//                 "Should get its first hints when opening the editor"
1288//             );
1289//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1290//             let inlay_cache = editor.inlay_hint_cache();
1291//             assert_eq!(
1292//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
1293//                 "Cache should use editor settings to get the allowed hint kinds"
1294//             );
1295//             assert_eq!(
1296//                 inlay_cache.version, edits_made,
1297//                 "The editor update the cache version after every cache/view change"
1298//             );
1299//         });
1300
1301//         editor.update(cx, |editor, cx| {
1302//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
1303//             editor.handle_input("some change", cx);
1304//             edits_made += 1;
1305//         });
1306//         cx.foreground().run_until_parked();
1307//         editor.update(cx, |editor, cx| {
1308//             let expected_hints = vec!["0".to_string(), "1".to_string()];
1309//             assert_eq!(
1310//                 expected_hints,
1311//                 cached_hint_labels(editor),
1312//                 "Should get new hints after an edit"
1313//             );
1314//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1315//             let inlay_cache = editor.inlay_hint_cache();
1316//             assert_eq!(
1317//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
1318//                 "Cache should use editor settings to get the allowed hint kinds"
1319//             );
1320//             assert_eq!(
1321//                 inlay_cache.version, edits_made,
1322//                 "The editor update the cache version after every cache/view change"
1323//             );
1324//         });
1325
1326//         fake_server
1327//             .request::<lsp::request::InlayHintRefreshRequest>(())
1328//             .await
1329//             .expect("inlay refresh request failed");
1330//         edits_made += 1;
1331//         cx.foreground().run_until_parked();
1332//         editor.update(cx, |editor, cx| {
1333//             let expected_hints = vec!["0".to_string(), "1".to_string(), "2".to_string()];
1334//             assert_eq!(
1335//                 expected_hints,
1336//                 cached_hint_labels(editor),
1337//                 "Should get new hints after hint refresh/ request"
1338//             );
1339//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1340//             let inlay_cache = editor.inlay_hint_cache();
1341//             assert_eq!(
1342//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
1343//                 "Cache should use editor settings to get the allowed hint kinds"
1344//             );
1345//             assert_eq!(
1346//                 inlay_cache.version, edits_made,
1347//                 "The editor update the cache version after every cache/view change"
1348//             );
1349//         });
1350//     }
1351
1352//     #[gpui::test]
1353//     async fn test_cache_update_on_lsp_completion_tasks(cx: &mut gpui::TestAppContext) {
1354//         init_test(cx, |settings| {
1355//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1356//                 enabled: true,
1357//                 show_type_hints: true,
1358//                 show_parameter_hints: true,
1359//                 show_other_hints: true,
1360//             })
1361//         });
1362
1363//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
1364//         let lsp_request_count = Arc::new(AtomicU32::new(0));
1365//         fake_server
1366//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
1367//                 let task_lsp_request_count = Arc::clone(&lsp_request_count);
1368//                 async move {
1369//                     assert_eq!(
1370//                         params.text_document.uri,
1371//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
1372//                     );
1373//                     let current_call_id =
1374//                         Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
1375//                     Ok(Some(vec![lsp::InlayHint {
1376//                         position: lsp::Position::new(0, current_call_id),
1377//                         label: lsp::InlayHintLabel::String(current_call_id.to_string()),
1378//                         kind: None,
1379//                         text_edits: None,
1380//                         tooltip: None,
1381//                         padding_left: None,
1382//                         padding_right: None,
1383//                         data: None,
1384//                     }]))
1385//                 }
1386//             })
1387//             .next()
1388//             .await;
1389//         cx.foreground().run_until_parked();
1390
1391//         let mut edits_made = 1;
1392//         editor.update(cx, |editor, cx| {
1393//             let expected_hints = vec!["0".to_string()];
1394//             assert_eq!(
1395//                 expected_hints,
1396//                 cached_hint_labels(editor),
1397//                 "Should get its first hints when opening the editor"
1398//             );
1399//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1400//             assert_eq!(
1401//                 editor.inlay_hint_cache().version,
1402//                 edits_made,
1403//                 "The editor update the cache version after every cache/view change"
1404//             );
1405//         });
1406
1407//         let progress_token = "test_progress_token";
1408//         fake_server
1409//             .request::<lsp::request::WorkDoneProgressCreate>(lsp::WorkDoneProgressCreateParams {
1410//                 token: lsp::ProgressToken::String(progress_token.to_string()),
1411//             })
1412//             .await
1413//             .expect("work done progress create request failed");
1414//         cx.foreground().run_until_parked();
1415//         fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
1416//             token: lsp::ProgressToken::String(progress_token.to_string()),
1417//             value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::Begin(
1418//                 lsp::WorkDoneProgressBegin::default(),
1419//             )),
1420//         });
1421//         cx.foreground().run_until_parked();
1422
1423//         editor.update(cx, |editor, cx| {
1424//             let expected_hints = vec!["0".to_string()];
1425//             assert_eq!(
1426//                 expected_hints,
1427//                 cached_hint_labels(editor),
1428//                 "Should not update hints while the work task is running"
1429//             );
1430//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1431//             assert_eq!(
1432//                 editor.inlay_hint_cache().version,
1433//                 edits_made,
1434//                 "Should not update the cache while the work task is running"
1435//             );
1436//         });
1437
1438//         fake_server.notify::<lsp::notification::Progress>(lsp::ProgressParams {
1439//             token: lsp::ProgressToken::String(progress_token.to_string()),
1440//             value: lsp::ProgressParamsValue::WorkDone(lsp::WorkDoneProgress::End(
1441//                 lsp::WorkDoneProgressEnd::default(),
1442//             )),
1443//         });
1444//         cx.foreground().run_until_parked();
1445
1446//         edits_made += 1;
1447//         editor.update(cx, |editor, cx| {
1448//             let expected_hints = vec!["1".to_string()];
1449//             assert_eq!(
1450//                 expected_hints,
1451//                 cached_hint_labels(editor),
1452//                 "New hints should be queried after the work task is done"
1453//             );
1454//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1455//             assert_eq!(
1456//                 editor.inlay_hint_cache().version,
1457//                 edits_made,
1458//                 "Cache version should udpate once after the work task is done"
1459//             );
1460//         });
1461//     }
1462
1463//     #[gpui::test]
1464//     async fn test_no_hint_updates_for_unrelated_language_files(cx: &mut gpui::TestAppContext) {
1465//         init_test(cx, |settings| {
1466//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1467//                 enabled: true,
1468//                 show_type_hints: true,
1469//                 show_parameter_hints: true,
1470//                 show_other_hints: true,
1471//             })
1472//         });
1473
1474//         let fs = FakeFs::new(cx.background());
1475//         fs.insert_tree(
1476//                     "/a",
1477//                     json!({
1478//                         "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
1479//                         "other.md": "Test md file with some text",
1480//                     }),
1481//                 )
1482//                 .await;
1483//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
1484//         let workspace = cx
1485//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
1486//             .root(cx);
1487//         let worktree_id = workspace.update(cx, |workspace, cx| {
1488//             workspace.project().read_with(cx, |project, cx| {
1489//                 project.worktrees(cx).next().unwrap().read(cx).id()
1490//             })
1491//         });
1492
1493//         let mut rs_fake_servers = None;
1494//         let mut md_fake_servers = None;
1495//         for (name, path_suffix) in [("Rust", "rs"), ("Markdown", "md")] {
1496//             let mut language = Language::new(
1497//                 LanguageConfig {
1498//                     name: name.into(),
1499//                     path_suffixes: vec![path_suffix.to_string()],
1500//                     ..Default::default()
1501//                 },
1502//                 Some(tree_sitter_rust::language()),
1503//             );
1504//             let fake_servers = language
1505//                 .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
1506//                     name,
1507//                     capabilities: lsp::ServerCapabilities {
1508//                         inlay_hint_provider: Some(lsp::OneOf::Left(true)),
1509//                         ..Default::default()
1510//                     },
1511//                     ..Default::default()
1512//                 }))
1513//                 .await;
1514//             match name {
1515//                 "Rust" => rs_fake_servers = Some(fake_servers),
1516//                 "Markdown" => md_fake_servers = Some(fake_servers),
1517//                 _ => unreachable!(),
1518//             }
1519//             project.update(cx, |project, _| {
1520//                 project.languages().add(Arc::new(language));
1521//             });
1522//         }
1523
1524//         let _rs_buffer = project
1525//             .update(cx, |project, cx| {
1526//                 project.open_local_buffer("/a/main.rs", cx)
1527//             })
1528//             .await
1529//             .unwrap();
1530//         cx.foreground().run_until_parked();
1531//         cx.foreground().start_waiting();
1532//         let rs_fake_server = rs_fake_servers.unwrap().next().await.unwrap();
1533//         let rs_editor = workspace
1534//             .update(cx, |workspace, cx| {
1535//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
1536//             })
1537//             .await
1538//             .unwrap()
1539//             .downcast::<Editor>()
1540//             .unwrap();
1541//         let rs_lsp_request_count = Arc::new(AtomicU32::new(0));
1542//         rs_fake_server
1543//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
1544//                 let task_lsp_request_count = Arc::clone(&rs_lsp_request_count);
1545//                 async move {
1546//                     assert_eq!(
1547//                         params.text_document.uri,
1548//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
1549//                     );
1550//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
1551//                     Ok(Some(vec![lsp::InlayHint {
1552//                         position: lsp::Position::new(0, i),
1553//                         label: lsp::InlayHintLabel::String(i.to_string()),
1554//                         kind: None,
1555//                         text_edits: None,
1556//                         tooltip: None,
1557//                         padding_left: None,
1558//                         padding_right: None,
1559//                         data: None,
1560//                     }]))
1561//                 }
1562//             })
1563//             .next()
1564//             .await;
1565//         cx.foreground().run_until_parked();
1566//         rs_editor.update(cx, |editor, cx| {
1567//             let expected_hints = vec!["0".to_string()];
1568//             assert_eq!(
1569//                 expected_hints,
1570//                 cached_hint_labels(editor),
1571//                 "Should get its first hints when opening the editor"
1572//             );
1573//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1574//             assert_eq!(
1575//                 editor.inlay_hint_cache().version,
1576//                 1,
1577//                 "Rust editor update the cache version after every cache/view change"
1578//             );
1579//         });
1580
1581//         cx.foreground().run_until_parked();
1582//         let _md_buffer = project
1583//             .update(cx, |project, cx| {
1584//                 project.open_local_buffer("/a/other.md", cx)
1585//             })
1586//             .await
1587//             .unwrap();
1588//         cx.foreground().run_until_parked();
1589//         cx.foreground().start_waiting();
1590//         let md_fake_server = md_fake_servers.unwrap().next().await.unwrap();
1591//         let md_editor = workspace
1592//             .update(cx, |workspace, cx| {
1593//                 workspace.open_path((worktree_id, "other.md"), None, true, cx)
1594//             })
1595//             .await
1596//             .unwrap()
1597//             .downcast::<Editor>()
1598//             .unwrap();
1599//         let md_lsp_request_count = Arc::new(AtomicU32::new(0));
1600//         md_fake_server
1601//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
1602//                 let task_lsp_request_count = Arc::clone(&md_lsp_request_count);
1603//                 async move {
1604//                     assert_eq!(
1605//                         params.text_document.uri,
1606//                         lsp::Url::from_file_path("/a/other.md").unwrap(),
1607//                     );
1608//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
1609//                     Ok(Some(vec![lsp::InlayHint {
1610//                         position: lsp::Position::new(0, i),
1611//                         label: lsp::InlayHintLabel::String(i.to_string()),
1612//                         kind: None,
1613//                         text_edits: None,
1614//                         tooltip: None,
1615//                         padding_left: None,
1616//                         padding_right: None,
1617//                         data: None,
1618//                     }]))
1619//                 }
1620//             })
1621//             .next()
1622//             .await;
1623//         cx.foreground().run_until_parked();
1624//         md_editor.update(cx, |editor, cx| {
1625//             let expected_hints = vec!["0".to_string()];
1626//             assert_eq!(
1627//                 expected_hints,
1628//                 cached_hint_labels(editor),
1629//                 "Markdown editor should have a separate verison, repeating Rust editor rules"
1630//             );
1631//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1632//             assert_eq!(editor.inlay_hint_cache().version, 1);
1633//         });
1634
1635//         rs_editor.update(cx, |editor, cx| {
1636//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
1637//             editor.handle_input("some rs change", cx);
1638//         });
1639//         cx.foreground().run_until_parked();
1640//         rs_editor.update(cx, |editor, cx| {
1641//             let expected_hints = vec!["1".to_string()];
1642//             assert_eq!(
1643//                 expected_hints,
1644//                 cached_hint_labels(editor),
1645//                 "Rust inlay cache should change after the edit"
1646//             );
1647//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1648//             assert_eq!(
1649//                 editor.inlay_hint_cache().version,
1650//                 2,
1651//                 "Every time hint cache changes, cache version should be incremented"
1652//             );
1653//         });
1654//         md_editor.update(cx, |editor, cx| {
1655//             let expected_hints = vec!["0".to_string()];
1656//             assert_eq!(
1657//                 expected_hints,
1658//                 cached_hint_labels(editor),
1659//                 "Markdown editor should not be affected by Rust editor changes"
1660//             );
1661//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1662//             assert_eq!(editor.inlay_hint_cache().version, 1);
1663//         });
1664
1665//         md_editor.update(cx, |editor, cx| {
1666//             editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
1667//             editor.handle_input("some md change", cx);
1668//         });
1669//         cx.foreground().run_until_parked();
1670//         md_editor.update(cx, |editor, cx| {
1671//             let expected_hints = vec!["1".to_string()];
1672//             assert_eq!(
1673//                 expected_hints,
1674//                 cached_hint_labels(editor),
1675//                 "Rust editor should not be affected by Markdown editor changes"
1676//             );
1677//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1678//             assert_eq!(editor.inlay_hint_cache().version, 2);
1679//         });
1680//         rs_editor.update(cx, |editor, cx| {
1681//             let expected_hints = vec!["1".to_string()];
1682//             assert_eq!(
1683//                 expected_hints,
1684//                 cached_hint_labels(editor),
1685//                 "Markdown editor should also change independently"
1686//             );
1687//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
1688//             assert_eq!(editor.inlay_hint_cache().version, 2);
1689//         });
1690//     }
1691
1692//     #[gpui::test]
1693//     async fn test_hint_setting_changes(cx: &mut gpui::TestAppContext) {
1694//         let allowed_hint_kinds = HashSet::from_iter([None, Some(InlayHintKind::Type)]);
1695//         init_test(cx, |settings| {
1696//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1697//                 enabled: true,
1698//                 show_type_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
1699//                 show_parameter_hints: allowed_hint_kinds.contains(&Some(InlayHintKind::Parameter)),
1700//                 show_other_hints: allowed_hint_kinds.contains(&None),
1701//             })
1702//         });
1703
1704//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
1705//         let lsp_request_count = Arc::new(AtomicU32::new(0));
1706//         let another_lsp_request_count = Arc::clone(&lsp_request_count);
1707//         fake_server
1708//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
1709//                 let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
1710//                 async move {
1711//                     Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst);
1712//                     assert_eq!(
1713//                         params.text_document.uri,
1714//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
1715//                     );
1716//                     Ok(Some(vec![
1717//                         lsp::InlayHint {
1718//                             position: lsp::Position::new(0, 1),
1719//                             label: lsp::InlayHintLabel::String("type hint".to_string()),
1720//                             kind: Some(lsp::InlayHintKind::TYPE),
1721//                             text_edits: None,
1722//                             tooltip: None,
1723//                             padding_left: None,
1724//                             padding_right: None,
1725//                             data: None,
1726//                         },
1727//                         lsp::InlayHint {
1728//                             position: lsp::Position::new(0, 2),
1729//                             label: lsp::InlayHintLabel::String("parameter hint".to_string()),
1730//                             kind: Some(lsp::InlayHintKind::PARAMETER),
1731//                             text_edits: None,
1732//                             tooltip: None,
1733//                             padding_left: None,
1734//                             padding_right: None,
1735//                             data: None,
1736//                         },
1737//                         lsp::InlayHint {
1738//                             position: lsp::Position::new(0, 3),
1739//                             label: lsp::InlayHintLabel::String("other hint".to_string()),
1740//                             kind: None,
1741//                             text_edits: None,
1742//                             tooltip: None,
1743//                             padding_left: None,
1744//                             padding_right: None,
1745//                             data: None,
1746//                         },
1747//                     ]))
1748//                 }
1749//             })
1750//             .next()
1751//             .await;
1752//         cx.foreground().run_until_parked();
1753
1754//         let mut edits_made = 1;
1755//         editor.update(cx, |editor, cx| {
1756//             assert_eq!(
1757//                 lsp_request_count.load(Ordering::Relaxed),
1758//                 1,
1759//                 "Should query new hints once"
1760//             );
1761//             assert_eq!(
1762//                 vec![
1763//                     "other hint".to_string(),
1764//                     "parameter hint".to_string(),
1765//                     "type hint".to_string(),
1766//                 ],
1767//                 cached_hint_labels(editor),
1768//                 "Should get its first hints when opening the editor"
1769//             );
1770//             assert_eq!(
1771//                 vec!["other hint".to_string(), "type hint".to_string()],
1772//                 visible_hint_labels(editor, cx)
1773//             );
1774//             let inlay_cache = editor.inlay_hint_cache();
1775//             assert_eq!(
1776//                 inlay_cache.allowed_hint_kinds, allowed_hint_kinds,
1777//                 "Cache should use editor settings to get the allowed hint kinds"
1778//             );
1779//             assert_eq!(
1780//                 inlay_cache.version, edits_made,
1781//                 "The editor update the cache version after every cache/view change"
1782//             );
1783//         });
1784
1785//         fake_server
1786//             .request::<lsp::request::InlayHintRefreshRequest>(())
1787//             .await
1788//             .expect("inlay refresh request failed");
1789//         cx.foreground().run_until_parked();
1790//         editor.update(cx, |editor, cx| {
1791//             assert_eq!(
1792//                 lsp_request_count.load(Ordering::Relaxed),
1793//                 2,
1794//                 "Should load new hints twice"
1795//             );
1796//             assert_eq!(
1797//                 vec![
1798//                     "other hint".to_string(),
1799//                     "parameter hint".to_string(),
1800//                     "type hint".to_string(),
1801//                 ],
1802//                 cached_hint_labels(editor),
1803//                 "Cached hints should not change due to allowed hint kinds settings update"
1804//             );
1805//             assert_eq!(
1806//                 vec!["other hint".to_string(), "type hint".to_string()],
1807//                 visible_hint_labels(editor, cx)
1808//             );
1809//             assert_eq!(
1810//                 editor.inlay_hint_cache().version,
1811//                 edits_made,
1812//                 "Should not update cache version due to new loaded hints being the same"
1813//             );
1814//         });
1815
1816//         for (new_allowed_hint_kinds, expected_visible_hints) in [
1817//             (HashSet::from_iter([None]), vec!["other hint".to_string()]),
1818//             (
1819//                 HashSet::from_iter([Some(InlayHintKind::Type)]),
1820//                 vec!["type hint".to_string()],
1821//             ),
1822//             (
1823//                 HashSet::from_iter([Some(InlayHintKind::Parameter)]),
1824//                 vec!["parameter hint".to_string()],
1825//             ),
1826//             (
1827//                 HashSet::from_iter([None, Some(InlayHintKind::Type)]),
1828//                 vec!["other hint".to_string(), "type hint".to_string()],
1829//             ),
1830//             (
1831//                 HashSet::from_iter([None, Some(InlayHintKind::Parameter)]),
1832//                 vec!["other hint".to_string(), "parameter hint".to_string()],
1833//             ),
1834//             (
1835//                 HashSet::from_iter([Some(InlayHintKind::Type), Some(InlayHintKind::Parameter)]),
1836//                 vec!["parameter hint".to_string(), "type hint".to_string()],
1837//             ),
1838//             (
1839//                 HashSet::from_iter([
1840//                     None,
1841//                     Some(InlayHintKind::Type),
1842//                     Some(InlayHintKind::Parameter),
1843//                 ]),
1844//                 vec![
1845//                     "other hint".to_string(),
1846//                     "parameter hint".to_string(),
1847//                     "type hint".to_string(),
1848//                 ],
1849//             ),
1850//         ] {
1851//             edits_made += 1;
1852//             update_test_language_settings(cx, |settings| {
1853//                 settings.defaults.inlay_hints = Some(InlayHintSettings {
1854//                     enabled: true,
1855//                     show_type_hints: new_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
1856//                     show_parameter_hints: new_allowed_hint_kinds
1857//                         .contains(&Some(InlayHintKind::Parameter)),
1858//                     show_other_hints: new_allowed_hint_kinds.contains(&None),
1859//                 })
1860//             });
1861//             cx.foreground().run_until_parked();
1862//             editor.update(cx, |editor, cx| {
1863//                 assert_eq!(
1864//                     lsp_request_count.load(Ordering::Relaxed),
1865//                     2,
1866//                     "Should not load new hints on allowed hint kinds change for hint kinds {new_allowed_hint_kinds:?}"
1867//                 );
1868//                 assert_eq!(
1869//                     vec![
1870//                         "other hint".to_string(),
1871//                         "parameter hint".to_string(),
1872//                         "type hint".to_string(),
1873//                     ],
1874//                     cached_hint_labels(editor),
1875//                     "Should get its cached hints unchanged after the settings change for hint kinds {new_allowed_hint_kinds:?}"
1876//                 );
1877//                 assert_eq!(
1878//                     expected_visible_hints,
1879//                     visible_hint_labels(editor, cx),
1880//                     "Should get its visible hints filtered after the settings change for hint kinds {new_allowed_hint_kinds:?}"
1881//                 );
1882//                 let inlay_cache = editor.inlay_hint_cache();
1883//                 assert_eq!(
1884//                     inlay_cache.allowed_hint_kinds, new_allowed_hint_kinds,
1885//                     "Cache should use editor settings to get the allowed hint kinds for hint kinds {new_allowed_hint_kinds:?}"
1886//                 );
1887//                 assert_eq!(
1888//                     inlay_cache.version, edits_made,
1889//                     "The editor should update the cache version after every cache/view change for hint kinds {new_allowed_hint_kinds:?} due to visible hints change"
1890//                 );
1891//             });
1892//         }
1893
1894//         edits_made += 1;
1895//         let another_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Type)]);
1896//         update_test_language_settings(cx, |settings| {
1897//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1898//                 enabled: false,
1899//                 show_type_hints: another_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
1900//                 show_parameter_hints: another_allowed_hint_kinds
1901//                     .contains(&Some(InlayHintKind::Parameter)),
1902//                 show_other_hints: another_allowed_hint_kinds.contains(&None),
1903//             })
1904//         });
1905//         cx.foreground().run_until_parked();
1906//         editor.update(cx, |editor, cx| {
1907//             assert_eq!(
1908//                 lsp_request_count.load(Ordering::Relaxed),
1909//                 2,
1910//                 "Should not load new hints when hints got disabled"
1911//             );
1912//             assert!(
1913//                 cached_hint_labels(editor).is_empty(),
1914//                 "Should clear the cache when hints got disabled"
1915//             );
1916//             assert!(
1917//                 visible_hint_labels(editor, cx).is_empty(),
1918//                 "Should clear visible hints when hints got disabled"
1919//             );
1920//             let inlay_cache = editor.inlay_hint_cache();
1921//             assert_eq!(
1922//                 inlay_cache.allowed_hint_kinds, another_allowed_hint_kinds,
1923//                 "Should update its allowed hint kinds even when hints got disabled"
1924//             );
1925//             assert_eq!(
1926//                 inlay_cache.version, edits_made,
1927//                 "The editor should update the cache version after hints got disabled"
1928//             );
1929//         });
1930
1931//         fake_server
1932//             .request::<lsp::request::InlayHintRefreshRequest>(())
1933//             .await
1934//             .expect("inlay refresh request failed");
1935//         cx.foreground().run_until_parked();
1936//         editor.update(cx, |editor, cx| {
1937//             assert_eq!(
1938//                 lsp_request_count.load(Ordering::Relaxed),
1939//                 2,
1940//                 "Should not load new hints when they got disabled"
1941//             );
1942//             assert!(cached_hint_labels(editor).is_empty());
1943//             assert!(visible_hint_labels(editor, cx).is_empty());
1944//             assert_eq!(
1945//                 editor.inlay_hint_cache().version, edits_made,
1946//                 "The editor should not update the cache version after /refresh query without updates"
1947//             );
1948//         });
1949
1950//         let final_allowed_hint_kinds = HashSet::from_iter([Some(InlayHintKind::Parameter)]);
1951//         edits_made += 1;
1952//         update_test_language_settings(cx, |settings| {
1953//             settings.defaults.inlay_hints = Some(InlayHintSettings {
1954//                 enabled: true,
1955//                 show_type_hints: final_allowed_hint_kinds.contains(&Some(InlayHintKind::Type)),
1956//                 show_parameter_hints: final_allowed_hint_kinds
1957//                     .contains(&Some(InlayHintKind::Parameter)),
1958//                 show_other_hints: final_allowed_hint_kinds.contains(&None),
1959//             })
1960//         });
1961//         cx.foreground().run_until_parked();
1962//         editor.update(cx, |editor, cx| {
1963//             assert_eq!(
1964//                 lsp_request_count.load(Ordering::Relaxed),
1965//                 3,
1966//                 "Should query for new hints when they got reenabled"
1967//             );
1968//             assert_eq!(
1969//                 vec![
1970//                     "other hint".to_string(),
1971//                     "parameter hint".to_string(),
1972//                     "type hint".to_string(),
1973//                 ],
1974//                 cached_hint_labels(editor),
1975//                 "Should get its cached hints fully repopulated after the hints got reenabled"
1976//             );
1977//             assert_eq!(
1978//                 vec!["parameter hint".to_string()],
1979//                 visible_hint_labels(editor, cx),
1980//                 "Should get its visible hints repopulated and filtered after the h"
1981//             );
1982//             let inlay_cache = editor.inlay_hint_cache();
1983//             assert_eq!(
1984//                 inlay_cache.allowed_hint_kinds, final_allowed_hint_kinds,
1985//                 "Cache should update editor settings when hints got reenabled"
1986//             );
1987//             assert_eq!(
1988//                 inlay_cache.version, edits_made,
1989//                 "Cache should update its version after hints got reenabled"
1990//             );
1991//         });
1992
1993//         fake_server
1994//             .request::<lsp::request::InlayHintRefreshRequest>(())
1995//             .await
1996//             .expect("inlay refresh request failed");
1997//         cx.foreground().run_until_parked();
1998//         editor.update(cx, |editor, cx| {
1999//             assert_eq!(
2000//                 lsp_request_count.load(Ordering::Relaxed),
2001//                 4,
2002//                 "Should query for new hints again"
2003//             );
2004//             assert_eq!(
2005//                 vec![
2006//                     "other hint".to_string(),
2007//                     "parameter hint".to_string(),
2008//                     "type hint".to_string(),
2009//                 ],
2010//                 cached_hint_labels(editor),
2011//             );
2012//             assert_eq!(
2013//                 vec!["parameter hint".to_string()],
2014//                 visible_hint_labels(editor, cx),
2015//             );
2016//             assert_eq!(editor.inlay_hint_cache().version, edits_made);
2017//         });
2018//     }
2019
2020//     #[gpui::test]
2021//     async fn test_hint_request_cancellation(cx: &mut gpui::TestAppContext) {
2022//         init_test(cx, |settings| {
2023//             settings.defaults.inlay_hints = Some(InlayHintSettings {
2024//                 enabled: true,
2025//                 show_type_hints: true,
2026//                 show_parameter_hints: true,
2027//                 show_other_hints: true,
2028//             })
2029//         });
2030
2031//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
2032//         let fake_server = Arc::new(fake_server);
2033//         let lsp_request_count = Arc::new(AtomicU32::new(0));
2034//         let another_lsp_request_count = Arc::clone(&lsp_request_count);
2035//         fake_server
2036//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
2037//                 let task_lsp_request_count = Arc::clone(&another_lsp_request_count);
2038//                 async move {
2039//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
2040//                     assert_eq!(
2041//                         params.text_document.uri,
2042//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
2043//                     );
2044//                     Ok(Some(vec![lsp::InlayHint {
2045//                         position: lsp::Position::new(0, i),
2046//                         label: lsp::InlayHintLabel::String(i.to_string()),
2047//                         kind: None,
2048//                         text_edits: None,
2049//                         tooltip: None,
2050//                         padding_left: None,
2051//                         padding_right: None,
2052//                         data: None,
2053//                     }]))
2054//                 }
2055//             })
2056//             .next()
2057//             .await;
2058
2059//         let mut expected_changes = Vec::new();
2060//         for change_after_opening in [
2061//             "initial change #1",
2062//             "initial change #2",
2063//             "initial change #3",
2064//         ] {
2065//             editor.update(cx, |editor, cx| {
2066//                 editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
2067//                 editor.handle_input(change_after_opening, cx);
2068//             });
2069//             expected_changes.push(change_after_opening);
2070//         }
2071
2072//         cx.foreground().run_until_parked();
2073
2074//         editor.update(cx, |editor, cx| {
2075//             let current_text = editor.text(cx);
2076//             for change in &expected_changes {
2077//                 assert!(
2078//                     current_text.contains(change),
2079//                     "Should apply all changes made"
2080//                 );
2081//             }
2082//             assert_eq!(
2083//                 lsp_request_count.load(Ordering::Relaxed),
2084//                 2,
2085//                 "Should query new hints twice: for editor init and for the last edit that interrupted all others"
2086//             );
2087//             let expected_hints = vec!["2".to_string()];
2088//             assert_eq!(
2089//                 expected_hints,
2090//                 cached_hint_labels(editor),
2091//                 "Should get hints from the last edit landed only"
2092//             );
2093//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2094//             assert_eq!(
2095//                 editor.inlay_hint_cache().version, 1,
2096//                 "Only one update should be registered in the cache after all cancellations"
2097//             );
2098//         });
2099
2100//         let mut edits = Vec::new();
2101//         for async_later_change in [
2102//             "another change #1",
2103//             "another change #2",
2104//             "another change #3",
2105//         ] {
2106//             expected_changes.push(async_later_change);
2107//             let task_editor = editor.clone();
2108//             let mut task_cx = cx.clone();
2109//             edits.push(cx.foreground().spawn(async move {
2110//                 task_editor.update(&mut task_cx, |editor, cx| {
2111//                     editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
2112//                     editor.handle_input(async_later_change, cx);
2113//                 });
2114//             }));
2115//         }
2116//         let _ = future::join_all(edits).await;
2117//         cx.foreground().run_until_parked();
2118
2119//         editor.update(cx, |editor, cx| {
2120//             let current_text = editor.text(cx);
2121//             for change in &expected_changes {
2122//                 assert!(
2123//                     current_text.contains(change),
2124//                     "Should apply all changes made"
2125//                 );
2126//             }
2127//             assert_eq!(
2128//                 lsp_request_count.load(Ordering::SeqCst),
2129//                 3,
2130//                 "Should query new hints one more time, for the last edit only"
2131//             );
2132//             let expected_hints = vec!["3".to_string()];
2133//             assert_eq!(
2134//                 expected_hints,
2135//                 cached_hint_labels(editor),
2136//                 "Should get hints from the last edit landed only"
2137//             );
2138//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2139//             assert_eq!(
2140//                 editor.inlay_hint_cache().version,
2141//                 2,
2142//                 "Should update the cache version once more, for the new change"
2143//             );
2144//         });
2145//     }
2146
2147//     #[gpui::test(iterations = 10)]
2148//     async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) {
2149//         init_test(cx, |settings| {
2150//             settings.defaults.inlay_hints = Some(InlayHintSettings {
2151//                 enabled: true,
2152//                 show_type_hints: true,
2153//                 show_parameter_hints: true,
2154//                 show_other_hints: true,
2155//             })
2156//         });
2157
2158//         let mut language = Language::new(
2159//             LanguageConfig {
2160//                 name: "Rust".into(),
2161//                 path_suffixes: vec!["rs".to_string()],
2162//                 ..Default::default()
2163//             },
2164//             Some(tree_sitter_rust::language()),
2165//         );
2166//         let mut fake_servers = language
2167//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
2168//                 capabilities: lsp::ServerCapabilities {
2169//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
2170//                     ..Default::default()
2171//                 },
2172//                 ..Default::default()
2173//             }))
2174//             .await;
2175//         let fs = FakeFs::new(cx.background());
2176//         fs.insert_tree(
2177//             "/a",
2178//             json!({
2179//                 "main.rs": format!("fn main() {{\n{}\n}}", "let i = 5;\n".repeat(500)),
2180//                 "other.rs": "// Test file",
2181//             }),
2182//         )
2183//         .await;
2184//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
2185//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
2186//         let workspace = cx
2187//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
2188//             .root(cx);
2189//         let worktree_id = workspace.update(cx, |workspace, cx| {
2190//             workspace.project().read_with(cx, |project, cx| {
2191//                 project.worktrees(cx).next().unwrap().read(cx).id()
2192//             })
2193//         });
2194
2195//         let _buffer = project
2196//             .update(cx, |project, cx| {
2197//                 project.open_local_buffer("/a/main.rs", cx)
2198//             })
2199//             .await
2200//             .unwrap();
2201//         cx.foreground().run_until_parked();
2202//         cx.foreground().start_waiting();
2203//         let fake_server = fake_servers.next().await.unwrap();
2204//         let editor = workspace
2205//             .update(cx, |workspace, cx| {
2206//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
2207//             })
2208//             .await
2209//             .unwrap()
2210//             .downcast::<Editor>()
2211//             .unwrap();
2212//         let lsp_request_ranges = Arc::new(Mutex::new(Vec::new()));
2213//         let lsp_request_count = Arc::new(AtomicUsize::new(0));
2214//         let closure_lsp_request_ranges = Arc::clone(&lsp_request_ranges);
2215//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
2216//         fake_server
2217//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
2218//                 let task_lsp_request_ranges = Arc::clone(&closure_lsp_request_ranges);
2219//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
2220//                 async move {
2221//                     assert_eq!(
2222//                         params.text_document.uri,
2223//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
2224//                     );
2225
2226//                     task_lsp_request_ranges.lock().push(params.range);
2227//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
2228//                     Ok(Some(vec![lsp::InlayHint {
2229//                         position: params.range.end,
2230//                         label: lsp::InlayHintLabel::String(i.to_string()),
2231//                         kind: None,
2232//                         text_edits: None,
2233//                         tooltip: None,
2234//                         padding_left: None,
2235//                         padding_right: None,
2236//                         data: None,
2237//                     }]))
2238//                 }
2239//             })
2240//             .next()
2241//             .await;
2242//         fn editor_visible_range(
2243//             editor: &ViewHandle<Editor>,
2244//             cx: &mut gpui::TestAppContext,
2245//         ) -> Range<Point> {
2246//             let ranges = editor.update(cx, |editor, cx| editor.excerpt_visible_offsets(None, cx));
2247//             assert_eq!(
2248//                 ranges.len(),
2249//                 1,
2250//                 "Single buffer should produce a single excerpt with visible range"
2251//             );
2252//             let (_, (excerpt_buffer, _, excerpt_visible_range)) =
2253//                 ranges.into_iter().next().unwrap();
2254//             excerpt_buffer.update(cx, |buffer, _| {
2255//                 let snapshot = buffer.snapshot();
2256//                 let start = buffer
2257//                     .anchor_before(excerpt_visible_range.start)
2258//                     .to_point(&snapshot);
2259//                 let end = buffer
2260//                     .anchor_after(excerpt_visible_range.end)
2261//                     .to_point(&snapshot);
2262//                 start..end
2263//             })
2264//         }
2265
2266//         // in large buffers, requests are made for more than visible range of a buffer.
2267//         // invisible parts are queried later, to avoid excessive requests on quick typing.
2268//         // wait the timeout needed to get all requests.
2269//         cx.foreground().advance_clock(Duration::from_millis(
2270//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
2271//         ));
2272//         cx.foreground().run_until_parked();
2273//         let initial_visible_range = editor_visible_range(&editor, cx);
2274//         let lsp_initial_visible_range = lsp::Range::new(
2275//             lsp::Position::new(
2276//                 initial_visible_range.start.row,
2277//                 initial_visible_range.start.column,
2278//             ),
2279//             lsp::Position::new(
2280//                 initial_visible_range.end.row,
2281//                 initial_visible_range.end.column,
2282//             ),
2283//         );
2284//         let expected_initial_query_range_end =
2285//             lsp::Position::new(initial_visible_range.end.row * 2, 2);
2286//         let mut expected_invisible_query_start = lsp_initial_visible_range.end;
2287//         expected_invisible_query_start.character += 1;
2288//         editor.update(cx, |editor, cx| {
2289//             let ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
2290//             assert_eq!(ranges.len(), 2,
2291//                 "When scroll is at the edge of a big document, its visible part and the same range further should be queried in order, but got: {ranges:?}");
2292//             let visible_query_range = &ranges[0];
2293//             assert_eq!(visible_query_range.start, lsp_initial_visible_range.start);
2294//             assert_eq!(visible_query_range.end, lsp_initial_visible_range.end);
2295//             let invisible_query_range = &ranges[1];
2296
2297//             assert_eq!(invisible_query_range.start, expected_invisible_query_start, "Should initially query visible edge of the document");
2298//             assert_eq!(invisible_query_range.end, expected_initial_query_range_end, "Should initially query visible edge of the document");
2299
2300//             let requests_count = lsp_request_count.load(Ordering::Acquire);
2301//             assert_eq!(requests_count, 2, "Visible + invisible request");
2302//             let expected_hints = vec!["1".to_string(), "2".to_string()];
2303//             assert_eq!(
2304//                 expected_hints,
2305//                 cached_hint_labels(editor),
2306//                 "Should have hints from both LSP requests made for a big file"
2307//             );
2308//             assert_eq!(expected_hints, visible_hint_labels(editor, cx), "Should display only hints from the visible range");
2309//             assert_eq!(
2310//                 editor.inlay_hint_cache().version, requests_count,
2311//                 "LSP queries should've bumped the cache version"
2312//             );
2313//         });
2314
2315//         editor.update(cx, |editor, cx| {
2316//             editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
2317//             editor.scroll_screen(&ScrollAmount::Page(1.0), cx);
2318//         });
2319//         cx.foreground().advance_clock(Duration::from_millis(
2320//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
2321//         ));
2322//         cx.foreground().run_until_parked();
2323//         let visible_range_after_scrolls = editor_visible_range(&editor, cx);
2324//         let visible_line_count =
2325//             editor.update(cx, |editor, _| editor.visible_line_count().unwrap());
2326//         let selection_in_cached_range = editor.update(cx, |editor, cx| {
2327//             let ranges = lsp_request_ranges
2328//                 .lock()
2329//                 .drain(..)
2330//                 .sorted_by_key(|r| r.start)
2331//                 .collect::<Vec<_>>();
2332//             assert_eq!(
2333//                 ranges.len(),
2334//                 2,
2335//                 "Should query 2 ranges after both scrolls, but got: {ranges:?}"
2336//             );
2337//             let first_scroll = &ranges[0];
2338//             let second_scroll = &ranges[1];
2339//             assert_eq!(
2340//                 first_scroll.end, second_scroll.start,
2341//                 "Should query 2 adjacent ranges after the scrolls, but got: {ranges:?}"
2342//             );
2343//             assert_eq!(
2344//                 first_scroll.start, expected_initial_query_range_end,
2345//                 "First scroll should start the query right after the end of the original scroll",
2346//             );
2347//             assert_eq!(
2348//                 second_scroll.end,
2349//                 lsp::Position::new(
2350//                     visible_range_after_scrolls.end.row
2351//                         + visible_line_count.ceil() as u32,
2352//                     1,
2353//                 ),
2354//                 "Second scroll should query one more screen down after the end of the visible range"
2355//             );
2356
2357//             let lsp_requests = lsp_request_count.load(Ordering::Acquire);
2358//             assert_eq!(lsp_requests, 4, "Should query for hints after every scroll");
2359//             let expected_hints = vec![
2360//                 "1".to_string(),
2361//                 "2".to_string(),
2362//                 "3".to_string(),
2363//                 "4".to_string(),
2364//             ];
2365//             assert_eq!(
2366//                 expected_hints,
2367//                 cached_hint_labels(editor),
2368//                 "Should have hints from the new LSP response after the edit"
2369//             );
2370//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2371//             assert_eq!(
2372//                 editor.inlay_hint_cache().version,
2373//                 lsp_requests,
2374//                 "Should update the cache for every LSP response with hints added"
2375//             );
2376
2377//             let mut selection_in_cached_range = visible_range_after_scrolls.end;
2378//             selection_in_cached_range.row -= visible_line_count.ceil() as u32;
2379//             selection_in_cached_range
2380//         });
2381
2382//         editor.update(cx, |editor, cx| {
2383//             editor.change_selections(Some(Autoscroll::center()), cx, |s| {
2384//                 s.select_ranges([selection_in_cached_range..selection_in_cached_range])
2385//             });
2386//         });
2387//         cx.foreground().advance_clock(Duration::from_millis(
2388//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
2389//         ));
2390//         cx.foreground().run_until_parked();
2391//         editor.update(cx, |_, _| {
2392//             let ranges = lsp_request_ranges
2393//                 .lock()
2394//                 .drain(..)
2395//                 .sorted_by_key(|r| r.start)
2396//                 .collect::<Vec<_>>();
2397//             assert!(ranges.is_empty(), "No new ranges or LSP queries should be made after returning to the selection with cached hints");
2398//             assert_eq!(lsp_request_count.load(Ordering::Acquire), 4);
2399//         });
2400
2401//         editor.update(cx, |editor, cx| {
2402//             editor.handle_input("++++more text++++", cx);
2403//         });
2404//         cx.foreground().advance_clock(Duration::from_millis(
2405//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
2406//         ));
2407//         cx.foreground().run_until_parked();
2408//         editor.update(cx, |editor, cx| {
2409//             let mut ranges = lsp_request_ranges.lock().drain(..).collect::<Vec<_>>();
2410//             ranges.sort_by_key(|r| r.start);
2411
2412//             assert_eq!(ranges.len(), 3,
2413//                 "On edit, should scroll to selection and query a range around it: visible + same range above and below. Instead, got query ranges {ranges:?}");
2414//             let above_query_range = &ranges[0];
2415//             let visible_query_range = &ranges[1];
2416//             let below_query_range = &ranges[2];
2417//             assert!(above_query_range.end.character < visible_query_range.start.character || above_query_range.end.line + 1 == visible_query_range.start.line,
2418//                 "Above range {above_query_range:?} should be before visible range {visible_query_range:?}");
2419//             assert!(visible_query_range.end.character < below_query_range.start.character || visible_query_range.end.line  + 1 == below_query_range.start.line,
2420//                 "Visible range {visible_query_range:?} should be before below range {below_query_range:?}");
2421//             assert!(above_query_range.start.line < selection_in_cached_range.row,
2422//                 "Hints should be queried with the selected range after the query range start");
2423//             assert!(below_query_range.end.line > selection_in_cached_range.row,
2424//                 "Hints should be queried with the selected range before the query range end");
2425//             assert!(above_query_range.start.line <= selection_in_cached_range.row - (visible_line_count * 3.0 / 2.0) as u32,
2426//                 "Hints query range should contain one more screen before");
2427//             assert!(below_query_range.end.line >= selection_in_cached_range.row + (visible_line_count * 3.0 / 2.0) as u32,
2428//                 "Hints query range should contain one more screen after");
2429
2430//             let lsp_requests = lsp_request_count.load(Ordering::Acquire);
2431//             assert_eq!(lsp_requests, 7, "There should be a visible range and two ranges above and below it queried");
2432//             let expected_hints = vec!["5".to_string(), "6".to_string(), "7".to_string()];
2433//             assert_eq!(expected_hints, cached_hint_labels(editor),
2434//                 "Should have hints from the new LSP response after the edit");
2435//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2436//             assert_eq!(editor.inlay_hint_cache().version, lsp_requests, "Should update the cache for every LSP response with hints added");
2437//         });
2438//     }
2439
2440//     #[gpui::test(iterations = 10)]
2441//     async fn test_multiple_excerpts_large_multibuffer(
2442//         deterministic: Arc<Deterministic>,
2443//         cx: &mut gpui::TestAppContext,
2444//     ) {
2445//         init_test(cx, |settings| {
2446//             settings.defaults.inlay_hints = Some(InlayHintSettings {
2447//                 enabled: true,
2448//                 show_type_hints: true,
2449//                 show_parameter_hints: true,
2450//                 show_other_hints: true,
2451//             })
2452//         });
2453
2454//         let mut language = Language::new(
2455//             LanguageConfig {
2456//                 name: "Rust".into(),
2457//                 path_suffixes: vec!["rs".to_string()],
2458//                 ..Default::default()
2459//             },
2460//             Some(tree_sitter_rust::language()),
2461//         );
2462//         let mut fake_servers = language
2463//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
2464//                 capabilities: lsp::ServerCapabilities {
2465//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
2466//                     ..Default::default()
2467//                 },
2468//                 ..Default::default()
2469//             }))
2470//             .await;
2471//         let language = Arc::new(language);
2472//         let fs = FakeFs::new(cx.background());
2473//         fs.insert_tree(
2474//             "/a",
2475//             json!({
2476//                 "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
2477//                 "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
2478//             }),
2479//         )
2480//         .await;
2481//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
2482//         project.update(cx, |project, _| {
2483//             project.languages().add(Arc::clone(&language))
2484//         });
2485//         let workspace = cx
2486//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
2487//             .root(cx);
2488//         let worktree_id = workspace.update(cx, |workspace, cx| {
2489//             workspace.project().read_with(cx, |project, cx| {
2490//                 project.worktrees(cx).next().unwrap().read(cx).id()
2491//             })
2492//         });
2493
2494//         let buffer_1 = project
2495//             .update(cx, |project, cx| {
2496//                 project.open_buffer((worktree_id, "main.rs"), cx)
2497//             })
2498//             .await
2499//             .unwrap();
2500//         let buffer_2 = project
2501//             .update(cx, |project, cx| {
2502//                 project.open_buffer((worktree_id, "other.rs"), cx)
2503//             })
2504//             .await
2505//             .unwrap();
2506//         let multibuffer = cx.add_model(|cx| {
2507//             let mut multibuffer = MultiBuffer::new(0);
2508//             multibuffer.push_excerpts(
2509//                 buffer_1.clone(),
2510//                 [
2511//                     ExcerptRange {
2512//                         context: Point::new(0, 0)..Point::new(2, 0),
2513//                         primary: None,
2514//                     },
2515//                     ExcerptRange {
2516//                         context: Point::new(4, 0)..Point::new(11, 0),
2517//                         primary: None,
2518//                     },
2519//                     ExcerptRange {
2520//                         context: Point::new(22, 0)..Point::new(33, 0),
2521//                         primary: None,
2522//                     },
2523//                     ExcerptRange {
2524//                         context: Point::new(44, 0)..Point::new(55, 0),
2525//                         primary: None,
2526//                     },
2527//                     ExcerptRange {
2528//                         context: Point::new(56, 0)..Point::new(66, 0),
2529//                         primary: None,
2530//                     },
2531//                     ExcerptRange {
2532//                         context: Point::new(67, 0)..Point::new(77, 0),
2533//                         primary: None,
2534//                     },
2535//                 ],
2536//                 cx,
2537//             );
2538//             multibuffer.push_excerpts(
2539//                 buffer_2.clone(),
2540//                 [
2541//                     ExcerptRange {
2542//                         context: Point::new(0, 1)..Point::new(2, 1),
2543//                         primary: None,
2544//                     },
2545//                     ExcerptRange {
2546//                         context: Point::new(4, 1)..Point::new(11, 1),
2547//                         primary: None,
2548//                     },
2549//                     ExcerptRange {
2550//                         context: Point::new(22, 1)..Point::new(33, 1),
2551//                         primary: None,
2552//                     },
2553//                     ExcerptRange {
2554//                         context: Point::new(44, 1)..Point::new(55, 1),
2555//                         primary: None,
2556//                     },
2557//                     ExcerptRange {
2558//                         context: Point::new(56, 1)..Point::new(66, 1),
2559//                         primary: None,
2560//                     },
2561//                     ExcerptRange {
2562//                         context: Point::new(67, 1)..Point::new(77, 1),
2563//                         primary: None,
2564//                     },
2565//                 ],
2566//                 cx,
2567//             );
2568//             multibuffer
2569//         });
2570
2571//         deterministic.run_until_parked();
2572//         cx.foreground().run_until_parked();
2573//         let editor = cx
2574//             .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
2575//             .root(cx);
2576//         let editor_edited = Arc::new(AtomicBool::new(false));
2577//         let fake_server = fake_servers.next().await.unwrap();
2578//         let closure_editor_edited = Arc::clone(&editor_edited);
2579//         fake_server
2580//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
2581//                 let task_editor_edited = Arc::clone(&closure_editor_edited);
2582//                 async move {
2583//                     let hint_text = if params.text_document.uri
2584//                         == lsp::Url::from_file_path("/a/main.rs").unwrap()
2585//                     {
2586//                         "main hint"
2587//                     } else if params.text_document.uri
2588//                         == lsp::Url::from_file_path("/a/other.rs").unwrap()
2589//                     {
2590//                         "other hint"
2591//                     } else {
2592//                         panic!("unexpected uri: {:?}", params.text_document.uri);
2593//                     };
2594
2595//                     // one hint per excerpt
2596//                     let positions = [
2597//                         lsp::Position::new(0, 2),
2598//                         lsp::Position::new(4, 2),
2599//                         lsp::Position::new(22, 2),
2600//                         lsp::Position::new(44, 2),
2601//                         lsp::Position::new(56, 2),
2602//                         lsp::Position::new(67, 2),
2603//                     ];
2604//                     let out_of_range_hint = lsp::InlayHint {
2605//                         position: lsp::Position::new(
2606//                             params.range.start.line + 99,
2607//                             params.range.start.character + 99,
2608//                         ),
2609//                         label: lsp::InlayHintLabel::String(
2610//                             "out of excerpt range, should be ignored".to_string(),
2611//                         ),
2612//                         kind: None,
2613//                         text_edits: None,
2614//                         tooltip: None,
2615//                         padding_left: None,
2616//                         padding_right: None,
2617//                         data: None,
2618//                     };
2619
2620//                     let edited = task_editor_edited.load(Ordering::Acquire);
2621//                     Ok(Some(
2622//                         std::iter::once(out_of_range_hint)
2623//                             .chain(positions.into_iter().enumerate().map(|(i, position)| {
2624//                                 lsp::InlayHint {
2625//                                     position,
2626//                                     label: lsp::InlayHintLabel::String(format!(
2627//                                         "{hint_text}{} #{i}",
2628//                                         if edited { "(edited)" } else { "" },
2629//                                     )),
2630//                                     kind: None,
2631//                                     text_edits: None,
2632//                                     tooltip: None,
2633//                                     padding_left: None,
2634//                                     padding_right: None,
2635//                                     data: None,
2636//                                 }
2637//                             }))
2638//                             .collect(),
2639//                     ))
2640//                 }
2641//             })
2642//             .next()
2643//             .await;
2644//         cx.foreground().run_until_parked();
2645
2646//         editor.update(cx, |editor, cx| {
2647//             let expected_hints = vec![
2648//                 "main hint #0".to_string(),
2649//                 "main hint #1".to_string(),
2650//                 "main hint #2".to_string(),
2651//                 "main hint #3".to_string(),
2652//             ];
2653//             assert_eq!(
2654//                 expected_hints,
2655//                 cached_hint_labels(editor),
2656//                 "When scroll is at the edge of a multibuffer, its visible excerpts only should be queried for inlay hints"
2657//             );
2658//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2659//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(), "Every visible excerpt hints should bump the verison");
2660//         });
2661
2662//         editor.update(cx, |editor, cx| {
2663//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
2664//                 s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
2665//             });
2666//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
2667//                 s.select_ranges([Point::new(22, 0)..Point::new(22, 0)])
2668//             });
2669//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
2670//                 s.select_ranges([Point::new(50, 0)..Point::new(50, 0)])
2671//             });
2672//         });
2673//         cx.foreground().run_until_parked();
2674//         editor.update(cx, |editor, cx| {
2675//             let expected_hints = vec![
2676//                 "main hint #0".to_string(),
2677//                 "main hint #1".to_string(),
2678//                 "main hint #2".to_string(),
2679//                 "main hint #3".to_string(),
2680//                 "main hint #4".to_string(),
2681//                 "main hint #5".to_string(),
2682//                 "other hint #0".to_string(),
2683//                 "other hint #1".to_string(),
2684//                 "other hint #2".to_string(),
2685//             ];
2686//             assert_eq!(expected_hints, cached_hint_labels(editor),
2687//                 "With more scrolls of the multibuffer, more hints should be added into the cache and nothing invalidated without edits");
2688//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2689//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len(),
2690//                 "Due to every excerpt having one hint, we update cache per new excerpt scrolled");
2691//         });
2692
2693//         editor.update(cx, |editor, cx| {
2694//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
2695//                 s.select_ranges([Point::new(100, 0)..Point::new(100, 0)])
2696//             });
2697//         });
2698//         cx.foreground().advance_clock(Duration::from_millis(
2699//             INVISIBLE_RANGES_HINTS_REQUEST_DELAY_MILLIS + 100,
2700//         ));
2701//         cx.foreground().run_until_parked();
2702//         let last_scroll_update_version = editor.update(cx, |editor, cx| {
2703//             let expected_hints = vec![
2704//                 "main hint #0".to_string(),
2705//                 "main hint #1".to_string(),
2706//                 "main hint #2".to_string(),
2707//                 "main hint #3".to_string(),
2708//                 "main hint #4".to_string(),
2709//                 "main hint #5".to_string(),
2710//                 "other hint #0".to_string(),
2711//                 "other hint #1".to_string(),
2712//                 "other hint #2".to_string(),
2713//                 "other hint #3".to_string(),
2714//                 "other hint #4".to_string(),
2715//                 "other hint #5".to_string(),
2716//             ];
2717//             assert_eq!(expected_hints, cached_hint_labels(editor),
2718//                 "After multibuffer was scrolled to the end, all hints for all excerpts should be fetched");
2719//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2720//             assert_eq!(editor.inlay_hint_cache().version, expected_hints.len());
2721//             expected_hints.len()
2722//         });
2723
2724//         editor.update(cx, |editor, cx| {
2725//             editor.change_selections(Some(Autoscroll::Next), cx, |s| {
2726//                 s.select_ranges([Point::new(4, 0)..Point::new(4, 0)])
2727//             });
2728//         });
2729//         cx.foreground().run_until_parked();
2730//         editor.update(cx, |editor, cx| {
2731//             let expected_hints = vec![
2732//                 "main hint #0".to_string(),
2733//                 "main hint #1".to_string(),
2734//                 "main hint #2".to_string(),
2735//                 "main hint #3".to_string(),
2736//                 "main hint #4".to_string(),
2737//                 "main hint #5".to_string(),
2738//                 "other hint #0".to_string(),
2739//                 "other hint #1".to_string(),
2740//                 "other hint #2".to_string(),
2741//                 "other hint #3".to_string(),
2742//                 "other hint #4".to_string(),
2743//                 "other hint #5".to_string(),
2744//             ];
2745//             assert_eq!(expected_hints, cached_hint_labels(editor),
2746//                 "After multibuffer was scrolled to the end, further scrolls up should not bring more hints");
2747//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2748//             assert_eq!(editor.inlay_hint_cache().version, last_scroll_update_version, "No updates should happen during scrolling already scolled buffer");
2749//         });
2750
2751//         editor_edited.store(true, Ordering::Release);
2752//         editor.update(cx, |editor, cx| {
2753//             editor.change_selections(None, cx, |s| {
2754//                 s.select_ranges([Point::new(56, 0)..Point::new(56, 0)])
2755//             });
2756//             editor.handle_input("++++more text++++", cx);
2757//         });
2758//         cx.foreground().run_until_parked();
2759//         editor.update(cx, |editor, cx| {
2760//             let expected_hints = vec![
2761//                 "main hint(edited) #0".to_string(),
2762//                 "main hint(edited) #1".to_string(),
2763//                 "main hint(edited) #2".to_string(),
2764//                 "main hint(edited) #3".to_string(),
2765//                 "main hint(edited) #4".to_string(),
2766//                 "main hint(edited) #5".to_string(),
2767//                 "other hint(edited) #0".to_string(),
2768//                 "other hint(edited) #1".to_string(),
2769//             ];
2770//             assert_eq!(
2771//                 expected_hints,
2772//                 cached_hint_labels(editor),
2773//                 "After multibuffer edit, editor gets scolled back to the last selection; \
2774// all hints should be invalidated and requeried for all of its visible excerpts"
2775//             );
2776//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
2777
2778//             let current_cache_version = editor.inlay_hint_cache().version;
2779//             let minimum_expected_version = last_scroll_update_version + expected_hints.len();
2780//             assert!(
2781//                 current_cache_version == minimum_expected_version || current_cache_version == minimum_expected_version + 1,
2782//                 "Due to every excerpt having one hint, cache should update per new excerpt received + 1 potential sporadic update"
2783//             );
2784//         });
2785//     }
2786
2787//     #[gpui::test]
2788//     async fn test_excerpts_removed(
2789//         deterministic: Arc<Deterministic>,
2790//         cx: &mut gpui::TestAppContext,
2791//     ) {
2792//         init_test(cx, |settings| {
2793//             settings.defaults.inlay_hints = Some(InlayHintSettings {
2794//                 enabled: true,
2795//                 show_type_hints: false,
2796//                 show_parameter_hints: false,
2797//                 show_other_hints: false,
2798//             })
2799//         });
2800
2801//         let mut language = Language::new(
2802//             LanguageConfig {
2803//                 name: "Rust".into(),
2804//                 path_suffixes: vec!["rs".to_string()],
2805//                 ..Default::default()
2806//             },
2807//             Some(tree_sitter_rust::language()),
2808//         );
2809//         let mut fake_servers = language
2810//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
2811//                 capabilities: lsp::ServerCapabilities {
2812//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
2813//                     ..Default::default()
2814//                 },
2815//                 ..Default::default()
2816//             }))
2817//             .await;
2818//         let language = Arc::new(language);
2819//         let fs = FakeFs::new(cx.background());
2820//         fs.insert_tree(
2821//             "/a",
2822//             json!({
2823//                 "main.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|i| format!("let i = {i};\n")).collect::<Vec<_>>().join("")),
2824//                 "other.rs": format!("fn main() {{\n{}\n}}", (0..501).map(|j| format!("let j = {j};\n")).collect::<Vec<_>>().join("")),
2825//             }),
2826//         )
2827//         .await;
2828//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
2829//         project.update(cx, |project, _| {
2830//             project.languages().add(Arc::clone(&language))
2831//         });
2832//         let workspace = cx
2833//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
2834//             .root(cx);
2835//         let worktree_id = workspace.update(cx, |workspace, cx| {
2836//             workspace.project().read_with(cx, |project, cx| {
2837//                 project.worktrees(cx).next().unwrap().read(cx).id()
2838//             })
2839//         });
2840
2841//         let buffer_1 = project
2842//             .update(cx, |project, cx| {
2843//                 project.open_buffer((worktree_id, "main.rs"), cx)
2844//             })
2845//             .await
2846//             .unwrap();
2847//         let buffer_2 = project
2848//             .update(cx, |project, cx| {
2849//                 project.open_buffer((worktree_id, "other.rs"), cx)
2850//             })
2851//             .await
2852//             .unwrap();
2853//         let multibuffer = cx.add_model(|_| MultiBuffer::new(0));
2854//         let (buffer_1_excerpts, buffer_2_excerpts) = multibuffer.update(cx, |multibuffer, cx| {
2855//             let buffer_1_excerpts = multibuffer.push_excerpts(
2856//                 buffer_1.clone(),
2857//                 [ExcerptRange {
2858//                     context: Point::new(0, 0)..Point::new(2, 0),
2859//                     primary: None,
2860//                 }],
2861//                 cx,
2862//             );
2863//             let buffer_2_excerpts = multibuffer.push_excerpts(
2864//                 buffer_2.clone(),
2865//                 [ExcerptRange {
2866//                     context: Point::new(0, 1)..Point::new(2, 1),
2867//                     primary: None,
2868//                 }],
2869//                 cx,
2870//             );
2871//             (buffer_1_excerpts, buffer_2_excerpts)
2872//         });
2873
2874//         assert!(!buffer_1_excerpts.is_empty());
2875//         assert!(!buffer_2_excerpts.is_empty());
2876
2877//         deterministic.run_until_parked();
2878//         cx.foreground().run_until_parked();
2879//         let editor = cx
2880//             .add_window(|cx| Editor::for_multibuffer(multibuffer, Some(project.clone()), cx))
2881//             .root(cx);
2882//         let editor_edited = Arc::new(AtomicBool::new(false));
2883//         let fake_server = fake_servers.next().await.unwrap();
2884//         let closure_editor_edited = Arc::clone(&editor_edited);
2885//         fake_server
2886//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
2887//                 let task_editor_edited = Arc::clone(&closure_editor_edited);
2888//                 async move {
2889//                     let hint_text = if params.text_document.uri
2890//                         == lsp::Url::from_file_path("/a/main.rs").unwrap()
2891//                     {
2892//                         "main hint"
2893//                     } else if params.text_document.uri
2894//                         == lsp::Url::from_file_path("/a/other.rs").unwrap()
2895//                     {
2896//                         "other hint"
2897//                     } else {
2898//                         panic!("unexpected uri: {:?}", params.text_document.uri);
2899//                     };
2900
2901//                     let positions = [
2902//                         lsp::Position::new(0, 2),
2903//                         lsp::Position::new(4, 2),
2904//                         lsp::Position::new(22, 2),
2905//                         lsp::Position::new(44, 2),
2906//                         lsp::Position::new(56, 2),
2907//                         lsp::Position::new(67, 2),
2908//                     ];
2909//                     let out_of_range_hint = lsp::InlayHint {
2910//                         position: lsp::Position::new(
2911//                             params.range.start.line + 99,
2912//                             params.range.start.character + 99,
2913//                         ),
2914//                         label: lsp::InlayHintLabel::String(
2915//                             "out of excerpt range, should be ignored".to_string(),
2916//                         ),
2917//                         kind: None,
2918//                         text_edits: None,
2919//                         tooltip: None,
2920//                         padding_left: None,
2921//                         padding_right: None,
2922//                         data: None,
2923//                     };
2924
2925//                     let edited = task_editor_edited.load(Ordering::Acquire);
2926//                     Ok(Some(
2927//                         std::iter::once(out_of_range_hint)
2928//                             .chain(positions.into_iter().enumerate().map(|(i, position)| {
2929//                                 lsp::InlayHint {
2930//                                     position,
2931//                                     label: lsp::InlayHintLabel::String(format!(
2932//                                         "{hint_text}{} #{i}",
2933//                                         if edited { "(edited)" } else { "" },
2934//                                     )),
2935//                                     kind: None,
2936//                                     text_edits: None,
2937//                                     tooltip: None,
2938//                                     padding_left: None,
2939//                                     padding_right: None,
2940//                                     data: None,
2941//                                 }
2942//                             }))
2943//                             .collect(),
2944//                     ))
2945//                 }
2946//             })
2947//             .next()
2948//             .await;
2949//         cx.foreground().run_until_parked();
2950
2951//         editor.update(cx, |editor, cx| {
2952//             assert_eq!(
2953//                 vec!["main hint #0".to_string(), "other hint #0".to_string()],
2954//                 cached_hint_labels(editor),
2955//                 "Cache should update for both excerpts despite hints display was disabled"
2956//             );
2957//             assert!(
2958//                 visible_hint_labels(editor, cx).is_empty(),
2959//                 "All hints are disabled and should not be shown despite being present in the cache"
2960//             );
2961//             assert_eq!(
2962//                 editor.inlay_hint_cache().version,
2963//                 2,
2964//                 "Cache should update once per excerpt query"
2965//             );
2966//         });
2967
2968//         editor.update(cx, |editor, cx| {
2969//             editor.buffer().update(cx, |multibuffer, cx| {
2970//                 multibuffer.remove_excerpts(buffer_2_excerpts, cx)
2971//             })
2972//         });
2973//         cx.foreground().run_until_parked();
2974//         editor.update(cx, |editor, cx| {
2975//             assert_eq!(
2976//                 vec!["main hint #0".to_string()],
2977//                 cached_hint_labels(editor),
2978//                 "For the removed excerpt, should clean corresponding cached hints"
2979//             );
2980//             assert!(
2981//                 visible_hint_labels(editor, cx).is_empty(),
2982//                 "All hints are disabled and should not be shown despite being present in the cache"
2983//             );
2984//             assert_eq!(
2985//                 editor.inlay_hint_cache().version,
2986//                 3,
2987//                 "Excerpt removal should trigger a cache update"
2988//             );
2989//         });
2990
2991//         update_test_language_settings(cx, |settings| {
2992//             settings.defaults.inlay_hints = Some(InlayHintSettings {
2993//                 enabled: true,
2994//                 show_type_hints: true,
2995//                 show_parameter_hints: true,
2996//                 show_other_hints: true,
2997//             })
2998//         });
2999//         cx.foreground().run_until_parked();
3000//         editor.update(cx, |editor, cx| {
3001//             let expected_hints = vec!["main hint #0".to_string()];
3002//             assert_eq!(
3003//                 expected_hints,
3004//                 cached_hint_labels(editor),
3005//                 "Hint display settings change should not change the cache"
3006//             );
3007//             assert_eq!(
3008//                 expected_hints,
3009//                 visible_hint_labels(editor, cx),
3010//                 "Settings change should make cached hints visible"
3011//             );
3012//             assert_eq!(
3013//                 editor.inlay_hint_cache().version,
3014//                 4,
3015//                 "Settings change should trigger a cache update"
3016//             );
3017//         });
3018//     }
3019
3020//     #[gpui::test]
3021//     async fn test_inside_char_boundary_range_hints(cx: &mut gpui::TestAppContext) {
3022//         init_test(cx, |settings| {
3023//             settings.defaults.inlay_hints = Some(InlayHintSettings {
3024//                 enabled: true,
3025//                 show_type_hints: true,
3026//                 show_parameter_hints: true,
3027//                 show_other_hints: true,
3028//             })
3029//         });
3030
3031//         let mut language = Language::new(
3032//             LanguageConfig {
3033//                 name: "Rust".into(),
3034//                 path_suffixes: vec!["rs".to_string()],
3035//                 ..Default::default()
3036//             },
3037//             Some(tree_sitter_rust::language()),
3038//         );
3039//         let mut fake_servers = language
3040//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
3041//                 capabilities: lsp::ServerCapabilities {
3042//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
3043//                     ..Default::default()
3044//                 },
3045//                 ..Default::default()
3046//             }))
3047//             .await;
3048//         let fs = FakeFs::new(cx.background());
3049//         fs.insert_tree(
3050//             "/a",
3051//             json!({
3052//                 "main.rs": format!(r#"fn main() {{\n{}\n}}"#, format!("let i = {};\n", "√".repeat(10)).repeat(500)),
3053//                 "other.rs": "// Test file",
3054//             }),
3055//         )
3056//         .await;
3057//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
3058//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
3059//         let workspace = cx
3060//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
3061//             .root(cx);
3062//         let worktree_id = workspace.update(cx, |workspace, cx| {
3063//             workspace.project().read_with(cx, |project, cx| {
3064//                 project.worktrees(cx).next().unwrap().read(cx).id()
3065//             })
3066//         });
3067
3068//         let _buffer = project
3069//             .update(cx, |project, cx| {
3070//                 project.open_local_buffer("/a/main.rs", cx)
3071//             })
3072//             .await
3073//             .unwrap();
3074//         cx.foreground().run_until_parked();
3075//         cx.foreground().start_waiting();
3076//         let fake_server = fake_servers.next().await.unwrap();
3077//         let editor = workspace
3078//             .update(cx, |workspace, cx| {
3079//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
3080//             })
3081//             .await
3082//             .unwrap()
3083//             .downcast::<Editor>()
3084//             .unwrap();
3085//         let lsp_request_count = Arc::new(AtomicU32::new(0));
3086//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
3087//         fake_server
3088//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
3089//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
3090//                 async move {
3091//                     assert_eq!(
3092//                         params.text_document.uri,
3093//                         lsp::Url::from_file_path("/a/main.rs").unwrap(),
3094//                     );
3095//                     let query_start = params.range.start;
3096//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::Release) + 1;
3097//                     Ok(Some(vec![lsp::InlayHint {
3098//                         position: query_start,
3099//                         label: lsp::InlayHintLabel::String(i.to_string()),
3100//                         kind: None,
3101//                         text_edits: None,
3102//                         tooltip: None,
3103//                         padding_left: None,
3104//                         padding_right: None,
3105//                         data: None,
3106//                     }]))
3107//                 }
3108//             })
3109//             .next()
3110//             .await;
3111
3112//         cx.foreground().run_until_parked();
3113//         editor.update(cx, |editor, cx| {
3114//             editor.change_selections(None, cx, |s| {
3115//                 s.select_ranges([Point::new(10, 0)..Point::new(10, 0)])
3116//             })
3117//         });
3118//         cx.foreground().run_until_parked();
3119//         editor.update(cx, |editor, cx| {
3120//             let expected_hints = vec!["1".to_string()];
3121//             assert_eq!(expected_hints, cached_hint_labels(editor));
3122//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
3123//             assert_eq!(editor.inlay_hint_cache().version, 1);
3124//         });
3125//     }
3126
3127//     #[gpui::test]
3128//     async fn test_toggle_inlay_hints(cx: &mut gpui::TestAppContext) {
3129//         init_test(cx, |settings| {
3130//             settings.defaults.inlay_hints = Some(InlayHintSettings {
3131//                 enabled: false,
3132//                 show_type_hints: true,
3133//                 show_parameter_hints: true,
3134//                 show_other_hints: true,
3135//             })
3136//         });
3137
3138//         let (file_with_hints, editor, fake_server) = prepare_test_objects(cx).await;
3139
3140//         editor.update(cx, |editor, cx| {
3141//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
3142//         });
3143//         cx.foreground().start_waiting();
3144//         let lsp_request_count = Arc::new(AtomicU32::new(0));
3145//         let closure_lsp_request_count = Arc::clone(&lsp_request_count);
3146//         fake_server
3147//             .handle_request::<lsp::request::InlayHintRequest, _, _>(move |params, _| {
3148//                 let task_lsp_request_count = Arc::clone(&closure_lsp_request_count);
3149//                 async move {
3150//                     assert_eq!(
3151//                         params.text_document.uri,
3152//                         lsp::Url::from_file_path(file_with_hints).unwrap(),
3153//                     );
3154
3155//                     let i = Arc::clone(&task_lsp_request_count).fetch_add(1, Ordering::SeqCst) + 1;
3156//                     Ok(Some(vec![lsp::InlayHint {
3157//                         position: lsp::Position::new(0, i),
3158//                         label: lsp::InlayHintLabel::String(i.to_string()),
3159//                         kind: None,
3160//                         text_edits: None,
3161//                         tooltip: None,
3162//                         padding_left: None,
3163//                         padding_right: None,
3164//                         data: None,
3165//                     }]))
3166//                 }
3167//             })
3168//             .next()
3169//             .await;
3170//         cx.foreground().run_until_parked();
3171//         editor.update(cx, |editor, cx| {
3172//             let expected_hints = vec!["1".to_string()];
3173//             assert_eq!(
3174//                 expected_hints,
3175//                 cached_hint_labels(editor),
3176//                 "Should display inlays after toggle despite them disabled in settings"
3177//             );
3178//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
3179//             assert_eq!(
3180//                 editor.inlay_hint_cache().version,
3181//                 1,
3182//                 "First toggle should be cache's first update"
3183//             );
3184//         });
3185
3186//         editor.update(cx, |editor, cx| {
3187//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
3188//         });
3189//         cx.foreground().run_until_parked();
3190//         editor.update(cx, |editor, cx| {
3191//             assert!(
3192//                 cached_hint_labels(editor).is_empty(),
3193//                 "Should clear hints after 2nd toggle"
3194//             );
3195//             assert!(visible_hint_labels(editor, cx).is_empty());
3196//             assert_eq!(editor.inlay_hint_cache().version, 2);
3197//         });
3198
3199//         update_test_language_settings(cx, |settings| {
3200//             settings.defaults.inlay_hints = Some(InlayHintSettings {
3201//                 enabled: true,
3202//                 show_type_hints: true,
3203//                 show_parameter_hints: true,
3204//                 show_other_hints: true,
3205//             })
3206//         });
3207//         cx.foreground().run_until_parked();
3208//         editor.update(cx, |editor, cx| {
3209//             let expected_hints = vec!["2".to_string()];
3210//             assert_eq!(
3211//                 expected_hints,
3212//                 cached_hint_labels(editor),
3213//                 "Should query LSP hints for the 2nd time after enabling hints in settings"
3214//             );
3215//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
3216//             assert_eq!(editor.inlay_hint_cache().version, 3);
3217//         });
3218
3219//         editor.update(cx, |editor, cx| {
3220//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
3221//         });
3222//         cx.foreground().run_until_parked();
3223//         editor.update(cx, |editor, cx| {
3224//             assert!(
3225//                 cached_hint_labels(editor).is_empty(),
3226//                 "Should clear hints after enabling in settings and a 3rd toggle"
3227//             );
3228//             assert!(visible_hint_labels(editor, cx).is_empty());
3229//             assert_eq!(editor.inlay_hint_cache().version, 4);
3230//         });
3231
3232//         editor.update(cx, |editor, cx| {
3233//             editor.toggle_inlay_hints(&crate::ToggleInlayHints, cx)
3234//         });
3235//         cx.foreground().run_until_parked();
3236//         editor.update(cx, |editor, cx| {
3237//             let expected_hints = vec!["3".to_string()];
3238//             assert_eq!(
3239//                 expected_hints,
3240//                 cached_hint_labels(editor),
3241//                 "Should query LSP hints for the 3rd time after enabling hints in settings and toggling them back on"
3242//             );
3243//             assert_eq!(expected_hints, visible_hint_labels(editor, cx));
3244//             assert_eq!(editor.inlay_hint_cache().version, 5);
3245//         });
3246//     }
3247
3248//     pub(crate) fn init_test(cx: &mut TestAppContext, f: impl Fn(&mut AllLanguageSettingsContent)) {
3249//         cx.foreground().forbid_parking();
3250
3251//         cx.update(|cx| {
3252//             cx.set_global(SettingsStore::test(cx));
3253//             theme::init(cx);
3254//             client::init_settings(cx);
3255//             language::init(cx);
3256//             Project::init_settings(cx);
3257//             workspace::init_settings(cx);
3258//             crate::init(cx);
3259//         });
3260
3261//         update_test_language_settings(cx, f);
3262//     }
3263
3264//     async fn prepare_test_objects(
3265//         cx: &mut TestAppContext,
3266//     ) -> (&'static str, ViewHandle<Editor>, FakeLanguageServer) {
3267//         let mut language = Language::new(
3268//             LanguageConfig {
3269//                 name: "Rust".into(),
3270//                 path_suffixes: vec!["rs".to_string()],
3271//                 ..Default::default()
3272//             },
3273//             Some(tree_sitter_rust::language()),
3274//         );
3275//         let mut fake_servers = language
3276//             .set_fake_lsp_adapter(Arc::new(FakeLspAdapter {
3277//                 capabilities: lsp::ServerCapabilities {
3278//                     inlay_hint_provider: Some(lsp::OneOf::Left(true)),
3279//                     ..Default::default()
3280//                 },
3281//                 ..Default::default()
3282//             }))
3283//             .await;
3284
3285//         let fs = FakeFs::new(cx.background());
3286//         fs.insert_tree(
3287//             "/a",
3288//             json!({
3289//                 "main.rs": "fn main() { a } // and some long comment to ensure inlays are not trimmed out",
3290//                 "other.rs": "// Test file",
3291//             }),
3292//         )
3293//         .await;
3294
3295//         let project = Project::test(fs, ["/a".as_ref()], cx).await;
3296//         project.update(cx, |project, _| project.languages().add(Arc::new(language)));
3297//         let workspace = cx
3298//             .add_window(|cx| Workspace::test_new(project.clone(), cx))
3299//             .root(cx);
3300//         let worktree_id = workspace.update(cx, |workspace, cx| {
3301//             workspace.project().read_with(cx, |project, cx| {
3302//                 project.worktrees(cx).next().unwrap().read(cx).id()
3303//             })
3304//         });
3305
3306//         let _buffer = project
3307//             .update(cx, |project, cx| {
3308//                 project.open_local_buffer("/a/main.rs", cx)
3309//             })
3310//             .await
3311//             .unwrap();
3312//         cx.foreground().run_until_parked();
3313//         cx.foreground().start_waiting();
3314//         let fake_server = fake_servers.next().await.unwrap();
3315//         let editor = workspace
3316//             .update(cx, |workspace, cx| {
3317//                 workspace.open_path((worktree_id, "main.rs"), None, true, cx)
3318//             })
3319//             .await
3320//             .unwrap()
3321//             .downcast::<Editor>()
3322//             .unwrap();
3323
3324//         editor.update(cx, |editor, cx| {
3325//             assert!(cached_hint_labels(editor).is_empty());
3326//             assert!(visible_hint_labels(editor, cx).is_empty());
3327//             assert_eq!(editor.inlay_hint_cache().version, 0);
3328//         });
3329
3330//         ("/a/main.rs", editor, fake_server)
3331//     }
3332
3333//     pub fn cached_hint_labels(editor: &Editor) -> Vec<String> {
3334//         let mut labels = Vec::new();
3335//         for (_, excerpt_hints) in &editor.inlay_hint_cache().hints {
3336//             let excerpt_hints = excerpt_hints.read();
3337//             for id in &excerpt_hints.ordered_hints {
3338//                 labels.push(excerpt_hints.hints_by_id[id].text());
3339//             }
3340//         }
3341
3342//         labels.sort();
3343//         labels
3344//     }
3345
3346//     pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, '_, Editor>) -> Vec<String> {
3347//         let mut hints = editor
3348//             .visible_inlay_hints(cx)
3349//             .into_iter()
3350//             .map(|hint| hint.text.to_string())
3351//             .collect::<Vec<_>>();
3352//         hints.sort();
3353//         hints
3354//     }
3355// }