Compare commits
8 Commits
v0.212.3
...
git/fix-pa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5788b0a29 | ||
|
|
70d909449b | ||
|
|
7e7a791360 | ||
|
|
909cc30cc3 | ||
|
|
c547a06425 | ||
|
|
47debe9943 | ||
|
|
7e5f706ddc | ||
|
|
89274d82e7 |
14
.github/workflows/after_release.yml
vendored
14
.github/workflows/after_release.yml
vendored
@@ -42,14 +42,14 @@ jobs:
|
||||
- id: set-package-name
|
||||
name: after_release::publish_winget::set_package_name
|
||||
run: |
|
||||
if [ "${{ github.event.release.prerelease }}" == "true" ]; then
|
||||
PACKAGE_NAME=ZedIndustries.Zed.Preview
|
||||
else
|
||||
PACKAGE_NAME=ZedIndustries.Zed
|
||||
fi
|
||||
if ("${{ github.event.release.prerelease }}" -eq "true") {
|
||||
$PACKAGE_NAME = "ZedIndustries.Zed.Preview"
|
||||
} else {
|
||||
$PACKAGE_NAME = "ZedIndustries.Zed"
|
||||
}
|
||||
|
||||
echo "PACKAGE_NAME=$PACKAGE_NAME" >> "$GITHUB_OUTPUT"
|
||||
shell: bash -euxo pipefail {0}
|
||||
echo "PACKAGE_NAME=$PACKAGE_NAME" >> $env:GITHUB_OUTPUT
|
||||
shell: pwsh
|
||||
- name: after_release::publish_winget::winget_releaser
|
||||
uses: vedantmgoyal9/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f
|
||||
with:
|
||||
|
||||
@@ -182,7 +182,6 @@ impl ProjectDiagnosticsEditor {
|
||||
project::Event::DiskBasedDiagnosticsFinished { language_server_id } => {
|
||||
log::debug!("disk based diagnostics finished for server {language_server_id}");
|
||||
this.close_diagnosticless_buffers(
|
||||
window,
|
||||
cx,
|
||||
this.editor.focus_handle(cx).contains_focused(window, cx)
|
||||
|| this.focus_handle.contains_focused(window, cx),
|
||||
@@ -247,10 +246,10 @@ impl ProjectDiagnosticsEditor {
|
||||
window.focus(&this.focus_handle);
|
||||
}
|
||||
}
|
||||
EditorEvent::Blurred => this.close_diagnosticless_buffers(window, cx, false),
|
||||
EditorEvent::Saved => this.close_diagnosticless_buffers(window, cx, true),
|
||||
EditorEvent::Blurred => this.close_diagnosticless_buffers(cx, false),
|
||||
EditorEvent::Saved => this.close_diagnosticless_buffers(cx, true),
|
||||
EditorEvent::SelectionsChanged { .. } => {
|
||||
this.close_diagnosticless_buffers(window, cx, true)
|
||||
this.close_diagnosticless_buffers(cx, true)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -298,17 +297,16 @@ impl ProjectDiagnosticsEditor {
|
||||
/// - have no diagnostics anymore
|
||||
/// - are saved (not dirty)
|
||||
/// - and, if `retain_selections` is true, do not have selections within them
|
||||
fn close_diagnosticless_buffers(
|
||||
&mut self,
|
||||
_window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
retain_selections: bool,
|
||||
) {
|
||||
let buffer_ids = self.multibuffer.read(cx).all_buffer_ids();
|
||||
let selected_buffers = self.editor.update(cx, |editor, cx| {
|
||||
fn close_diagnosticless_buffers(&mut self, cx: &mut Context<Self>, retain_selections: bool) {
|
||||
let snapshot = self
|
||||
.editor
|
||||
.update(cx, |editor, cx| editor.display_snapshot(cx));
|
||||
let buffer = self.multibuffer.read(cx);
|
||||
let buffer_ids = buffer.all_buffer_ids();
|
||||
let selected_buffers = self.editor.update(cx, |editor, _| {
|
||||
editor
|
||||
.selections
|
||||
.all_anchors(cx)
|
||||
.all_anchors(&snapshot)
|
||||
.iter()
|
||||
.filter_map(|anchor| anchor.start.buffer_id)
|
||||
.collect::<HashSet<_>>()
|
||||
@@ -443,7 +441,7 @@ impl ProjectDiagnosticsEditor {
|
||||
fn focus_out(&mut self, _: FocusOutEvent, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if !self.focus_handle.is_focused(window) && !self.editor.focus_handle(cx).is_focused(window)
|
||||
{
|
||||
self.close_diagnosticless_buffers(window, cx, false);
|
||||
self.close_diagnosticless_buffers(cx, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,8 +455,7 @@ impl ProjectDiagnosticsEditor {
|
||||
});
|
||||
}
|
||||
});
|
||||
self.multibuffer
|
||||
.update(cx, |multibuffer, cx| multibuffer.clear(cx));
|
||||
self.close_diagnosticless_buffers(cx, false);
|
||||
self.project.update(cx, |project, cx| {
|
||||
self.paths_to_update = project
|
||||
.diagnostic_summaries(false, cx)
|
||||
|
||||
@@ -156,7 +156,9 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// Cursor is at the first diagnostic
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert_eq!(
|
||||
editor.selections.display_ranges(cx),
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx)),
|
||||
[DisplayPoint::new(DisplayRow(3), 8)..DisplayPoint::new(DisplayRow(3), 8)]
|
||||
);
|
||||
});
|
||||
@@ -232,7 +234,9 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// Cursor keeps its position.
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert_eq!(
|
||||
editor.selections.display_ranges(cx),
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx)),
|
||||
[DisplayPoint::new(DisplayRow(8), 8)..DisplayPoint::new(DisplayRow(8), 8)]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -63,6 +63,14 @@ pub struct BlockSnapshot {
|
||||
pub(super) excerpt_header_height: u32,
|
||||
}
|
||||
|
||||
impl Deref for BlockSnapshot {
|
||||
type Target = WrapSnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.wrap_snapshot
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct CustomBlockId(pub usize);
|
||||
|
||||
|
||||
@@ -630,6 +630,14 @@ pub struct FoldSnapshot {
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
impl Deref for FoldSnapshot {
|
||||
type Target = InlaySnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inlay_snapshot
|
||||
}
|
||||
}
|
||||
|
||||
impl FoldSnapshot {
|
||||
pub fn buffer(&self) -> &MultiBufferSnapshot {
|
||||
&self.inlay_snapshot.buffer
|
||||
|
||||
@@ -32,6 +32,14 @@ pub struct InlaySnapshot {
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for InlaySnapshot {
|
||||
type Target = MultiBufferSnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Transform {
|
||||
Isomorphic(TextSummary),
|
||||
|
||||
@@ -167,6 +167,14 @@ pub struct TabSnapshot {
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for TabSnapshot {
|
||||
type Target = FoldSnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.fold_snapshot
|
||||
}
|
||||
}
|
||||
|
||||
impl TabSnapshot {
|
||||
pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
|
||||
&self.fold_snapshot.inlay_snapshot.buffer
|
||||
|
||||
@@ -43,6 +43,14 @@ pub struct WrapSnapshot {
|
||||
interpolated: bool,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for WrapSnapshot {
|
||||
type Target = TabSnapshot;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.tab_snapshot
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
struct Transform {
|
||||
summary: TransformSummary,
|
||||
|
||||
@@ -1827,7 +1827,7 @@ impl Editor {
|
||||
})
|
||||
});
|
||||
|
||||
let selections = SelectionsCollection::new(display_map.clone(), multi_buffer.clone());
|
||||
let selections = SelectionsCollection::new();
|
||||
|
||||
let blink_manager = cx.new(|cx| {
|
||||
let mut blink_manager = BlinkManager::new(CURSOR_BLINK_INTERVAL, cx);
|
||||
@@ -2384,7 +2384,7 @@ impl Editor {
|
||||
}
|
||||
|
||||
pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
|
||||
self.selections.display_map(cx)
|
||||
self.display_map.update(cx, |map, cx| map.snapshot(cx))
|
||||
}
|
||||
|
||||
pub fn deploy_mouse_context_menu(
|
||||
@@ -3283,11 +3283,13 @@ impl Editor {
|
||||
other: Entity<Editor>,
|
||||
cx: &mut Context<Self>,
|
||||
) -> gpui::Subscription {
|
||||
assert_eq!(self.buffer(), other.read(cx).buffer());
|
||||
let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
|
||||
if !other_selections.is_empty() {
|
||||
self.selections.change_with(cx, |selections| {
|
||||
selections.select_anchors(other_selections);
|
||||
});
|
||||
self.selections
|
||||
.change_with(&self.display_snapshot(cx), |selections| {
|
||||
selections.select_anchors(other_selections);
|
||||
});
|
||||
}
|
||||
|
||||
let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
|
||||
@@ -3296,7 +3298,8 @@ impl Editor {
|
||||
if other_selections.is_empty() {
|
||||
return;
|
||||
}
|
||||
this.selections.change_with(cx, |selections| {
|
||||
let snapshot = this.display_snapshot(cx);
|
||||
this.selections.change_with(&snapshot, |selections| {
|
||||
selections.select_anchors(other_selections);
|
||||
});
|
||||
}
|
||||
@@ -3309,9 +3312,12 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
other.update(cx, |other_editor, cx| {
|
||||
other_editor.selections.change_with(cx, |selections| {
|
||||
selections.select_anchors(these_selections);
|
||||
})
|
||||
let snapshot = other_editor.display_snapshot(cx);
|
||||
other_editor
|
||||
.selections
|
||||
.change_with(&snapshot, |selections| {
|
||||
selections.select_anchors(these_selections);
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -3327,13 +3333,14 @@ impl Editor {
|
||||
effects: SelectionEffects,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_>) -> R,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
|
||||
) -> R {
|
||||
let snapshot = self.display_snapshot(cx);
|
||||
if let Some(state) = &mut self.deferred_selection_effects_state {
|
||||
state.effects.scroll = effects.scroll.or(state.effects.scroll);
|
||||
state.effects.completions = effects.completions;
|
||||
state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
|
||||
let (changed, result) = self.selections.change_with(cx, change);
|
||||
let (changed, result) = self.selections.change_with(&snapshot, change);
|
||||
state.changed |= changed;
|
||||
return result;
|
||||
}
|
||||
@@ -3348,7 +3355,7 @@ impl Editor {
|
||||
add_selections_state: self.add_selections_state.clone(),
|
||||
},
|
||||
};
|
||||
let (changed, result) = self.selections.change_with(cx, change);
|
||||
let (changed, result) = self.selections.change_with(&snapshot, change);
|
||||
state.changed = state.changed || changed;
|
||||
if self.defer_selection_effects {
|
||||
self.deferred_selection_effects_state = Some(state);
|
||||
@@ -16157,7 +16164,7 @@ impl Editor {
|
||||
.map(|s| s.to_vec())
|
||||
{
|
||||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
let map = s.display_map();
|
||||
let map = s.display_snapshot();
|
||||
s.select_display_ranges(selections.iter().map(|a| {
|
||||
let point = a.to_display_point(&map);
|
||||
point..point
|
||||
@@ -16178,7 +16185,7 @@ impl Editor {
|
||||
.map(|s| s.to_vec())
|
||||
{
|
||||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
let map = s.display_map();
|
||||
let map = s.display_snapshot();
|
||||
s.select_display_ranges(selections.iter().map(|a| {
|
||||
let point = a.to_display_point(&map);
|
||||
point..point
|
||||
@@ -17973,14 +17980,15 @@ impl Editor {
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let old_cursor_position = self.selections.newest_anchor().head();
|
||||
self.selections.change_with(cx, |s| {
|
||||
s.select_anchors(selections);
|
||||
if let Some(pending_selection) = pending_selection {
|
||||
s.set_pending(pending_selection, SelectMode::Character);
|
||||
} else {
|
||||
s.clear_pending();
|
||||
}
|
||||
});
|
||||
self.selections
|
||||
.change_with(&self.display_snapshot(cx), |s| {
|
||||
s.select_anchors(selections);
|
||||
if let Some(pending_selection) = pending_selection {
|
||||
s.set_pending(pending_selection, SelectMode::Character);
|
||||
} else {
|
||||
s.clear_pending();
|
||||
}
|
||||
});
|
||||
self.selections_did_change(
|
||||
false,
|
||||
&old_cursor_position,
|
||||
@@ -20188,7 +20196,7 @@ impl Editor {
|
||||
|
||||
let locations = self
|
||||
.selections
|
||||
.all_anchors(cx)
|
||||
.all_anchors(&self.display_snapshot(cx))
|
||||
.iter()
|
||||
.map(|selection| {
|
||||
(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,30 @@
|
||||
use std::{
|
||||
cell::Ref,
|
||||
cmp, fmt, iter, mem,
|
||||
ops::{Deref, DerefMut, Range, Sub},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use collections::HashMap;
|
||||
use gpui::{App, Entity, Pixels};
|
||||
use itertools::Itertools;
|
||||
use gpui::Pixels;
|
||||
use itertools::Itertools as _;
|
||||
use language::{Bias, Point, Selection, SelectionGoal, TextDimension};
|
||||
use util::post_inc;
|
||||
|
||||
use crate::{
|
||||
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBuffer, MultiBufferSnapshot, SelectMode,
|
||||
ToOffset, ToPoint,
|
||||
display_map::{DisplayMap, DisplaySnapshot, ToDisplayPoint},
|
||||
Anchor, DisplayPoint, DisplayRow, ExcerptId, MultiBufferSnapshot, SelectMode, ToOffset,
|
||||
ToPoint,
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
movement::TextLayoutDetails,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PendingSelection {
|
||||
pub selection: Selection<Anchor>,
|
||||
pub mode: SelectMode,
|
||||
selection: Selection<Anchor>,
|
||||
mode: SelectMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SelectionsCollection {
|
||||
display_map: Entity<DisplayMap>,
|
||||
buffer: Entity<MultiBuffer>,
|
||||
next_selection_id: usize,
|
||||
line_mode: bool,
|
||||
/// The non-pending, non-overlapping selections.
|
||||
@@ -40,10 +37,8 @@ pub struct SelectionsCollection {
|
||||
}
|
||||
|
||||
impl SelectionsCollection {
|
||||
pub fn new(display_map: Entity<DisplayMap>, buffer: Entity<MultiBuffer>) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
display_map,
|
||||
buffer,
|
||||
next_selection_id: 1,
|
||||
line_mode: false,
|
||||
disjoint: Arc::default(),
|
||||
@@ -62,14 +57,6 @@ impl SelectionsCollection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_map(&self, cx: &mut App) -> DisplaySnapshot {
|
||||
self.display_map.update(cx, |map, cx| map.snapshot(cx))
|
||||
}
|
||||
|
||||
fn buffer<'a>(&self, cx: &'a App) -> Ref<'a, MultiBufferSnapshot> {
|
||||
self.buffer.read(cx).read(cx)
|
||||
}
|
||||
|
||||
pub fn clone_state(&mut self, other: &SelectionsCollection) {
|
||||
self.next_selection_id = other.next_selection_id;
|
||||
self.line_mode = other.line_mode;
|
||||
@@ -106,15 +93,14 @@ impl SelectionsCollection {
|
||||
}
|
||||
|
||||
/// Non-overlapping selections using anchors, including the pending selection.
|
||||
pub fn all_anchors(&self, cx: &mut App) -> Arc<[Selection<Anchor>]> {
|
||||
pub fn all_anchors(&self, snapshot: &DisplaySnapshot) -> Arc<[Selection<Anchor>]> {
|
||||
if self.pending.is_none() {
|
||||
self.disjoint_anchors_arc()
|
||||
} else {
|
||||
let all_offset_selections = self.all::<usize>(&self.display_map(cx));
|
||||
let buffer = self.buffer(cx);
|
||||
let all_offset_selections = self.all::<usize>(snapshot);
|
||||
all_offset_selections
|
||||
.into_iter()
|
||||
.map(|selection| selection_to_anchor_selection(selection, &buffer))
|
||||
.map(|selection| selection_to_anchor_selection(selection, snapshot))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
@@ -354,16 +340,17 @@ impl SelectionsCollection {
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn display_ranges(&self, cx: &mut App) -> Vec<Range<DisplayPoint>> {
|
||||
let display_map = self.display_map(cx);
|
||||
pub fn display_ranges(&self, display_snapshot: &DisplaySnapshot) -> Vec<Range<DisplayPoint>> {
|
||||
self.disjoint_anchors_arc()
|
||||
.iter()
|
||||
.chain(self.pending_anchor())
|
||||
.map(|s| {
|
||||
if s.reversed {
|
||||
s.end.to_display_point(&display_map)..s.start.to_display_point(&display_map)
|
||||
s.end.to_display_point(display_snapshot)
|
||||
..s.start.to_display_point(display_snapshot)
|
||||
} else {
|
||||
s.start.to_display_point(&display_map)..s.end.to_display_point(&display_map)
|
||||
s.start.to_display_point(display_snapshot)
|
||||
..s.end.to_display_point(display_snapshot)
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -414,13 +401,13 @@ impl SelectionsCollection {
|
||||
|
||||
pub fn change_with<R>(
|
||||
&mut self,
|
||||
cx: &mut App,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection) -> R,
|
||||
snapshot: &DisplaySnapshot,
|
||||
change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
|
||||
) -> (bool, R) {
|
||||
let mut mutable_collection = MutableSelectionsCollection {
|
||||
snapshot,
|
||||
collection: self,
|
||||
selections_changed: false,
|
||||
cx,
|
||||
};
|
||||
|
||||
let result = change(&mut mutable_collection);
|
||||
@@ -460,13 +447,13 @@ impl SelectionsCollection {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MutableSelectionsCollection<'a> {
|
||||
pub struct MutableSelectionsCollection<'snap, 'a> {
|
||||
collection: &'a mut SelectionsCollection,
|
||||
snapshot: &'snap DisplaySnapshot,
|
||||
selections_changed: bool,
|
||||
cx: &'a mut App,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for MutableSelectionsCollection<'a> {
|
||||
impl<'snap, 'a> fmt::Debug for MutableSelectionsCollection<'snap, 'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("MutableSelectionsCollection")
|
||||
.field("collection", &self.collection)
|
||||
@@ -475,13 +462,9 @@ impl<'a> fmt::Debug for MutableSelectionsCollection<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MutableSelectionsCollection<'a> {
|
||||
pub fn display_map(&mut self) -> DisplaySnapshot {
|
||||
self.collection.display_map(self.cx)
|
||||
}
|
||||
|
||||
pub fn buffer(&self) -> Ref<'_, MultiBufferSnapshot> {
|
||||
self.collection.buffer(self.cx)
|
||||
impl<'snap, 'a> MutableSelectionsCollection<'snap, 'a> {
|
||||
pub fn display_snapshot(&self) -> DisplaySnapshot {
|
||||
self.snapshot.clone()
|
||||
}
|
||||
|
||||
pub fn clear_disjoint(&mut self) {
|
||||
@@ -512,12 +495,11 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn set_pending_anchor_range(&mut self, range: Range<Anchor>, mode: SelectMode) {
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
self.collection.pending = Some(PendingSelection {
|
||||
selection: {
|
||||
let mut start = range.start;
|
||||
let mut end = range.end;
|
||||
let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
let reversed = if start.cmp(&end, self.snapshot).is_gt() {
|
||||
mem::swap(&mut start, &mut end);
|
||||
true
|
||||
} else {
|
||||
@@ -557,7 +539,7 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !oldest.start.cmp(&oldest.end, &self.buffer()).is_eq() {
|
||||
if !oldest.start.cmp(&oldest.end, self.snapshot).is_eq() {
|
||||
let head = oldest.head();
|
||||
oldest.start = head;
|
||||
oldest.end = head;
|
||||
@@ -573,10 +555,10 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
where
|
||||
T: 'a + ToOffset + ToPoint + TextDimension + Ord + Sub<T, Output = T> + std::marker::Copy,
|
||||
{
|
||||
let display_map = self.display_map();
|
||||
let display_map = self.display_snapshot();
|
||||
let mut selections = self.collection.all(&display_map);
|
||||
let mut start = range.start.to_offset(&self.buffer());
|
||||
let mut end = range.end.to_offset(&self.buffer());
|
||||
let mut start = range.start.to_offset(self.snapshot);
|
||||
let mut end = range.end.to_offset(self.snapshot);
|
||||
let reversed = if start > end {
|
||||
mem::swap(&mut start, &mut end);
|
||||
true
|
||||
@@ -597,10 +579,9 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
where
|
||||
T: ToOffset + std::marker::Copy + std::fmt::Debug,
|
||||
{
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
let mut selections = selections
|
||||
.into_iter()
|
||||
.map(|selection| selection.map(|it| it.to_offset(&buffer)))
|
||||
.map(|selection| selection.map(|it| it.to_offset(self.snapshot)))
|
||||
.map(|mut selection| {
|
||||
if selection.start > selection.end {
|
||||
mem::swap(&mut selection.start, &mut selection.end);
|
||||
@@ -629,14 +610,14 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
self.collection.disjoint = Arc::from_iter(
|
||||
selections
|
||||
.into_iter()
|
||||
.map(|selection| selection_to_anchor_selection(selection, &buffer)),
|
||||
.map(|selection| selection_to_anchor_selection(selection, self.snapshot)),
|
||||
);
|
||||
self.collection.pending = None;
|
||||
self.selections_changed = true;
|
||||
}
|
||||
|
||||
pub fn select_anchors(&mut self, selections: Vec<Selection<Anchor>>) {
|
||||
let map = self.display_map();
|
||||
let map = self.display_snapshot();
|
||||
let resolved_selections =
|
||||
resolve_selections_wrapping_blocks::<usize, _>(&selections, &map).collect::<Vec<_>>();
|
||||
self.select(resolved_selections);
|
||||
@@ -647,10 +628,9 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
I: IntoIterator<Item = Range<T>>,
|
||||
T: ToOffset,
|
||||
{
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
let ranges = ranges
|
||||
.into_iter()
|
||||
.map(|range| range.start.to_offset(&buffer)..range.end.to_offset(&buffer));
|
||||
.map(|range| range.start.to_offset(self.snapshot)..range.end.to_offset(self.snapshot));
|
||||
self.select_offset_ranges(ranges);
|
||||
}
|
||||
|
||||
@@ -686,13 +666,12 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
where
|
||||
I: IntoIterator<Item = Range<Anchor>>,
|
||||
{
|
||||
let buffer = self.buffer.read(self.cx).snapshot(self.cx);
|
||||
let selections = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
let mut start = range.start;
|
||||
let mut end = range.end;
|
||||
let reversed = if start.cmp(&end, &buffer).is_gt() {
|
||||
let reversed = if start.cmp(&end, self.snapshot).is_gt() {
|
||||
mem::swap(&mut start, &mut end);
|
||||
true
|
||||
} else {
|
||||
@@ -718,7 +697,6 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
where
|
||||
T: IntoIterator<Item = Range<DisplayPoint>>,
|
||||
{
|
||||
let display_map = self.display_map();
|
||||
let selections = ranges
|
||||
.into_iter()
|
||||
.map(|range| {
|
||||
@@ -732,8 +710,8 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
};
|
||||
Selection {
|
||||
id: post_inc(&mut self.collection.next_selection_id),
|
||||
start: start.to_point(&display_map),
|
||||
end: end.to_point(&display_map),
|
||||
start: start.to_point(self.snapshot),
|
||||
end: end.to_point(self.snapshot),
|
||||
reversed,
|
||||
goal: SelectionGoal::None,
|
||||
}
|
||||
@@ -743,7 +721,6 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
}
|
||||
|
||||
pub fn reverse_selections(&mut self) {
|
||||
let map = &self.display_map();
|
||||
let mut new_selections: Vec<Selection<Point>> = Vec::new();
|
||||
let disjoint = self.disjoint.clone();
|
||||
for selection in disjoint
|
||||
@@ -753,8 +730,14 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
{
|
||||
new_selections.push(Selection {
|
||||
id: self.new_selection_id(),
|
||||
start: selection.start.to_display_point(map).to_point(map),
|
||||
end: selection.end.to_display_point(map).to_point(map),
|
||||
start: selection
|
||||
.start
|
||||
.to_display_point(self.snapshot)
|
||||
.to_point(self.snapshot),
|
||||
end: selection
|
||||
.end
|
||||
.to_display_point(self.snapshot)
|
||||
.to_point(self.snapshot),
|
||||
reversed: selection.reversed,
|
||||
goal: selection.goal,
|
||||
});
|
||||
@@ -767,7 +750,7 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
mut move_selection: impl FnMut(&DisplaySnapshot, &mut Selection<DisplayPoint>),
|
||||
) {
|
||||
let mut changed = false;
|
||||
let display_map = self.display_map();
|
||||
let display_map = self.display_snapshot();
|
||||
let selections = self.collection.all_display(&display_map);
|
||||
let selections = selections
|
||||
.into_iter()
|
||||
@@ -791,22 +774,20 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
mut move_selection: impl FnMut(&MultiBufferSnapshot, &mut Selection<usize>),
|
||||
) {
|
||||
let mut changed = false;
|
||||
let snapshot = self.buffer().clone();
|
||||
let display_map = self.display_map();
|
||||
let display_map = self.display_snapshot();
|
||||
let selections = self
|
||||
.collection
|
||||
.all::<usize>(&display_map)
|
||||
.into_iter()
|
||||
.map(|selection| {
|
||||
let mut moved_selection = selection.clone();
|
||||
move_selection(&snapshot, &mut moved_selection);
|
||||
move_selection(self.snapshot, &mut moved_selection);
|
||||
if selection != moved_selection {
|
||||
changed = true;
|
||||
}
|
||||
moved_selection
|
||||
})
|
||||
.collect();
|
||||
drop(snapshot);
|
||||
|
||||
if changed {
|
||||
self.select(selections)
|
||||
@@ -858,11 +839,10 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
&mut self,
|
||||
find_replacement_cursors: impl FnOnce(&DisplaySnapshot) -> Vec<DisplayPoint>,
|
||||
) {
|
||||
let display_map = self.display_map();
|
||||
let new_selections = find_replacement_cursors(&display_map)
|
||||
let new_selections = find_replacement_cursors(self.snapshot)
|
||||
.into_iter()
|
||||
.map(|cursor| {
|
||||
let cursor_point = cursor.to_point(&display_map);
|
||||
let cursor_point = cursor.to_point(self.snapshot);
|
||||
Selection {
|
||||
id: post_inc(&mut self.collection.next_selection_id),
|
||||
start: cursor_point,
|
||||
@@ -886,12 +866,11 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
let mut selections_with_lost_position = HashMap::default();
|
||||
|
||||
let anchors_with_status = {
|
||||
let buffer = self.buffer();
|
||||
let disjoint_anchors = self
|
||||
.disjoint
|
||||
.iter()
|
||||
.flat_map(|selection| [&selection.start, &selection.end]);
|
||||
buffer.refresh_anchors(disjoint_anchors)
|
||||
self.snapshot.refresh_anchors(disjoint_anchors)
|
||||
};
|
||||
let adjusted_disjoint: Vec<_> = anchors_with_status
|
||||
.chunks(2)
|
||||
@@ -919,16 +898,16 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
.collect();
|
||||
|
||||
if !adjusted_disjoint.is_empty() {
|
||||
let map = self.display_map();
|
||||
let map = self.display_snapshot();
|
||||
let resolved_selections =
|
||||
resolve_selections_wrapping_blocks(adjusted_disjoint.iter(), &map).collect();
|
||||
self.select::<usize>(resolved_selections);
|
||||
}
|
||||
|
||||
if let Some(pending) = pending.as_mut() {
|
||||
let buffer = self.buffer();
|
||||
let anchors =
|
||||
buffer.refresh_anchors([&pending.selection.start, &pending.selection.end]);
|
||||
let anchors = self
|
||||
.snapshot
|
||||
.refresh_anchors([&pending.selection.start, &pending.selection.end]);
|
||||
let (_, start, kept_start) = anchors[0];
|
||||
let (_, end, kept_end) = anchors[1];
|
||||
let kept_head = if pending.selection.reversed {
|
||||
@@ -951,14 +930,14 @@ impl<'a> MutableSelectionsCollection<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for MutableSelectionsCollection<'_> {
|
||||
impl Deref for MutableSelectionsCollection<'_, '_> {
|
||||
type Target = SelectionsCollection;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.collection
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for MutableSelectionsCollection<'_> {
|
||||
impl DerefMut for MutableSelectionsCollection<'_, '_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.collection
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ use settings::{Settings, SettingsStore, StatusStyle};
|
||||
use std::future::Future;
|
||||
use std::ops::Range;
|
||||
use std::path::Path;
|
||||
use std::{collections::HashSet, sync::Arc, time::Duration, usize};
|
||||
use std::{collections::HashSet, sync::Arc, usize};
|
||||
use strum::{IntoEnumIterator, VariantNames};
|
||||
use time::OffsetDateTime;
|
||||
use ui::{
|
||||
@@ -176,8 +176,6 @@ fn git_panel_context_menu(
|
||||
|
||||
const GIT_PANEL_KEY: &str = "GitPanel";
|
||||
|
||||
const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
|
||||
|
||||
pub fn register(workspace: &mut Workspace) {
|
||||
workspace.register_action(|workspace, _: &ToggleFocus, window, cx| {
|
||||
workspace.toggle_panel_focus::<GitPanel>(window, cx);
|
||||
@@ -2582,7 +2580,6 @@ impl GitPanel {
|
||||
let handle = cx.entity().downgrade();
|
||||
self.reopen_commit_buffer(window, cx);
|
||||
self.update_visible_entries_task = cx.spawn_in(window, async move |_, cx| {
|
||||
cx.background_executor().timer(UPDATE_DEBOUNCE).await;
|
||||
if let Some(git_panel) = handle.upgrade() {
|
||||
git_panel
|
||||
.update_in(cx, |git_panel, window, cx| {
|
||||
@@ -5074,11 +5071,10 @@ mod tests {
|
||||
|
||||
let panel = workspace.update(cx, GitPanel::new).unwrap();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
pretty_assertions::assert_eq!(
|
||||
@@ -5100,11 +5096,10 @@ mod tests {
|
||||
],
|
||||
);
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
pretty_assertions::assert_eq!(
|
||||
entries,
|
||||
@@ -5195,11 +5190,10 @@ mod tests {
|
||||
|
||||
let panel = workspace.update(cx, GitPanel::new).unwrap();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5244,11 +5238,10 @@ mod tests {
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5293,11 +5286,10 @@ mod tests {
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5387,11 +5379,10 @@ mod tests {
|
||||
|
||||
let panel = workspace.update(cx, GitPanel::new).unwrap();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5460,11 +5451,10 @@ mod tests {
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5519,11 +5509,10 @@ mod tests {
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let handle = cx.update_window_entity(&panel, |panel, _, _| {
|
||||
cx.update_window_entity(&panel, |panel, _, _| {
|
||||
std::mem::replace(&mut panel.update_visible_entries_task, Task::ready(()))
|
||||
});
|
||||
cx.executor().advance_clock(2 * UPDATE_DEBOUNCE);
|
||||
handle.await;
|
||||
})
|
||||
.await;
|
||||
|
||||
let entries = panel.read_with(cx, |panel, _| panel.entries.clone());
|
||||
#[rustfmt::skip]
|
||||
@@ -5649,6 +5638,21 @@ mod tests {
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
let panel = workspace.update(cx, GitPanel::new).unwrap();
|
||||
|
||||
cx.read(|cx| {
|
||||
project
|
||||
.read(cx)
|
||||
.worktrees(cx)
|
||||
.next()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.as_local()
|
||||
.unwrap()
|
||||
.scan_complete()
|
||||
})
|
||||
.await;
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
// Enable the `sort_by_path` setting and wait for entries to be updated,
|
||||
// as there should no longer be separators between Tracked and Untracked
|
||||
// files.
|
||||
|
||||
@@ -211,8 +211,8 @@ impl DirectWriteTextSystem {
|
||||
})))
|
||||
}
|
||||
|
||||
pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) {
|
||||
self.0.write().handle_gpu_lost(directx_devices);
|
||||
pub(crate) fn handle_gpu_lost(&self, directx_devices: &DirectXDevices) -> Result<()> {
|
||||
self.0.write().handle_gpu_lost(directx_devices)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1215,18 +1215,11 @@ impl DirectWriteState {
|
||||
result
|
||||
}
|
||||
|
||||
fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) {
|
||||
try_to_recover_from_device_lost(
|
||||
|| GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite"),
|
||||
|gpu_state| self.components.gpu_state = gpu_state,
|
||||
|| {
|
||||
log::error!(
|
||||
"Failed to recreate GPU state for DirectWrite after multiple attempts."
|
||||
);
|
||||
// Do something here?
|
||||
// At this point, the device loss is considered unrecoverable.
|
||||
},
|
||||
);
|
||||
fn handle_gpu_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> {
|
||||
try_to_recover_from_device_lost(|| {
|
||||
GPUState::new(directx_devices).context("Recreating GPU state for DirectWrite")
|
||||
})
|
||||
.map(|gpu_state| self.components.gpu_state = gpu_state)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use anyhow::{Context, Result};
|
||||
use itertools::Itertools;
|
||||
use util::ResultExt;
|
||||
use windows::Win32::{
|
||||
Foundation::HMODULE,
|
||||
@@ -20,24 +21,18 @@ use windows::Win32::{
|
||||
};
|
||||
use windows::core::Interface;
|
||||
|
||||
pub(crate) fn try_to_recover_from_device_lost<T>(
|
||||
mut f: impl FnMut() -> Result<T>,
|
||||
on_success: impl FnOnce(T),
|
||||
on_error: impl FnOnce(),
|
||||
) {
|
||||
let result = (0..5).find_map(|i| {
|
||||
if i > 0 {
|
||||
// Add a small delay before retrying
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
f().log_err()
|
||||
});
|
||||
|
||||
if let Some(result) = result {
|
||||
on_success(result);
|
||||
} else {
|
||||
on_error();
|
||||
}
|
||||
pub(crate) fn try_to_recover_from_device_lost<T>(mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||
(0..5)
|
||||
.map(|i| {
|
||||
if i > 0 {
|
||||
// Add a small delay before retrying
|
||||
std::thread::sleep(std::time::Duration::from_millis(100 + i * 10));
|
||||
}
|
||||
f()
|
||||
})
|
||||
.find_or_last(Result::is_ok)
|
||||
.unwrap()
|
||||
.context("DirectXRenderer failed to recover from lost device after multiple attempts")
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
mem::ManuallyDrop,
|
||||
slice,
|
||||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
@@ -39,12 +39,15 @@ pub(crate) struct FontInfo {
|
||||
pub(crate) struct DirectXRenderer {
|
||||
hwnd: HWND,
|
||||
atlas: Arc<DirectXAtlas>,
|
||||
devices: ManuallyDrop<DirectXRendererDevices>,
|
||||
resources: ManuallyDrop<DirectXResources>,
|
||||
devices: Option<DirectXRendererDevices>,
|
||||
resources: Option<DirectXResources>,
|
||||
globals: DirectXGlobalElements,
|
||||
pipelines: DirectXRenderPipelines,
|
||||
direct_composition: Option<DirectComposition>,
|
||||
font_info: &'static FontInfo,
|
||||
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
/// Direct3D objects
|
||||
@@ -60,19 +63,17 @@ pub(crate) struct DirectXRendererDevices {
|
||||
struct DirectXResources {
|
||||
// Direct3D rendering objects
|
||||
swap_chain: IDXGISwapChain1,
|
||||
render_target: ManuallyDrop<ID3D11Texture2D>,
|
||||
render_target_view: [Option<ID3D11RenderTargetView>; 1],
|
||||
render_target: Option<ID3D11Texture2D>,
|
||||
render_target_view: Option<ID3D11RenderTargetView>,
|
||||
|
||||
// Path intermediate textures (with MSAA)
|
||||
path_intermediate_texture: ID3D11Texture2D,
|
||||
path_intermediate_srv: [Option<ID3D11ShaderResourceView>; 1],
|
||||
path_intermediate_srv: Option<ID3D11ShaderResourceView>,
|
||||
path_intermediate_msaa_texture: ID3D11Texture2D,
|
||||
path_intermediate_msaa_view: [Option<ID3D11RenderTargetView>; 1],
|
||||
path_intermediate_msaa_view: Option<ID3D11RenderTargetView>,
|
||||
|
||||
// Cached window size and viewport
|
||||
width: u32,
|
||||
height: u32,
|
||||
viewport: [D3D11_VIEWPORT; 1],
|
||||
// Cached viewport
|
||||
viewport: D3D11_VIEWPORT,
|
||||
}
|
||||
|
||||
struct DirectXRenderPipelines {
|
||||
@@ -86,8 +87,8 @@ struct DirectXRenderPipelines {
|
||||
}
|
||||
|
||||
struct DirectXGlobalElements {
|
||||
global_params_buffer: [Option<ID3D11Buffer>; 1],
|
||||
sampler: [Option<ID3D11SamplerState>; 1],
|
||||
global_params_buffer: Option<ID3D11Buffer>,
|
||||
sampler: Option<ID3D11SamplerState>,
|
||||
}
|
||||
|
||||
struct DirectComposition {
|
||||
@@ -100,7 +101,7 @@ impl DirectXRendererDevices {
|
||||
pub(crate) fn new(
|
||||
directx_devices: &DirectXDevices,
|
||||
disable_direct_composition: bool,
|
||||
) -> Result<ManuallyDrop<Self>> {
|
||||
) -> Result<Self> {
|
||||
let DirectXDevices {
|
||||
adapter,
|
||||
dxgi_factory,
|
||||
@@ -113,13 +114,13 @@ impl DirectXRendererDevices {
|
||||
Some(device.cast().context("Creating DXGI device")?)
|
||||
};
|
||||
|
||||
Ok(ManuallyDrop::new(Self {
|
||||
Ok(Self {
|
||||
adapter: adapter.clone(),
|
||||
dxgi_factory: dxgi_factory.clone(),
|
||||
device: device.clone(),
|
||||
device_context: device_context.clone(),
|
||||
dxgi_device,
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,12 +159,14 @@ impl DirectXRenderer {
|
||||
Ok(DirectXRenderer {
|
||||
hwnd,
|
||||
atlas,
|
||||
devices,
|
||||
resources,
|
||||
devices: Some(devices),
|
||||
resources: Some(resources),
|
||||
globals,
|
||||
pipelines,
|
||||
direct_composition,
|
||||
font_info: Self::get_font_info(),
|
||||
width: 1,
|
||||
height: 1,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -172,55 +175,49 @@ impl DirectXRenderer {
|
||||
}
|
||||
|
||||
fn pre_draw(&self) -> Result<()> {
|
||||
let resources = self.resources.as_ref().expect("resources missing");
|
||||
let device_context = &self
|
||||
.devices
|
||||
.as_ref()
|
||||
.expect("devices missing")
|
||||
.device_context;
|
||||
update_buffer(
|
||||
&self.devices.device_context,
|
||||
self.globals.global_params_buffer[0].as_ref().unwrap(),
|
||||
device_context,
|
||||
self.globals.global_params_buffer.as_ref().unwrap(),
|
||||
&[GlobalParams {
|
||||
gamma_ratios: self.font_info.gamma_ratios,
|
||||
viewport_size: [
|
||||
self.resources.viewport[0].Width,
|
||||
self.resources.viewport[0].Height,
|
||||
],
|
||||
viewport_size: [resources.viewport.Width, resources.viewport.Height],
|
||||
grayscale_enhanced_contrast: self.font_info.grayscale_enhanced_contrast,
|
||||
_pad: 0,
|
||||
}],
|
||||
)?;
|
||||
unsafe {
|
||||
self.devices.device_context.ClearRenderTargetView(
|
||||
self.resources.render_target_view[0].as_ref().unwrap(),
|
||||
&[0.0; 4],
|
||||
);
|
||||
self.devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(&self.resources.render_target_view), None);
|
||||
self.devices
|
||||
.device_context
|
||||
.RSSetViewports(Some(&self.resources.viewport));
|
||||
device_context
|
||||
.ClearRenderTargetView(resources.render_target_view.as_ref().unwrap(), &[0.0; 4]);
|
||||
device_context
|
||||
.OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None);
|
||||
device_context.RSSetViewports(Some(slice::from_ref(&resources.viewport)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn present(&mut self) -> Result<()> {
|
||||
let result = unsafe { self.resources.swap_chain.Present(0, DXGI_PRESENT(0)) };
|
||||
let result = unsafe {
|
||||
self.resources
|
||||
.as_ref()
|
||||
.expect("resources missing")
|
||||
.swap_chain
|
||||
.Present(0, DXGI_PRESENT(0))
|
||||
};
|
||||
result.ok().context("Presenting swap chain failed")
|
||||
}
|
||||
|
||||
pub(crate) fn handle_device_lost(&mut self, directx_devices: &DirectXDevices) {
|
||||
try_to_recover_from_device_lost(
|
||||
|| {
|
||||
self.handle_device_lost_impl(directx_devices)
|
||||
.context("DirectXRenderer handling device lost")
|
||||
},
|
||||
|_| {},
|
||||
|| {
|
||||
log::error!(
|
||||
"DirectXRenderer failed to recover from device lost after multiple attempts"
|
||||
);
|
||||
// Do something here?
|
||||
// At this point, the device loss is considered unrecoverable.
|
||||
},
|
||||
);
|
||||
pub(crate) fn handle_device_lost(&mut self, directx_devices: &DirectXDevices) -> Result<()> {
|
||||
try_to_recover_from_device_lost(|| {
|
||||
self.handle_device_lost_impl(directx_devices)
|
||||
.context("DirectXRenderer handling device lost")
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_device_lost_impl(&mut self, directx_devices: &DirectXDevices) -> Result<()> {
|
||||
@@ -228,35 +225,41 @@ impl DirectXRenderer {
|
||||
|
||||
unsafe {
|
||||
#[cfg(debug_assertions)]
|
||||
report_live_objects(&self.devices.device)
|
||||
.context("Failed to report live objects after device lost")
|
||||
.log_err();
|
||||
if let Some(devices) = &self.devices {
|
||||
report_live_objects(&devices.device)
|
||||
.context("Failed to report live objects after device lost")
|
||||
.log_err();
|
||||
}
|
||||
|
||||
ManuallyDrop::drop(&mut self.resources);
|
||||
self.devices.device_context.OMSetRenderTargets(None, None);
|
||||
self.devices.device_context.ClearState();
|
||||
self.devices.device_context.Flush();
|
||||
self.resources.take();
|
||||
if let Some(devices) = &self.devices {
|
||||
devices.device_context.OMSetRenderTargets(None, None);
|
||||
devices.device_context.ClearState();
|
||||
devices.device_context.Flush();
|
||||
#[cfg(debug_assertions)]
|
||||
report_live_objects(&devices.device)
|
||||
.context("Failed to report live objects after device lost")
|
||||
.log_err();
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
report_live_objects(&self.devices.device)
|
||||
.context("Failed to report live objects after device lost")
|
||||
.log_err();
|
||||
|
||||
drop(self.direct_composition.take());
|
||||
ManuallyDrop::drop(&mut self.devices);
|
||||
self.direct_composition.take();
|
||||
self.devices.take();
|
||||
}
|
||||
|
||||
let devices = DirectXRendererDevices::new(directx_devices, disable_direct_composition)
|
||||
.context("Recreating DirectX devices")?;
|
||||
let resources = DirectXResources::new(
|
||||
&devices,
|
||||
self.resources.width,
|
||||
self.resources.height,
|
||||
self.width,
|
||||
self.height,
|
||||
self.hwnd,
|
||||
disable_direct_composition,
|
||||
)?;
|
||||
let globals = DirectXGlobalElements::new(&devices.device)?;
|
||||
let pipelines = DirectXRenderPipelines::new(&devices.device)?;
|
||||
)
|
||||
.context("Creating DirectX resources")?;
|
||||
let globals = DirectXGlobalElements::new(&devices.device)
|
||||
.context("Creating DirectXGlobalElements")?;
|
||||
let pipelines = DirectXRenderPipelines::new(&devices.device)
|
||||
.context("Creating DirectXRenderPipelines")?;
|
||||
|
||||
let direct_composition = if disable_direct_composition {
|
||||
None
|
||||
@@ -269,17 +272,17 @@ impl DirectXRenderer {
|
||||
|
||||
self.atlas
|
||||
.handle_device_lost(&devices.device, &devices.device_context);
|
||||
self.devices = devices;
|
||||
self.resources = resources;
|
||||
|
||||
unsafe {
|
||||
devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None);
|
||||
}
|
||||
self.devices = Some(devices);
|
||||
self.resources = Some(resources);
|
||||
self.globals = globals;
|
||||
self.pipelines = pipelines;
|
||||
self.direct_composition = direct_composition;
|
||||
|
||||
unsafe {
|
||||
self.devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(&self.resources.render_target_view), None);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -318,23 +321,25 @@ impl DirectXRenderer {
|
||||
pub(crate) fn resize(&mut self, new_size: Size<DevicePixels>) -> Result<()> {
|
||||
let width = new_size.width.0.max(1) as u32;
|
||||
let height = new_size.height.0.max(1) as u32;
|
||||
if self.resources.width == width && self.resources.height == height {
|
||||
if self.width == width && self.height == height {
|
||||
return Ok(());
|
||||
}
|
||||
self.resources.width = width;
|
||||
self.resources.height = height;
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
|
||||
// Clear the render target before resizing
|
||||
unsafe { self.devices.device_context.OMSetRenderTargets(None, None) };
|
||||
unsafe { ManuallyDrop::drop(&mut self.resources.render_target) };
|
||||
drop(self.resources.render_target_view[0].take().unwrap());
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
unsafe { devices.device_context.OMSetRenderTargets(None, None) };
|
||||
let resources = self.resources.as_mut().context("resources missing")?;
|
||||
resources.render_target.take();
|
||||
resources.render_target_view.take();
|
||||
|
||||
// Resizing the swap chain requires a call to the underlying DXGI adapter, which can return the device removed error.
|
||||
// The app might have moved to a monitor that's attached to a different graphics device.
|
||||
// When a graphics device is removed or reset, the desktop resolution often changes, resulting in a window size change.
|
||||
// But here we just return the error, because we are handling device lost scenarios elsewhere.
|
||||
unsafe {
|
||||
self.resources
|
||||
resources
|
||||
.swap_chain
|
||||
.ResizeBuffers(
|
||||
BUFFER_COUNT as u32,
|
||||
@@ -346,12 +351,11 @@ impl DirectXRenderer {
|
||||
.context("Failed to resize swap chain")?;
|
||||
}
|
||||
|
||||
self.resources
|
||||
.recreate_resources(&self.devices, width, height)?;
|
||||
resources.recreate_resources(devices, width, height)?;
|
||||
unsafe {
|
||||
self.devices
|
||||
devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(&self.resources.render_target_view), None);
|
||||
.OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -361,15 +365,22 @@ impl DirectXRenderer {
|
||||
if shadows.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
self.pipelines.shadow_pipeline.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
shadows,
|
||||
)?;
|
||||
self.pipelines.shadow_pipeline.draw(
|
||||
&self.devices.device_context,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&devices.device_context,
|
||||
slice::from_ref(
|
||||
&self
|
||||
.resources
|
||||
.as_ref()
|
||||
.context("resources missing")?
|
||||
.viewport,
|
||||
),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
||||
4,
|
||||
shadows.len() as u32,
|
||||
@@ -380,15 +391,22 @@ impl DirectXRenderer {
|
||||
if quads.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
self.pipelines.quad_pipeline.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
quads,
|
||||
)?;
|
||||
self.pipelines.quad_pipeline.draw(
|
||||
&self.devices.device_context,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&devices.device_context,
|
||||
slice::from_ref(
|
||||
&self
|
||||
.resources
|
||||
.as_ref()
|
||||
.context("resources missing")?
|
||||
.viewport,
|
||||
),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
||||
4,
|
||||
quads.len() as u32,
|
||||
@@ -400,18 +418,19 @@ impl DirectXRenderer {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let resources = self.resources.as_ref().context("resources missing")?;
|
||||
// Clear intermediate MSAA texture
|
||||
unsafe {
|
||||
self.devices.device_context.ClearRenderTargetView(
|
||||
self.resources.path_intermediate_msaa_view[0]
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
devices.device_context.ClearRenderTargetView(
|
||||
resources.path_intermediate_msaa_view.as_ref().unwrap(),
|
||||
&[0.0; 4],
|
||||
);
|
||||
// Set intermediate MSAA texture as render target
|
||||
self.devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(&self.resources.path_intermediate_msaa_view), None);
|
||||
devices.device_context.OMSetRenderTargets(
|
||||
Some(slice::from_ref(&resources.path_intermediate_msaa_view)),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
// Collect all vertices and sprites for a single draw call
|
||||
@@ -427,14 +446,15 @@ impl DirectXRenderer {
|
||||
}
|
||||
|
||||
self.pipelines.path_rasterization_pipeline.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
&vertices,
|
||||
)?;
|
||||
|
||||
self.pipelines.path_rasterization_pipeline.draw(
|
||||
&self.devices.device_context,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&devices.device_context,
|
||||
slice::from_ref(&resources.viewport),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
|
||||
vertices.len() as u32,
|
||||
1,
|
||||
@@ -442,17 +462,17 @@ impl DirectXRenderer {
|
||||
|
||||
// Resolve MSAA to non-MSAA intermediate texture
|
||||
unsafe {
|
||||
self.devices.device_context.ResolveSubresource(
|
||||
&self.resources.path_intermediate_texture,
|
||||
devices.device_context.ResolveSubresource(
|
||||
&resources.path_intermediate_texture,
|
||||
0,
|
||||
&self.resources.path_intermediate_msaa_texture,
|
||||
&resources.path_intermediate_msaa_texture,
|
||||
0,
|
||||
RENDER_TARGET_FORMAT,
|
||||
);
|
||||
// Restore main render target
|
||||
self.devices
|
||||
devices
|
||||
.device_context
|
||||
.OMSetRenderTargets(Some(&self.resources.render_target_view), None);
|
||||
.OMSetRenderTargets(Some(slice::from_ref(&resources.render_target_view)), None);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -485,19 +505,21 @@ impl DirectXRenderer {
|
||||
vec![PathSprite { bounds }]
|
||||
};
|
||||
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let resources = self.resources.as_ref().context("resources missing")?;
|
||||
self.pipelines.path_sprite_pipeline.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
&sprites,
|
||||
)?;
|
||||
|
||||
// Draw the sprites with the path texture
|
||||
self.pipelines.path_sprite_pipeline.draw_with_texture(
|
||||
&self.devices.device_context,
|
||||
&self.resources.path_intermediate_srv,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&self.globals.sampler,
|
||||
&devices.device_context,
|
||||
slice::from_ref(&resources.path_intermediate_srv),
|
||||
slice::from_ref(&resources.viewport),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
slice::from_ref(&self.globals.sampler),
|
||||
sprites.len() as u32,
|
||||
)
|
||||
}
|
||||
@@ -506,15 +528,17 @@ impl DirectXRenderer {
|
||||
if underlines.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let resources = self.resources.as_ref().context("resources missing")?;
|
||||
self.pipelines.underline_pipeline.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
underlines,
|
||||
)?;
|
||||
self.pipelines.underline_pipeline.draw(
|
||||
&self.devices.device_context,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&devices.device_context,
|
||||
slice::from_ref(&resources.viewport),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
||||
4,
|
||||
underlines.len() as u32,
|
||||
@@ -529,18 +553,20 @@ impl DirectXRenderer {
|
||||
if sprites.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let resources = self.resources.as_ref().context("resources missing")?;
|
||||
self.pipelines.mono_sprites.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
sprites,
|
||||
)?;
|
||||
let texture_view = self.atlas.get_texture_view(texture_id);
|
||||
self.pipelines.mono_sprites.draw_with_texture(
|
||||
&self.devices.device_context,
|
||||
&devices.device_context,
|
||||
&texture_view,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&self.globals.sampler,
|
||||
slice::from_ref(&resources.viewport),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
slice::from_ref(&self.globals.sampler),
|
||||
sprites.len() as u32,
|
||||
)
|
||||
}
|
||||
@@ -553,18 +579,21 @@ impl DirectXRenderer {
|
||||
if sprites.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let resources = self.resources.as_ref().context("resources missing")?;
|
||||
self.pipelines.poly_sprites.update_buffer(
|
||||
&self.devices.device,
|
||||
&self.devices.device_context,
|
||||
&devices.device,
|
||||
&devices.device_context,
|
||||
sprites,
|
||||
)?;
|
||||
let texture_view = self.atlas.get_texture_view(texture_id);
|
||||
self.pipelines.poly_sprites.draw_with_texture(
|
||||
&self.devices.device_context,
|
||||
&devices.device_context,
|
||||
&texture_view,
|
||||
&self.resources.viewport,
|
||||
&self.globals.global_params_buffer,
|
||||
&self.globals.sampler,
|
||||
slice::from_ref(&resources.viewport),
|
||||
slice::from_ref(&self.globals.global_params_buffer),
|
||||
slice::from_ref(&self.globals.sampler),
|
||||
sprites.len() as u32,
|
||||
)
|
||||
}
|
||||
@@ -577,7 +606,8 @@ impl DirectXRenderer {
|
||||
}
|
||||
|
||||
pub(crate) fn gpu_specs(&self) -> Result<GpuSpecs> {
|
||||
let desc = unsafe { self.devices.adapter.GetDesc1() }?;
|
||||
let devices = self.devices.as_ref().context("devices missing")?;
|
||||
let desc = unsafe { devices.adapter.GetDesc1() }?;
|
||||
let is_software_emulated = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE.0 as u32) != 0;
|
||||
let device_name = String::from_utf16_lossy(&desc.Description)
|
||||
.trim_matches(char::from(0))
|
||||
@@ -592,7 +622,7 @@ impl DirectXRenderer {
|
||||
0x10DE => nvidia::get_driver_version(),
|
||||
0x1002 => amd::get_driver_version(),
|
||||
// For Intel and other vendors, we use the DXGI API to get the driver version.
|
||||
_ => dxgi::get_driver_version(&self.devices.adapter),
|
||||
_ => dxgi::get_driver_version(&devices.adapter),
|
||||
}
|
||||
.context("Failed to get gpu driver info")
|
||||
.log_err()
|
||||
@@ -626,7 +656,7 @@ impl DirectXResources {
|
||||
height: u32,
|
||||
hwnd: HWND,
|
||||
disable_direct_composition: bool,
|
||||
) -> Result<ManuallyDrop<Self>> {
|
||||
) -> Result<Self> {
|
||||
let swap_chain = if disable_direct_composition {
|
||||
create_swap_chain(&devices.dxgi_factory, &devices.device, hwnd, width, height)?
|
||||
} else {
|
||||
@@ -649,18 +679,16 @@ impl DirectXResources {
|
||||
) = create_resources(devices, &swap_chain, width, height)?;
|
||||
set_rasterizer_state(&devices.device, &devices.device_context)?;
|
||||
|
||||
Ok(ManuallyDrop::new(Self {
|
||||
Ok(Self {
|
||||
swap_chain,
|
||||
render_target,
|
||||
render_target: Some(render_target),
|
||||
render_target_view,
|
||||
path_intermediate_texture,
|
||||
path_intermediate_msaa_texture,
|
||||
path_intermediate_msaa_view,
|
||||
path_intermediate_srv,
|
||||
viewport,
|
||||
width,
|
||||
height,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -679,7 +707,7 @@ impl DirectXResources {
|
||||
path_intermediate_msaa_view,
|
||||
viewport,
|
||||
) = create_resources(devices, &self.swap_chain, width, height)?;
|
||||
self.render_target = render_target;
|
||||
self.render_target = Some(render_target);
|
||||
self.render_target_view = render_target_view;
|
||||
self.path_intermediate_texture = path_intermediate_texture;
|
||||
self.path_intermediate_msaa_texture = path_intermediate_msaa_texture;
|
||||
@@ -789,7 +817,7 @@ impl DirectXGlobalElements {
|
||||
};
|
||||
let mut buffer = None;
|
||||
device.CreateBuffer(&desc, None, Some(&mut buffer))?;
|
||||
[buffer]
|
||||
buffer
|
||||
};
|
||||
|
||||
let sampler = unsafe {
|
||||
@@ -807,7 +835,7 @@ impl DirectXGlobalElements {
|
||||
};
|
||||
let mut output = None;
|
||||
device.CreateSamplerState(&desc, Some(&mut output))?;
|
||||
[output]
|
||||
output
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
@@ -832,7 +860,7 @@ struct PipelineState<T> {
|
||||
fragment: ID3D11PixelShader,
|
||||
buffer: ID3D11Buffer,
|
||||
buffer_size: usize,
|
||||
view: [Option<ID3D11ShaderResourceView>; 1],
|
||||
view: Option<ID3D11ShaderResourceView>,
|
||||
blend_state: ID3D11BlendState,
|
||||
_marker: std::marker::PhantomData<T>,
|
||||
}
|
||||
@@ -902,7 +930,7 @@ impl<T> PipelineState<T> {
|
||||
) -> Result<()> {
|
||||
set_pipeline_state(
|
||||
device_context,
|
||||
&self.view,
|
||||
slice::from_ref(&self.view),
|
||||
topology,
|
||||
viewport,
|
||||
&self.vertex,
|
||||
@@ -927,7 +955,7 @@ impl<T> PipelineState<T> {
|
||||
) -> Result<()> {
|
||||
set_pipeline_state(
|
||||
device_context,
|
||||
&self.view,
|
||||
slice::from_ref(&self.view),
|
||||
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
|
||||
viewport,
|
||||
&self.vertex,
|
||||
@@ -964,18 +992,8 @@ struct PathSprite {
|
||||
impl Drop for DirectXRenderer {
|
||||
fn drop(&mut self) {
|
||||
#[cfg(debug_assertions)]
|
||||
report_live_objects(&self.devices.device).ok();
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut self.devices);
|
||||
ManuallyDrop::drop(&mut self.resources);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DirectXResources {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut self.render_target);
|
||||
if let Some(devices) = &self.devices {
|
||||
report_live_objects(&devices.device).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1049,13 +1067,13 @@ fn create_resources(
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<(
|
||||
ManuallyDrop<ID3D11Texture2D>,
|
||||
[Option<ID3D11RenderTargetView>; 1],
|
||||
ID3D11Texture2D,
|
||||
[Option<ID3D11ShaderResourceView>; 1],
|
||||
Option<ID3D11RenderTargetView>,
|
||||
ID3D11Texture2D,
|
||||
[Option<ID3D11RenderTargetView>; 1],
|
||||
[D3D11_VIEWPORT; 1],
|
||||
Option<ID3D11ShaderResourceView>,
|
||||
ID3D11Texture2D,
|
||||
Option<ID3D11RenderTargetView>,
|
||||
D3D11_VIEWPORT,
|
||||
)> {
|
||||
let (render_target, render_target_view) =
|
||||
create_render_target_and_its_view(swap_chain, &devices.device)?;
|
||||
@@ -1079,17 +1097,11 @@ fn create_resources(
|
||||
fn create_render_target_and_its_view(
|
||||
swap_chain: &IDXGISwapChain1,
|
||||
device: &ID3D11Device,
|
||||
) -> Result<(
|
||||
ManuallyDrop<ID3D11Texture2D>,
|
||||
[Option<ID3D11RenderTargetView>; 1],
|
||||
)> {
|
||||
) -> Result<(ID3D11Texture2D, Option<ID3D11RenderTargetView>)> {
|
||||
let render_target: ID3D11Texture2D = unsafe { swap_chain.GetBuffer(0) }?;
|
||||
let mut render_target_view = None;
|
||||
unsafe { device.CreateRenderTargetView(&render_target, None, Some(&mut render_target_view))? };
|
||||
Ok((
|
||||
ManuallyDrop::new(render_target),
|
||||
[Some(render_target_view.unwrap())],
|
||||
))
|
||||
Ok((render_target, render_target_view))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1097,7 +1109,7 @@ fn create_path_intermediate_texture(
|
||||
device: &ID3D11Device,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<(ID3D11Texture2D, [Option<ID3D11ShaderResourceView>; 1])> {
|
||||
) -> Result<(ID3D11Texture2D, Option<ID3D11ShaderResourceView>)> {
|
||||
let texture = unsafe {
|
||||
let mut output = None;
|
||||
let desc = D3D11_TEXTURE2D_DESC {
|
||||
@@ -1122,7 +1134,7 @@ fn create_path_intermediate_texture(
|
||||
let mut shader_resource_view = None;
|
||||
unsafe { device.CreateShaderResourceView(&texture, None, Some(&mut shader_resource_view))? };
|
||||
|
||||
Ok((texture, [Some(shader_resource_view.unwrap())]))
|
||||
Ok((texture, Some(shader_resource_view.unwrap())))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1130,7 +1142,7 @@ fn create_path_intermediate_msaa_texture_and_view(
|
||||
device: &ID3D11Device,
|
||||
width: u32,
|
||||
height: u32,
|
||||
) -> Result<(ID3D11Texture2D, [Option<ID3D11RenderTargetView>; 1])> {
|
||||
) -> Result<(ID3D11Texture2D, Option<ID3D11RenderTargetView>)> {
|
||||
let msaa_texture = unsafe {
|
||||
let mut output = None;
|
||||
let desc = D3D11_TEXTURE2D_DESC {
|
||||
@@ -1153,15 +1165,11 @@ fn create_path_intermediate_msaa_texture_and_view(
|
||||
};
|
||||
let mut msaa_view = None;
|
||||
unsafe { device.CreateRenderTargetView(&msaa_texture, None, Some(&mut msaa_view))? };
|
||||
Ok((msaa_texture, [Some(msaa_view.unwrap())]))
|
||||
Ok((msaa_texture, Some(msaa_view.unwrap())))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_viewport(
|
||||
device_context: &ID3D11DeviceContext,
|
||||
width: f32,
|
||||
height: f32,
|
||||
) -> [D3D11_VIEWPORT; 1] {
|
||||
fn set_viewport(device_context: &ID3D11DeviceContext, width: f32, height: f32) -> D3D11_VIEWPORT {
|
||||
let viewport = [D3D11_VIEWPORT {
|
||||
TopLeftX: 0.0,
|
||||
TopLeftY: 0.0,
|
||||
@@ -1171,7 +1179,7 @@ fn set_viewport(
|
||||
MaxDepth: 1.0,
|
||||
}];
|
||||
unsafe { device_context.RSSetViewports(Some(&viewport)) };
|
||||
viewport
|
||||
viewport[0]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -1299,10 +1307,10 @@ fn create_buffer(
|
||||
fn create_buffer_view(
|
||||
device: &ID3D11Device,
|
||||
buffer: &ID3D11Buffer,
|
||||
) -> Result<[Option<ID3D11ShaderResourceView>; 1]> {
|
||||
) -> Result<Option<ID3D11ShaderResourceView>> {
|
||||
let mut view = None;
|
||||
unsafe { device.CreateShaderResourceView(buffer, None, Some(&mut view)) }?;
|
||||
Ok([view])
|
||||
Ok(view)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -1133,7 +1133,9 @@ impl WindowsWindowInner {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let devices = lparam.0 as *const DirectXDevices;
|
||||
let devices = unsafe { &*devices };
|
||||
lock.renderer.handle_device_lost(&devices);
|
||||
if let Err(err) = lock.renderer.handle_device_lost(&devices) {
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
Some(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
ffi::OsStr,
|
||||
mem::ManuallyDrop,
|
||||
path::{Path, PathBuf},
|
||||
rc::{Rc, Weak},
|
||||
sync::{Arc, atomic::Ordering},
|
||||
@@ -57,7 +56,7 @@ pub(crate) struct WindowsPlatformState {
|
||||
jump_list: JumpList,
|
||||
// NOTE: standard cursor handles don't need to close.
|
||||
pub(crate) current_cursor: Option<HCURSOR>,
|
||||
directx_devices: ManuallyDrop<DirectXDevices>,
|
||||
directx_devices: Option<DirectXDevices>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -76,7 +75,7 @@ impl WindowsPlatformState {
|
||||
let callbacks = PlatformCallbacks::default();
|
||||
let jump_list = JumpList::new();
|
||||
let current_cursor = load_cursor(CursorStyle::Arrow);
|
||||
let directx_devices = ManuallyDrop::new(directx_devices);
|
||||
let directx_devices = Some(directx_devices);
|
||||
|
||||
Self {
|
||||
callbacks,
|
||||
@@ -190,7 +189,7 @@ impl WindowsPlatform {
|
||||
main_receiver: self.inner.main_receiver.clone(),
|
||||
platform_window_handle: self.handle,
|
||||
disable_direct_composition: self.disable_direct_composition,
|
||||
directx_devices: (*self.inner.state.borrow().directx_devices).clone(),
|
||||
directx_devices: self.inner.state.borrow().directx_devices.clone().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +237,7 @@ impl WindowsPlatform {
|
||||
}
|
||||
|
||||
fn begin_vsync_thread(&self) {
|
||||
let mut directx_device = (*self.inner.state.borrow().directx_devices).clone();
|
||||
let mut directx_device = self.inner.state.borrow().directx_devices.clone().unwrap();
|
||||
let platform_window: SafeHwnd = self.handle.into();
|
||||
let validation_number = self.inner.validation_number;
|
||||
let all_windows = Arc::downgrade(&self.raw_window_handles);
|
||||
@@ -250,13 +249,15 @@ impl WindowsPlatform {
|
||||
loop {
|
||||
vsync_provider.wait_for_vsync();
|
||||
if check_device_lost(&directx_device.device) {
|
||||
handle_gpu_device_lost(
|
||||
if let Err(err) = handle_gpu_device_lost(
|
||||
&mut directx_device,
|
||||
platform_window.as_raw(),
|
||||
validation_number,
|
||||
&all_windows,
|
||||
&text_system,
|
||||
);
|
||||
) {
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
}
|
||||
let Some(all_windows) = all_windows.upgrade() else {
|
||||
break;
|
||||
@@ -826,10 +827,8 @@ impl WindowsPlatformInner {
|
||||
let mut lock = self.state.borrow_mut();
|
||||
let directx_devices = lparam.0 as *const DirectXDevices;
|
||||
let directx_devices = unsafe { &*directx_devices };
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut lock.directx_devices);
|
||||
}
|
||||
lock.directx_devices = ManuallyDrop::new(directx_devices.clone());
|
||||
lock.directx_devices.take();
|
||||
lock.directx_devices = Some(directx_devices.clone());
|
||||
|
||||
Some(0)
|
||||
}
|
||||
@@ -846,14 +845,6 @@ impl Drop for WindowsPlatform {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WindowsPlatformState {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
ManuallyDrop::drop(&mut self.directx_devices);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WindowCreationInfo {
|
||||
pub(crate) icon: HICON,
|
||||
pub(crate) executor: ForegroundExecutor,
|
||||
@@ -1077,37 +1068,28 @@ fn handle_gpu_device_lost(
|
||||
validation_number: usize,
|
||||
all_windows: &std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
|
||||
text_system: &std::sync::Weak<DirectWriteTextSystem>,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
// Here we wait a bit to ensure the system has time to recover from the device lost state.
|
||||
// If we don't wait, the final drawing result will be blank.
|
||||
std::thread::sleep(std::time::Duration::from_millis(350));
|
||||
|
||||
try_to_recover_from_device_lost(
|
||||
|| {
|
||||
DirectXDevices::new()
|
||||
.context("Failed to recreate new DirectX devices after device lost")
|
||||
},
|
||||
|new_devices| *directx_devices = new_devices,
|
||||
|| {
|
||||
log::error!("Failed to recover DirectX devices after multiple attempts.");
|
||||
// Do something here?
|
||||
// At this point, the device loss is considered unrecoverable.
|
||||
// std::process::exit(1);
|
||||
},
|
||||
);
|
||||
*directx_devices = try_to_recover_from_device_lost(|| {
|
||||
DirectXDevices::new().context("Failed to recreate new DirectX devices after device lost")
|
||||
})?;
|
||||
log::info!("DirectX devices successfully recreated.");
|
||||
|
||||
let lparam = LPARAM(directx_devices as *const _ as _);
|
||||
unsafe {
|
||||
SendMessageW(
|
||||
platform_window,
|
||||
WM_GPUI_GPU_DEVICE_LOST,
|
||||
Some(WPARAM(validation_number)),
|
||||
Some(LPARAM(directx_devices as *const _ as _)),
|
||||
Some(lparam),
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(text_system) = text_system.upgrade() {
|
||||
text_system.handle_gpu_lost(&directx_devices);
|
||||
text_system.handle_gpu_lost(&directx_devices)?;
|
||||
}
|
||||
if let Some(all_windows) = all_windows.upgrade() {
|
||||
for window in all_windows.read().iter() {
|
||||
@@ -1116,7 +1098,7 @@ fn handle_gpu_device_lost(
|
||||
window.as_raw(),
|
||||
WM_GPUI_GPU_DEVICE_LOST,
|
||||
Some(WPARAM(validation_number)),
|
||||
Some(LPARAM(directx_devices as *const _ as _)),
|
||||
Some(lparam),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1132,6 +1114,7 @@ fn handle_gpu_device_lost(
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const PLATFORM_WINDOW_CLASS_NAME: PCWSTR = w!("Zed::PlatformWindow");
|
||||
|
||||
@@ -410,6 +410,8 @@ impl MultiBuffer {
|
||||
}
|
||||
|
||||
self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx);
|
||||
// todo(lw): There is a logic bug somewhere that causes the to_remove vector to be not ordered correctly
|
||||
to_remove.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id));
|
||||
self.remove_excerpts(to_remove, cx);
|
||||
if excerpt_ids.is_empty() {
|
||||
self.excerpts_by_path.remove(&path);
|
||||
|
||||
@@ -370,7 +370,7 @@ impl RemoteConnection for SshRemoteConnection {
|
||||
|
||||
let ssh_proxy_process = match self
|
||||
.socket
|
||||
.ssh_command(self.ssh_shell_kind, "env", &proxy_args)
|
||||
.ssh_command(self.ssh_shell_kind, "env", &proxy_args, false)
|
||||
// IMPORTANT: we kill this process when we drop the task that uses it.
|
||||
.kill_on_drop(true)
|
||||
.spawn()
|
||||
@@ -578,6 +578,7 @@ impl SshRemoteConnection {
|
||||
self.ssh_shell_kind,
|
||||
&dst_path.display(self.path_style()),
|
||||
&["version"],
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.is_ok()
|
||||
@@ -615,13 +616,13 @@ impl SshRemoteConnection {
|
||||
{
|
||||
Ok(_) => {
|
||||
self.extract_server_binary(&dst_path, &tmp_path_gz, delegate, cx)
|
||||
.await?;
|
||||
.await
|
||||
.context("extracting server binary")?;
|
||||
return Ok(dst_path);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Failed to download binary on server, attempting to upload server: {}",
|
||||
e
|
||||
"Failed to download binary on server, attempting to upload server: {e:#}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -629,11 +630,14 @@ impl SshRemoteConnection {
|
||||
|
||||
let src_path = delegate
|
||||
.download_server_binary_locally(self.ssh_platform, release_channel, wanted_version, cx)
|
||||
.await?;
|
||||
.await
|
||||
.context("downloading server binary locally")?;
|
||||
self.upload_local_server_binary(&src_path, &tmp_path_gz, delegate, cx)
|
||||
.await?;
|
||||
.await
|
||||
.context("uploading server binary")?;
|
||||
self.extract_server_binary(&dst_path, &tmp_path_gz, delegate, cx)
|
||||
.await?;
|
||||
.await
|
||||
.context("extracting server binary")?;
|
||||
Ok(dst_path)
|
||||
}
|
||||
|
||||
@@ -651,6 +655,7 @@ impl SshRemoteConnection {
|
||||
self.ssh_shell_kind,
|
||||
"mkdir",
|
||||
&["-p", parent.display(self.path_style()).as_ref()],
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@@ -675,6 +680,7 @@ impl SshRemoteConnection {
|
||||
"-o",
|
||||
&tmp_path_gz.display(self.path_style()),
|
||||
],
|
||||
true,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -682,7 +688,7 @@ impl SshRemoteConnection {
|
||||
Err(e) => {
|
||||
if self
|
||||
.socket
|
||||
.run_command(self.ssh_shell_kind, "which", &["curl"])
|
||||
.run_command(self.ssh_shell_kind, "which", &["curl"], true)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
@@ -702,6 +708,7 @@ impl SshRemoteConnection {
|
||||
"-O",
|
||||
&tmp_path_gz.display(self.path_style()),
|
||||
],
|
||||
true,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -709,7 +716,7 @@ impl SshRemoteConnection {
|
||||
Err(e) => {
|
||||
if self
|
||||
.socket
|
||||
.run_command(self.ssh_shell_kind, "which", &["wget"])
|
||||
.run_command(self.ssh_shell_kind, "which", &["wget"], true)
|
||||
.await
|
||||
.is_ok()
|
||||
{
|
||||
@@ -738,6 +745,7 @@ impl SshRemoteConnection {
|
||||
self.ssh_shell_kind,
|
||||
"mkdir",
|
||||
&["-p", parent.display(self.path_style()).as_ref()],
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
@@ -778,14 +786,23 @@ impl SshRemoteConnection {
|
||||
let dst_path = dst_path.display(self.path_style());
|
||||
let dst_path = shell_kind.try_quote(&dst_path).context("shell quoting")?;
|
||||
let script = if let Some(tmp_path) = orig_tmp_path.strip_suffix(".gz") {
|
||||
let orig_tmp_path = shell_kind
|
||||
.try_quote(&orig_tmp_path)
|
||||
.context("shell quoting")?;
|
||||
let tmp_path = shell_kind.try_quote(&tmp_path).context("shell quoting")?;
|
||||
format!(
|
||||
"gunzip -f {orig_tmp_path} && chmod {server_mode} {tmp_path} && mv {tmp_path} {dst_path}",
|
||||
)
|
||||
} else {
|
||||
let orig_tmp_path = shell_kind
|
||||
.try_quote(&orig_tmp_path)
|
||||
.context("shell quoting")?;
|
||||
format!("chmod {server_mode} {orig_tmp_path} && mv {orig_tmp_path} {dst_path}",)
|
||||
};
|
||||
let args = shell_kind.args_for_shell(false, script.to_string());
|
||||
self.socket.run_command(shell_kind, "sh", &args).await?;
|
||||
self.socket
|
||||
.run_command(shell_kind, "sh", &args, true)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -934,6 +951,7 @@ impl SshSocket {
|
||||
shell_kind: ShellKind,
|
||||
program: &str,
|
||||
args: &[impl AsRef<str>],
|
||||
allow_pseudo_tty: bool,
|
||||
) -> process::Command {
|
||||
let mut command = util::command::new_smol_command("ssh");
|
||||
let program = shell_kind.prepend_command_prefix(program);
|
||||
@@ -953,9 +971,11 @@ impl SshSocket {
|
||||
let separator = shell_kind.sequential_commands_separator();
|
||||
let to_run = format!("cd{separator} {to_run}");
|
||||
self.ssh_options(&mut command, true)
|
||||
.arg(self.connection_options.ssh_url())
|
||||
.arg("-T")
|
||||
.arg(to_run);
|
||||
.arg(self.connection_options.ssh_url());
|
||||
if !allow_pseudo_tty {
|
||||
command.arg("-T");
|
||||
}
|
||||
command.arg(to_run);
|
||||
log::debug!("ssh {:?}", command);
|
||||
command
|
||||
}
|
||||
@@ -965,8 +985,12 @@ impl SshSocket {
|
||||
shell_kind: ShellKind,
|
||||
program: &str,
|
||||
args: &[impl AsRef<str>],
|
||||
allow_pseudo_tty: bool,
|
||||
) -> Result<String> {
|
||||
let output = self.ssh_command(shell_kind, program, args).output().await?;
|
||||
let output = self
|
||||
.ssh_command(shell_kind, program, args, allow_pseudo_tty)
|
||||
.output()
|
||||
.await?;
|
||||
anyhow::ensure!(
|
||||
output.status.success(),
|
||||
"failed to run command: {}",
|
||||
@@ -1039,7 +1063,7 @@ impl SshSocket {
|
||||
}
|
||||
|
||||
async fn platform(&self, shell: ShellKind) -> Result<RemotePlatform> {
|
||||
let uname = self.run_command(shell, "uname", &["-sm"]).await?;
|
||||
let uname = self.run_command(shell, "uname", &["-sm"], false).await?;
|
||||
let Some((os, arch)) = uname.split_once(" ") else {
|
||||
anyhow::bail!("unknown uname: {uname:?}")
|
||||
};
|
||||
@@ -1072,7 +1096,7 @@ impl SshSocket {
|
||||
async fn shell(&self) -> String {
|
||||
let default_shell = "sh";
|
||||
match self
|
||||
.run_command(ShellKind::Posix, "sh", &["-c", "echo $SHELL"])
|
||||
.run_command(ShellKind::Posix, "sh", &["-c", "echo $SHELL"], false)
|
||||
.await
|
||||
{
|
||||
Ok(shell) => match shell.trim() {
|
||||
|
||||
@@ -1685,7 +1685,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(0));
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||
);
|
||||
});
|
||||
@@ -1696,7 +1698,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||
);
|
||||
});
|
||||
@@ -1707,7 +1711,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||
);
|
||||
});
|
||||
@@ -1718,7 +1724,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||
);
|
||||
});
|
||||
@@ -1729,7 +1737,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||
);
|
||||
});
|
||||
@@ -1740,7 +1750,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||
);
|
||||
});
|
||||
@@ -1751,7 +1763,9 @@ mod tests {
|
||||
search_bar.update_in(cx, |search_bar, window, cx| {
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||
);
|
||||
});
|
||||
@@ -1772,7 +1786,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(1));
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||
);
|
||||
});
|
||||
@@ -1793,7 +1809,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(1));
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 11)..DisplayPoint::new(DisplayRow(3), 13)]
|
||||
);
|
||||
});
|
||||
@@ -1814,7 +1832,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(2));
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||
);
|
||||
});
|
||||
@@ -1835,7 +1855,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(2));
|
||||
search_bar.select_next_match(&SelectNextMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(0), 41)..DisplayPoint::new(DisplayRow(0), 43)]
|
||||
);
|
||||
});
|
||||
@@ -1856,7 +1878,9 @@ mod tests {
|
||||
assert_eq!(search_bar.active_match_index, Some(0));
|
||||
search_bar.select_prev_match(&SelectPreviousMatch, window, cx);
|
||||
assert_eq!(
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(3), 56)..DisplayPoint::new(DisplayRow(3), 58)]
|
||||
);
|
||||
});
|
||||
@@ -1989,7 +2013,7 @@ mod tests {
|
||||
"Initially, the editor should not be focused"
|
||||
);
|
||||
let initial_selections = editor.update(cx, |editor, cx| {
|
||||
let initial_selections = editor.selections.display_ranges(cx);
|
||||
let initial_selections = editor.selections.display_ranges(&editor.display_snapshot(cx));
|
||||
assert_eq!(
|
||||
initial_selections.len(), 1,
|
||||
"Expected to have only one selection before adding carets to all matches, but got: {initial_selections:?}",
|
||||
@@ -2008,7 +2032,7 @@ mod tests {
|
||||
);
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(&editor.display_snapshot(cx)));
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
expected_query_matches_count,
|
||||
@@ -2032,8 +2056,11 @@ mod tests {
|
||||
"Should still have editor focused after SelectNextMatch"
|
||||
);
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
let all_selections = editor.update(cx, |editor, cx| {
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))
|
||||
});
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
1,
|
||||
@@ -2062,7 +2089,7 @@ mod tests {
|
||||
);
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(&editor.display_snapshot(cx)));
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
expected_query_matches_count,
|
||||
@@ -2087,8 +2114,11 @@ mod tests {
|
||||
);
|
||||
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
let all_selections = editor.update(cx, |editor, cx| {
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))
|
||||
});
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
1,
|
||||
@@ -2130,7 +2160,7 @@ mod tests {
|
||||
);
|
||||
search_bar.update(cx, |search_bar, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(&editor.display_snapshot(cx)));
|
||||
assert_eq!(
|
||||
all_selections, last_match_selections,
|
||||
"Should not select anything new if there are no matches"
|
||||
@@ -2194,8 +2224,11 @@ mod tests {
|
||||
search_bar.select_all_matches(&SelectAllMatches, window, cx);
|
||||
});
|
||||
search_bar.update(cx, |_, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
let all_selections = editor.update(cx, |editor, cx| {
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))
|
||||
});
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
2,
|
||||
@@ -2220,8 +2253,11 @@ mod tests {
|
||||
search_bar.select_all_matches(&SelectAllMatches, window, cx);
|
||||
});
|
||||
search_bar.update(cx, |_, cx| {
|
||||
let all_selections =
|
||||
editor.update(cx, |editor, cx| editor.selections.display_ranges(cx));
|
||||
let all_selections = editor.update(cx, |editor, cx| {
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))
|
||||
});
|
||||
assert_eq!(
|
||||
all_selections.len(),
|
||||
2,
|
||||
|
||||
@@ -2526,7 +2526,7 @@ pub mod tests {
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)]
|
||||
);
|
||||
|
||||
@@ -2537,9 +2537,9 @@ pub mod tests {
|
||||
.update(cx, |search_view, window, cx| {
|
||||
assert_eq!(search_view.active_match_index, Some(1));
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
search_view.results_editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)]
|
||||
);
|
||||
search_view.select_match(Direction::Next, window, cx);
|
||||
@@ -2550,9 +2550,9 @@ pub mod tests {
|
||||
.update(cx, |search_view, window, cx| {
|
||||
assert_eq!(search_view.active_match_index, Some(2));
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
search_view.results_editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)]
|
||||
);
|
||||
search_view.select_match(Direction::Next, window, cx);
|
||||
@@ -2563,9 +2563,9 @@ pub mod tests {
|
||||
.update(cx, |search_view, window, cx| {
|
||||
assert_eq!(search_view.active_match_index, Some(0));
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
search_view.results_editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(2), 32)..DisplayPoint::new(DisplayRow(2), 35)]
|
||||
);
|
||||
search_view.select_match(Direction::Prev, window, cx);
|
||||
@@ -2576,9 +2576,9 @@ pub mod tests {
|
||||
.update(cx, |search_view, window, cx| {
|
||||
assert_eq!(search_view.active_match_index, Some(2));
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
search_view.results_editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(5), 6)..DisplayPoint::new(DisplayRow(5), 9)]
|
||||
);
|
||||
search_view.select_match(Direction::Prev, window, cx);
|
||||
@@ -2589,9 +2589,9 @@ pub mod tests {
|
||||
.update(cx, |search_view, _, cx| {
|
||||
assert_eq!(search_view.active_match_index, Some(1));
|
||||
assert_eq!(
|
||||
search_view
|
||||
.results_editor
|
||||
.update(cx, |editor, cx| editor.selections.display_ranges(cx)),
|
||||
search_view.results_editor.update(cx, |editor, cx| editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx))),
|
||||
[DisplayPoint::new(DisplayRow(2), 37)..DisplayPoint::new(DisplayRow(2), 40)]
|
||||
);
|
||||
})
|
||||
|
||||
@@ -38,7 +38,7 @@ impl Vim {
|
||||
.map(|s| s.to_vec())
|
||||
{
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
let map = s.display_map();
|
||||
let map = s.display_snapshot();
|
||||
s.select_display_ranges(selections.iter().map(|a| {
|
||||
let point = a.to_display_point(&map);
|
||||
point..point
|
||||
|
||||
@@ -682,8 +682,9 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||
.disjoint_anchor_ranges()
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
let end = Point::new(range.end.0, s.buffer().line_len(range.end));
|
||||
let end = Point::new(range.end.0, snapshot.line_len(range.end));
|
||||
s.select_ranges([end..Point::new(range.start.0, 0)]);
|
||||
});
|
||||
selections
|
||||
|
||||
@@ -120,8 +120,8 @@ impl Vim {
|
||||
|
||||
editor.edit(edits, cx);
|
||||
|
||||
let snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
let snapshot = s.buffer().clone();
|
||||
s.select_ranges(new_selections.into_iter().map(|(anchor, len)| {
|
||||
let offset = anchor.to_offset(&snapshot);
|
||||
if action.before {
|
||||
|
||||
@@ -1210,7 +1210,7 @@ impl Vim {
|
||||
s.select_anchor_ranges(vec![pos..pos])
|
||||
}
|
||||
|
||||
let snapshot = s.display_map();
|
||||
let snapshot = s.display_snapshot();
|
||||
if let Some(pending) = s.pending_anchor_mut()
|
||||
&& pending.reversed
|
||||
&& mode.is_visual()
|
||||
|
||||
@@ -179,7 +179,7 @@ pub fn register(editor: &mut Editor, cx: &mut Context<Vim>) {
|
||||
vim.update_editor(cx, |_, editor, cx| {
|
||||
editor.set_clip_at_line_ends(false, cx);
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
let map = s.display_map();
|
||||
let map = s.display_snapshot();
|
||||
let ranges = ranges
|
||||
.into_iter()
|
||||
.map(|(start, end, reversed)| {
|
||||
@@ -304,7 +304,7 @@ impl Vim {
|
||||
) {
|
||||
let text_layout_details = editor.text_layout_details(window);
|
||||
editor.change_selections(Default::default(), window, cx, |s| {
|
||||
let map = &s.display_map();
|
||||
let map = &s.display_snapshot();
|
||||
let mut head = s.newest_anchor().head().to_display_point(map);
|
||||
let mut tail = s.oldest_anchor().tail().to_display_point(map);
|
||||
|
||||
|
||||
@@ -4071,7 +4071,9 @@ mod tests {
|
||||
let editor = item.downcast::<Editor>().unwrap();
|
||||
let (selections, scroll_position) = editor.update(cx, |editor, cx| {
|
||||
(
|
||||
editor.selections.display_ranges(cx),
|
||||
editor
|
||||
.selections
|
||||
.display_ranges(&editor.display_snapshot(cx)),
|
||||
editor.scroll_position(cx),
|
||||
)
|
||||
});
|
||||
|
||||
@@ -5,4 +5,5 @@ if [[ "$GITHUB_REF_NAME" == *"-pre" ]]; then
|
||||
preview="-p"
|
||||
fi
|
||||
|
||||
gh release create -t "$GITHUB_REF_NAME" -d "$GITHUB_REF_NAME" -F "$1" $preview
|
||||
gh release view "$GITHUB_REF_NAME" ||\
|
||||
gh release create -t "$GITHUB_REF_NAME" -d "$GITHUB_REF_NAME" -F "$1" $preview
|
||||
|
||||
@@ -88,14 +88,14 @@ fn post_to_discord(deps: &[&NamedJob]) -> NamedJob {
|
||||
|
||||
fn publish_winget() -> NamedJob {
|
||||
fn set_package_name() -> (Step<Run>, StepOutput) {
|
||||
let step = named::bash(indoc::indoc! {r#"
|
||||
if [ "${{ github.event.release.prerelease }}" == "true" ]; then
|
||||
PACKAGE_NAME=ZedIndustries.Zed.Preview
|
||||
else
|
||||
PACKAGE_NAME=ZedIndustries.Zed
|
||||
fi
|
||||
let step = named::pwsh(indoc::indoc! {r#"
|
||||
if ("${{ github.event.release.prerelease }}" -eq "true") {
|
||||
$PACKAGE_NAME = "ZedIndustries.Zed.Preview"
|
||||
} else {
|
||||
$PACKAGE_NAME = "ZedIndustries.Zed"
|
||||
}
|
||||
|
||||
echo "PACKAGE_NAME=$PACKAGE_NAME" >> "$GITHUB_OUTPUT"
|
||||
echo "PACKAGE_NAME=$PACKAGE_NAME" >> $env:GITHUB_OUTPUT
|
||||
"#})
|
||||
.id("set-package-name");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user