editor: Represent scroll offset with more precision (#39367)

Piotr Osiewicz and Smit Barmase created

Closes #5355

Release Notes:

- Fixed rendering glitches with files with more than 16 million lines
(that occured due to floating number rounding errors).

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>

Change summary

Cargo.lock                                                        |   4 
Cargo.toml                                                        |   1 
crates/agent_ui/src/acp/thread_view.rs                            |  24 
crates/agent_ui/src/inline_assistant.rs                           |  25 
crates/agent_ui/src/text_thread_editor.rs                         |   7 
crates/assistant_tools/src/edit_file_tool.rs                      |   4 
crates/debugger_ui/src/session/running/variable_list.rs           |   2 
crates/editor/src/display_map.rs                                  |  14 
crates/editor/src/display_map/block_map.rs                        |   2 
crates/editor/src/editor.rs                                       |  93 
crates/editor/src/editor_settings.rs                              |   4 
crates/editor/src/editor_tests.rs                                 |   6 
crates/editor/src/element.rs                                      | 397 
crates/editor/src/items.rs                                        |   4 
crates/editor/src/mouse_context_menu.rs                           |   2 
crates/editor/src/movement.rs                                     |  33 
crates/editor/src/persistence.rs                                  |   6 
crates/editor/src/scroll.rs                                       |  61 
crates/editor/src/scroll/actions.rs                               |   4 
crates/editor/src/scroll/autoscroll.rs                            |  54 
crates/editor/src/scroll/scroll_amount.rs                         |  22 
crates/editor/src/test/editor_test_context.rs                     |   3 
crates/file_finder/src/file_finder.rs                             |   6 
crates/git_ui/src/commit_modal.rs                                 |   3 
crates/go_to_line/src/go_to_line.rs                               |   5 
crates/gpui/examples/image_loading.rs                             |  10 
crates/gpui/examples/text.rs                                      |   6 
crates/gpui/src/elements/img.rs                                   |   2 
crates/gpui/src/geometry.rs                                       | 122 
crates/gpui/src/platform/linux/x11/window.rs                      |   2 
crates/gpui/src/text_system/line.rs                               |   2 
crates/gpui/src/window.rs                                         |   2 
crates/image_viewer/src/image_viewer.rs                           |   8 
crates/language_model/src/request.rs                              |   4 
crates/markdown/examples/markdown_as_child.rs                     |   2 
crates/outline/src/outline.rs                                     |   3 
crates/outline_panel/src/outline_panel.rs                         |   2 
crates/proto/proto/call.proto                                     |  12 
crates/repl/src/outputs/image.rs                                  |  10 
crates/repl/src/outputs/plain.rs                                  |   2 
crates/search/src/project_search.rs                               |   2 
crates/settings_profile_selector/src/settings_profile_selector.rs |  28 
crates/storybook/src/stories/with_rem_size.rs                     |   2 
crates/terminal_view/src/terminal_element.rs                      |   7 
crates/terminal_view/src/terminal_scrollbar.rs                    |  10 
crates/text/src/selection.rs                                      |   4 
crates/title_bar/src/collab.rs                                    |   2 
crates/ui/src/components/keybinding_hint.rs                       |   2 
crates/ui/src/components/list/list_bullet_item.rs                 |   2 
crates/ui/src/styles/typography.rs                                |   4 
crates/ui/src/styles/units.rs                                     |   4 
crates/ui/src/utils/search_input.rs                               |  10 
crates/vim/src/motion.rs                                          |   8 
crates/vim/src/normal/scroll.rs                                   |   6 
crates/vim/src/test/neovim_backed_test_context.rs                 |   2 
crates/vim/src/visual.rs                                          |   6 
crates/workspace/src/dock.rs                                      |   4 
crates/workspace/src/pane_group.rs                                |   4 
crates/workspace/src/persistence.rs                               |   2 
crates/workspace/src/workspace.rs                                 |   2 
crates/zed/src/zed.rs                                             |  10 
61 files changed, 626 insertions(+), 470 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -13603,9 +13603,9 @@ dependencies = [
 
 [[package]]
 name = "rust_decimal"
-version = "1.37.1"
+version = "1.38.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faa7de2ba56ac291bd90c6b9bece784a52ae1411f9506544b3eae36dd2356d50"
+checksum = "c8975fc98059f365204d635119cf9c5a60ae67b841ed49b5422a9a7e56cdfac0"
 dependencies = [
  "arrayvec",
  "borsh",

Cargo.toml 🔗

@@ -548,6 +548,7 @@ nanoid = "0.4"
 nbformat = {  git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
 nix = "0.29"
 num-format = "0.4.4"
+num-traits = "0.2"
 objc = "0.2"
 objc2-foundation = { version = "0.3", default-features = false, features = [
     "NSArray",

crates/agent_ui/src/acp/thread_view.rs 🔗

@@ -5559,23 +5559,23 @@ fn default_markdown_style(
         }),
         code_block: StyleRefinement {
             padding: EdgesRefinement {
-                top: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(Pixels(8.)))),
-                left: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(Pixels(8.)))),
-                right: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(Pixels(8.)))),
-                bottom: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(Pixels(8.)))),
+                top: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(px(8.)))),
+                left: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(px(8.)))),
+                right: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(px(8.)))),
+                bottom: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(px(8.)))),
             },
             margin: EdgesRefinement {
-                top: Some(Length::Definite(Pixels(8.).into())),
-                left: Some(Length::Definite(Pixels(0.).into())),
-                right: Some(Length::Definite(Pixels(0.).into())),
-                bottom: Some(Length::Definite(Pixels(12.).into())),
+                top: Some(Length::Definite(px(8.).into())),
+                left: Some(Length::Definite(px(0.).into())),
+                right: Some(Length::Definite(px(0.).into())),
+                bottom: Some(Length::Definite(px(12.).into())),
             },
             border_style: Some(BorderStyle::Solid),
             border_widths: EdgesRefinement {
-                top: Some(AbsoluteLength::Pixels(Pixels(1.))),
-                left: Some(AbsoluteLength::Pixels(Pixels(1.))),
-                right: Some(AbsoluteLength::Pixels(Pixels(1.))),
-                bottom: Some(AbsoluteLength::Pixels(Pixels(1.))),
+                top: Some(AbsoluteLength::Pixels(px(1.))),
+                left: Some(AbsoluteLength::Pixels(px(1.))),
+                right: Some(AbsoluteLength::Pixels(px(1.))),
+                bottom: Some(AbsoluteLength::Pixels(px(1.))),
             },
             border_color: Some(colors.border_variant),
             background: Some(colors.editor_background.into()),

crates/agent_ui/src/inline_assistant.rs 🔗

@@ -18,7 +18,9 @@ use agent_settings::AgentSettings;
 use anyhow::{Context as _, Result};
 use client::telemetry::Telemetry;
 use collections::{HashMap, HashSet, VecDeque, hash_map};
+use editor::RowExt;
 use editor::SelectionEffects;
+use editor::scroll::ScrollOffset;
 use editor::{
     Anchor, AnchorRangeExt, CodeActionProvider, Editor, EditorEvent, ExcerptId, ExcerptRange,
     MultiBuffer, MultiBufferSnapshot, ToOffset as _, ToPoint,
@@ -744,7 +746,7 @@ impl InlineAssistant {
                 let scroll_bottom = scroll_top + editor.visible_line_count().unwrap_or(0.);
                 editor_assists.scroll_lock = editor
                     .row_for_block(decorations.prompt_block_id, cx)
-                    .map(|row| row.0 as f32)
+                    .map(|row| row.as_f64())
                     .filter(|prompt_row| (scroll_top..scroll_bottom).contains(&prompt_row))
                     .map(|prompt_row| InlineAssistScrollLock {
                         assist_id,
@@ -910,7 +912,9 @@ impl InlineAssistant {
 
         editor.update(cx, |editor, cx| {
             let scroll_position = editor.scroll_position(cx);
-            let target_scroll_top = editor.row_for_block(decorations.prompt_block_id, cx)?.0 as f32
+            let target_scroll_top = editor
+                .row_for_block(decorations.prompt_block_id, cx)?
+                .as_f64()
                 - scroll_lock.distance_from_top;
             if target_scroll_top != scroll_position.y {
                 editor.set_scroll_position(point(scroll_position.x, target_scroll_top), window, cx);
@@ -959,8 +963,9 @@ impl InlineAssistant {
                     if let Some(decorations) = assist.decorations.as_ref() {
                         let distance_from_top = editor.update(cx, |editor, cx| {
                             let scroll_top = editor.scroll_position(cx).y;
-                            let prompt_row =
-                                editor.row_for_block(decorations.prompt_block_id, cx)?.0 as f32;
+                            let prompt_row = editor
+                                .row_for_block(decorations.prompt_block_id, cx)?
+                                .0 as ScrollOffset;
                             Some(prompt_row - scroll_top)
                         });
 
@@ -1192,8 +1197,8 @@ impl InlineAssistant {
             let mut scroll_target_range = None;
             if let Some(decorations) = assist.decorations.as_ref() {
                 scroll_target_range = maybe!({
-                    let top = editor.row_for_block(decorations.prompt_block_id, cx)?.0 as f32;
-                    let bottom = editor.row_for_block(decorations.end_block_id, cx)?.0 as f32;
+                    let top = editor.row_for_block(decorations.prompt_block_id, cx)?.0 as f64;
+                    let bottom = editor.row_for_block(decorations.end_block_id, cx)?.0 as f64;
                     Some((top, bottom))
                 });
                 if scroll_target_range.is_none() {
@@ -1207,15 +1212,15 @@ impl InlineAssistant {
                     .start
                     .to_display_point(&snapshot.display_snapshot)
                     .row();
-                let top = start_row.0 as f32;
+                let top = start_row.0 as ScrollOffset;
                 let bottom = top + 1.0;
                 (top, bottom)
             });
             let mut scroll_target_top = scroll_target_range.0;
             let mut scroll_target_bottom = scroll_target_range.1;
 
-            scroll_target_top -= editor.vertical_scroll_margin() as f32;
-            scroll_target_bottom += editor.vertical_scroll_margin() as f32;
+            scroll_target_top -= editor.vertical_scroll_margin() as ScrollOffset;
+            scroll_target_bottom += editor.vertical_scroll_margin() as ScrollOffset;
 
             let height_in_lines = editor.visible_line_count().unwrap_or(0.);
             let scroll_top = editor.scroll_position(cx).y;
@@ -1543,7 +1548,7 @@ struct EditorInlineAssists {
 
 struct InlineAssistScrollLock {
     assist_id: InlineAssistId,
-    distance_from_top: f32,
+    distance_from_top: ScrollOffset,
 }
 
 impl EditorInlineAssists {

crates/agent_ui/src/text_thread_editor.rs 🔗

@@ -17,6 +17,7 @@ use editor::{
         BlockPlacement, BlockProperties, BlockStyle, Crease, CreaseMetadata, CustomBlockId, FoldId,
         RenderBlock, ToDisplayPoint,
     },
+    scroll::ScrollOffset,
 };
 use editor::{FoldPlaceholder, display_map::CreaseId};
 use fs::Fs;
@@ -108,7 +109,7 @@ pub enum InsertDraggedFiles {
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 struct ScrollPosition {
-    offset_before_cursor: gpui::Point<f32>,
+    offset_before_cursor: gpui::Point<ScrollOffset>,
     cursor: Anchor,
 }
 
@@ -631,7 +632,7 @@ impl TextThreadEditor {
                         let snapshot = editor.snapshot(window, cx);
                         let cursor_point = scroll_position.cursor.to_display_point(&snapshot);
                         let scroll_top =
-                            cursor_point.row().as_f32() - scroll_position.offset_before_cursor.y;
+                            cursor_point.row().as_f64() - scroll_position.offset_before_cursor.y;
                         editor.set_scroll_position(
                             point(scroll_position.offset_before_cursor.x, scroll_top),
                             window,
@@ -979,7 +980,7 @@ impl TextThreadEditor {
             let cursor_row = cursor
                 .to_display_point(&snapshot.display_snapshot)
                 .row()
-                .as_f32();
+                .as_f64();
             let scroll_position = editor
                 .scroll_manager
                 .anchor()

crates/assistant_tools/src/edit_file_tool.rs 🔗

@@ -17,7 +17,7 @@ use editor::{
 use futures::StreamExt;
 use gpui::{
     Animation, AnimationExt, AnyWindowHandle, App, AppContext, AsyncApp, Entity, Task,
-    TextStyleRefinement, WeakEntity, pulsating_between, px,
+    TextStyleRefinement, WeakEntity, pulsating_between,
 };
 use indoc::formatdoc;
 use language::{
@@ -1102,7 +1102,7 @@ impl ToolCard for EditFileToolCard {
                     .relative()
                     .h_full()
                     .when(!self.full_height_expanded, |editor_container| {
-                        editor_container.max_h(px(COLLAPSED_LINES as f32 * editor_line_height.0))
+                        editor_container.max_h(COLLAPSED_LINES as f32 * editor_line_height)
                     })
                     .overflow_hidden()
                     .border_t_1()

crates/debugger_ui/src/session/running/variable_list.rs 🔗

@@ -1213,7 +1213,7 @@ impl VariableList {
 
         let weak = cx.weak_entity();
         let focus_handle = self.focus_handle.clone();
-        let watcher_len = (self.list_handle.content_size().width.0 / 12.0).floor() - 3.0;
+        let watcher_len = (f32::from(self.list_handle.content_size().width / 12.0).floor()) - 3.0;
         let watcher_len = watcher_len as usize;
 
         div()

crates/editor/src/display_map.rs 🔗

@@ -1176,7 +1176,7 @@ impl DisplaySnapshot {
             .map(|(row, block)| (DisplayRow(row), block))
     }
 
-    pub fn sticky_header_excerpt(&self, row: f32) -> Option<StickyHeaderExcerpt<'_>> {
+    pub fn sticky_header_excerpt(&self, row: f64) -> Option<StickyHeaderExcerpt<'_>> {
         self.block_snapshot.sticky_header_excerpt(row)
     }
 
@@ -1877,33 +1877,33 @@ pub mod tests {
                 ),
                 (
                     DisplayPoint::new(DisplayRow(0), 7),
-                    language::SelectionGoal::HorizontalPosition(x.0)
+                    language::SelectionGoal::HorizontalPosition(f64::from(x))
                 )
             );
             assert_eq!(
                 movement::down(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(0), 7),
-                    language::SelectionGoal::HorizontalPosition(x.0),
+                    language::SelectionGoal::HorizontalPosition(f64::from(x)),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(1), 10),
-                    language::SelectionGoal::HorizontalPosition(x.0)
+                    language::SelectionGoal::HorizontalPosition(f64::from(x))
                 )
             );
             assert_eq!(
                 movement::down(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(1), 10),
-                    language::SelectionGoal::HorizontalPosition(x.0),
+                    language::SelectionGoal::HorizontalPosition(f64::from(x)),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(2), 4),
-                    language::SelectionGoal::HorizontalPosition(x.0)
+                    language::SelectionGoal::HorizontalPosition(f64::from(x))
                 )
             );
 
@@ -1920,7 +1920,7 @@ pub mod tests {
 
             // Re-wrap on font size changes
             map.update(cx, |map, cx| {
-                map.set_font(font("Helvetica"), px(font_size.0 + 3.), cx)
+                map.set_font(font("Helvetica"), font_size + Pixels::from(3.), cx)
             });
 
             let snapshot = map.update(cx, |map, cx| map.snapshot(cx));

crates/editor/src/display_map/block_map.rs 🔗

@@ -1395,7 +1395,7 @@ impl BlockSnapshot {
         })
     }
 
-    pub fn sticky_header_excerpt(&self, position: f32) -> Option<StickyHeaderExcerpt<'_>> {
+    pub(crate) fn sticky_header_excerpt(&self, position: f64) -> Option<StickyHeaderExcerpt<'_>> {
         let top_row = position as u32;
         let mut cursor = self.transforms.cursor::<BlockRow>(());
         cursor.seek(&BlockRow(top_row), Bias::Right);

crates/editor/src/editor.rs 🔗

@@ -210,6 +210,7 @@ use crate::{
     code_context_menus::CompletionsMenuSource,
     editor_settings::MultiCursorModifier,
     hover_links::{find_url, find_url_from_range},
+    scroll::{ScrollOffset, ScrollPixelOffset},
     signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
 };
 
@@ -8621,8 +8622,8 @@ impl Editor {
         self.context_menu_options = Some(options);
     }
 
-    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = Pixels(24.);
-    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = Pixels(2.);
+    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
+    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 
     fn render_edit_prediction_popover(
         &mut self,
@@ -8631,11 +8632,12 @@ impl Editor {
         right_margin: Pixels,
         editor_snapshot: &EditorSnapshot,
         visible_row_range: Range<DisplayRow>,
-        scroll_top: f32,
-        scroll_bottom: f32,
+        scroll_top: ScrollOffset,
+        scroll_bottom: ScrollOffset,
         line_layouts: &[LineWithInvisibles],
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         newest_selection_head: Option<DisplayPoint>,
         editor_width: Pixels,
         style: &EditorStyle,
@@ -8727,6 +8729,7 @@ impl Editor {
                 visible_row_range,
                 line_layouts,
                 line_height,
+                scroll_position,
                 scroll_pixel_position,
                 newest_selection_head,
                 editor_width,
@@ -8769,14 +8772,14 @@ impl Editor {
         visible_row_range: Range<DisplayRow>,
         line_layouts: &[LineWithInvisibles],
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         newest_selection_head: Option<DisplayPoint>,
         target_display_point: DisplayPoint,
         window: &mut Window,
         cx: &mut App,
     ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
         let scrolled_content_origin =
-            content_origin - gpui::Point::new(scroll_pixel_position.x, Pixels(0.0));
+            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 
         const SCROLL_PADDING_Y: Pixels = px(12.);
 
@@ -8811,8 +8814,8 @@ impl Editor {
         let target_column = target_display_point.column() as usize;
 
         let target_x = line_layout.x_for_index(target_column);
-        let target_y =
-            (target_display_point.row().as_f32() * line_height) - scroll_pixel_position.y;
+        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
+            - scroll_pixel_position.y;
 
         let flag_on_right = target_x < text_bounds.size.width / 2.;
 
@@ -8840,7 +8843,7 @@ impl Editor {
 
         let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 
-        let mut origin = scrolled_content_origin + point(target_x, target_y)
+        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
             - point(
                 if flag_on_right {
                     POLE_WIDTH
@@ -8893,16 +8896,16 @@ impl Editor {
         content_origin: gpui::Point<Pixels>,
         editor_snapshot: &EditorSnapshot,
         visible_row_range: Range<DisplayRow>,
-        scroll_top: f32,
-        scroll_bottom: f32,
+        scroll_top: ScrollOffset,
+        scroll_bottom: ScrollOffset,
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         target_display_point: DisplayPoint,
         editor_width: Pixels,
         window: &mut Window,
         cx: &mut App,
     ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
-        if target_display_point.row().as_f32() < scroll_top {
+        if target_display_point.row().as_f64() < scroll_top {
             let mut element = self
                 .render_edit_prediction_line_popover(
                     "Jump to Edit",
@@ -8921,7 +8924,7 @@ impl Editor {
             let origin = text_bounds.origin + offset;
             element.prepaint_at(origin, window, cx);
             Some((element, origin))
-        } else if (target_display_point.row().as_f32() + 1.) > scroll_bottom {
+        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
             let mut element = self
                 .render_edit_prediction_line_popover(
                     "Jump to Edit",
@@ -8963,7 +8966,7 @@ impl Editor {
         visible_row_range: Range<DisplayRow>,
         target_display_point: DisplayPoint,
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         content_origin: gpui::Point<Pixels>,
         editor_width: Pixels,
         window: &mut Window,
@@ -8982,7 +8985,7 @@ impl Editor {
 
         let line_origin = self.display_to_pixel_point(target_line_end, editor_snapshot, window)?;
 
-        let start_point = content_origin - point(scroll_pixel_position.x, Pixels::ZERO);
+        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
         let mut origin = start_point
             + line_origin
             + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
@@ -9023,7 +9026,8 @@ impl Editor {
         visible_row_range: Range<DisplayRow>,
         line_layouts: &[LineWithInvisibles],
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         newest_selection_head: Option<DisplayPoint>,
         editor_width: Pixels,
         style: &EditorStyle,
@@ -9136,9 +9140,11 @@ impl Editor {
                 ..Default::default()
             });
 
-        let x_after_longest =
-            text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X
-                - scroll_pixel_position.x;
+        let x_after_longest = Pixels::from(
+            ScrollPixelOffset::from(
+                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
+            ) - scroll_pixel_position.x,
+        );
 
         let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 
@@ -9150,8 +9156,11 @@ impl Editor {
         let mut origin = if can_position_to_the_right {
             point(
                 x_after_longest,
-                text_bounds.origin.y + edit_start.row().as_f32() * line_height
-                    - scroll_pixel_position.y,
+                text_bounds.origin.y
+                    + Pixels::from(
+                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
+                            - scroll_pixel_position.y,
+                    ),
             )
         } else {
             let cursor_row = newest_selection_head.map(|head| head.row());
@@ -9181,8 +9190,10 @@ impl Editor {
 
             content_origin
                 + point(
-                    -scroll_pixel_position.x,
-                    row_target.as_f32() * line_height - scroll_pixel_position.y,
+                    Pixels::from(-scroll_pixel_position.x),
+                    Pixels::from(
+                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
+                    ),
                 )
         };
 
@@ -14250,7 +14261,7 @@ impl Editor {
                     let mut row = range.start.row();
                     let positions =
                         if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
-                            px(start)..px(end)
+                            Pixels::from(start)..Pixels::from(end)
                         } else {
                             let start_x =
                                 display_map.x_for_display_point(range.start, &text_layout_details);
@@ -15884,7 +15895,7 @@ impl Editor {
 
         if should_scroll_up {
             let new_scroll_position =
-                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as f32);
+                current_scroll_position + gpui::Point::new(0.0, lines_to_expand as ScrollOffset);
             self.set_scroll_position(new_scroll_position, window, cx);
         }
     }
@@ -21737,11 +21748,11 @@ impl Editor {
             .scroll_position(editor_snapshot)
             .y;
 
-        if source.row().as_f32() < scroll_top.floor() {
+        if source.row().as_f64() < scroll_top.floor() {
             return None;
         }
         let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
-        let source_y = line_height * (source.row().as_f32() - scroll_top);
+        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
         Some(gpui::Point::new(source_x, source_y))
     }
 
@@ -23323,7 +23334,7 @@ impl EditorSnapshot {
             .map(|display_map| display_map.text())
     }
 
-    pub fn scroll_position(&self) -> gpui::Point<f32> {
+    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
         self.scroll_anchor.scroll_position(&self.display_snapshot)
     }
 
@@ -23889,12 +23900,16 @@ impl EntityInputHandler for Editor {
 
         let snapshot = self.snapshot(window, cx);
         let scroll_position = snapshot.scroll_position();
-        let scroll_left = scroll_position.x * em_advance;
+        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
 
         let start = OffsetUtf16(range_utf16.start).to_display_point(&snapshot);
-        let x = snapshot.x_for_display_point(start, &text_layout_details) - scroll_left
-            + self.gutter_dimensions.full_width();
-        let y = line_height * (start.row().as_f32() - scroll_position.y);
+        let x = Pixels::from(
+            ScrollOffset::from(
+                snapshot.x_for_display_point(start, &text_layout_details)
+                    + self.gutter_dimensions.full_width(),
+            ) - scroll_left,
+        );
+        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
 
         Some(Bounds {
             origin: element_bounds.origin + point(x, y),
@@ -24161,7 +24176,7 @@ impl<T: ToOffset> RangeToAnchorExt for Range<T> {
 }
 
 pub trait RowExt {
-    fn as_f32(&self) -> f32;
+    fn as_f64(&self) -> f64;
 
     fn next_row(&self) -> Self;
 
@@ -24171,8 +24186,8 @@ pub trait RowExt {
 }
 
 impl RowExt for DisplayRow {
-    fn as_f32(&self) -> f32 {
-        self.0 as f32
+    fn as_f64(&self) -> f64 {
+        self.0 as _
     }
 
     fn next_row(&self) -> Self {
@@ -24189,8 +24204,8 @@ impl RowExt for DisplayRow {
 }
 
 impl RowExt for MultiBufferRow {
-    fn as_f32(&self) -> f32 {
-        self.0 as f32
+    fn as_f64(&self) -> f64 {
+        self.0 as _
     }
 
     fn next_row(&self) -> Self {

crates/editor/src/editor_settings.rs 🔗

@@ -31,7 +31,7 @@ pub struct EditorSettings {
     pub minimap: Minimap,
     pub gutter: Gutter,
     pub scroll_beyond_last_line: ScrollBeyondLastLine,
-    pub vertical_scroll_margin: f32,
+    pub vertical_scroll_margin: f64,
     pub autoscroll_on_clicks: bool,
     pub horizontal_scroll_margin: f32,
     pub scroll_sensitivity: f32,
@@ -248,7 +248,7 @@ impl Settings for EditorSettings {
                 folds: gutter.folds.unwrap(),
             },
             scroll_beyond_last_line: editor.scroll_beyond_last_line.unwrap(),
-            vertical_scroll_margin: editor.vertical_scroll_margin.unwrap(),
+            vertical_scroll_margin: editor.vertical_scroll_margin.unwrap() as f64,
             autoscroll_on_clicks: editor.autoscroll_on_clicks.unwrap(),
             horizontal_scroll_margin: editor.horizontal_scroll_margin.unwrap(),
             scroll_sensitivity: editor.scroll_sensitivity.unwrap(),

crates/editor/src/editor_tests.rs 🔗

@@ -782,12 +782,12 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
             assert!(pop_history(&mut editor, cx).is_none());
 
             // Set scroll position to check later
-            editor.set_scroll_position(gpui::Point::<f32>::new(5.5, 5.5), window, cx);
+            editor.set_scroll_position(gpui::Point::<f64>::new(5.5, 5.5), window, cx);
             let original_scroll_position = editor.scroll_manager.anchor();
 
             // Jump to the end of the document and adjust scroll
             editor.move_to_end(&MoveToEnd, window, cx);
-            editor.set_scroll_position(gpui::Point::<f32>::new(-2.5, -0.5), window, cx);
+            editor.set_scroll_position(gpui::Point::<f64>::new(-2.5, -0.5), window, cx);
             assert_ne!(editor.scroll_manager.anchor(), original_scroll_position);
 
             let nav_entry = pop_history(&mut editor, cx).unwrap();
@@ -817,7 +817,7 @@ async fn test_navigation_history(cx: &mut TestAppContext) {
             );
             assert_eq!(
                 editor.scroll_position(cx),
-                gpui::Point::new(0., editor.max_point(cx).row().as_f32())
+                gpui::Point::new(0., editor.max_point(cx).row().as_f64())
             );
 
             editor

crates/editor/src/element.rs 🔗

@@ -28,7 +28,10 @@ use crate::{
     inlay_hint_settings,
     items::BufferSearchHighlights,
     mouse_context_menu::{self, MenuPosition},
-    scroll::{ActiveScrollbarState, ScrollbarThumbState, scroll_amount::ScrollAmount},
+    scroll::{
+        ActiveScrollbarState, ScrollOffset, ScrollPixelOffset, ScrollbarThumbState,
+        scroll_amount::ScrollAmount,
+    },
 };
 use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
 use collections::{BTreeMap, HashMap};
@@ -696,11 +699,11 @@ impl EditorElement {
                         // and run the selection logic.
                         modifiers.alt = false;
                     } else {
-                        let scroll_position_row =
-                            position_map.scroll_pixel_position.y / position_map.line_height;
+                        let scroll_position_row = position_map.scroll_position.y;
                         let display_row = (((event.position - gutter_hitbox.bounds.origin).y
-                            + position_map.scroll_pixel_position.y)
                             / position_map.line_height)
+                            as f64
+                            + position_map.scroll_position.y)
                             as u32;
                         let multi_buffer_row = position_map
                             .snapshot
@@ -765,9 +768,9 @@ impl EditorElement {
         cx.stop_propagation();
 
         if !is_singleton {
-            let display_row = (((event.position - gutter_hitbox.bounds.origin).y
-                + position_map.scroll_pixel_position.y)
-                / position_map.line_height) as u32;
+            let display_row = (ScrollPixelOffset::from(
+                (event.position - gutter_hitbox.bounds.origin).y / position_map.line_height,
+            ) + position_map.scroll_position.y) as u32;
             let multi_buffer_row = position_map
                 .snapshot
                 .display_point_to_point(DisplayPoint::new(DisplayRow(display_row), 0), Bias::Right)
@@ -777,9 +780,7 @@ impl EditorElement {
                 .and_then(|line_number| line_number.hitbox.as_ref())
                 .is_some_and(|hitbox| hitbox.contains(&event.position))
             {
-                let scroll_position_row =
-                    position_map.scroll_pixel_position.y / position_map.line_height;
-                let line_offset_from_top = display_row - scroll_position_row as u32;
+                let line_offset_from_top = display_row - position_map.scroll_position.y as u32;
 
                 editor.open_excerpts_common(
                     Some(JumpData::MultiBufferRow {
@@ -1571,8 +1572,8 @@ impl EditorElement {
         line_layouts: &[LineWithInvisibles],
         text_hitbox: &Hitbox,
         content_origin: gpui::Point<Pixels>,
-        scroll_position: gpui::Point<f32>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_height: Pixels,
         em_width: Pixels,
         em_advance: Pixels,
@@ -1664,10 +1665,10 @@ impl EditorElement {
                         None
                     };
 
-                    let x = cursor_character_x - scroll_pixel_position.x;
-                    let y = (cursor_position.row().as_f32()
-                        - scroll_pixel_position.y / line_height)
-                        * line_height;
+                    let x = cursor_character_x - scroll_pixel_position.x.into();
+                    let y = ((cursor_position.row().as_f64() - scroll_position.y)
+                        * ScrollPixelOffset::from(line_height))
+                    .into();
                     if selection.is_newest {
                         editor.pixel_position_of_newest_cursor = Some(point(
                             text_hitbox.origin.x + x + block_width / 2.,
@@ -1676,19 +1677,27 @@ impl EditorElement {
 
                         if autoscroll_containing_element {
                             let top = text_hitbox.origin.y
-                                + (cursor_position.row().as_f32() - scroll_position.y - 3.).max(0.)
-                                    * line_height;
+                                + ((cursor_position.row().as_f64() - scroll_position.y - 3.)
+                                    .max(0.)
+                                    * ScrollPixelOffset::from(line_height))
+                                .into();
                             let left = text_hitbox.origin.x
-                                + (cursor_position.column() as f32 - scroll_position.x - 3.)
+                                + ((cursor_position.column() as ScrollOffset
+                                    - scroll_position.x
+                                    - 3.)
                                     .max(0.)
-                                    * em_width;
+                                    * ScrollPixelOffset::from(em_width))
+                                .into();
 
                             let bottom = text_hitbox.origin.y
-                                + (cursor_position.row().as_f32() - scroll_position.y + 4.)
-                                    * line_height;
+                                + ((cursor_position.row().as_f64() - scroll_position.y + 4.)
+                                    * ScrollPixelOffset::from(line_height))
+                                .into();
                             let right = text_hitbox.origin.x
-                                + (cursor_position.column() as f32 - scroll_position.x + 4.)
-                                    * em_width;
+                                + ((cursor_position.column() as ScrollOffset - scroll_position.x
+                                    + 4.)
+                                    * ScrollPixelOffset::from(em_width))
+                                .into();
 
                             autoscroll_bounds =
                                 Some(Bounds::from_corners(point(left, top), point(right, bottom)))
@@ -1729,7 +1738,7 @@ impl EditorElement {
         snapshot: &EditorSnapshot,
         scrollbar_layout_information: &ScrollbarLayoutInformation,
         content_offset: gpui::Point<Pixels>,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         non_visible_cursors: bool,
         right_margin: Pixels,
         editor_width: Pixels,
@@ -1817,7 +1826,7 @@ impl EditorElement {
         &self,
         snapshot: &EditorSnapshot,
         minimap_width: Pixels,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<f64>,
         scrollbar_layout_information: &ScrollbarLayoutInformation,
         scrollbar_layout: Option<&EditorScrollbars>,
         window: &mut Window,
@@ -1892,9 +1901,9 @@ impl EditorElement {
         );
         let minimap_height = minimap_bounds.size.height;
 
-        let visible_editor_lines = editor_bounds.size.height / line_height;
-        let total_editor_lines = scroll_range.height / line_height;
-        let minimap_lines = minimap_height / minimap_line_height;
+        let visible_editor_lines = (editor_bounds.size.height / line_height) as f64;
+        let total_editor_lines = (scroll_range.height / line_height) as f64;
+        let minimap_lines = (minimap_height / minimap_line_height) as f64;
 
         let minimap_scroll_top = MinimapLayout::calculate_minimap_top_offset(
             total_editor_lines,
@@ -2000,7 +2009,7 @@ impl EditorElement {
         line_height: Pixels,
         gutter_dimensions: &GutterDimensions,
         gutter_settings: crate::editor_settings::Gutter,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         gutter_hitbox: &Hitbox,
         window: &mut Window,
         cx: &mut App,
@@ -2016,7 +2025,8 @@ impl EditorElement {
 
                 let position = point(
                     gutter_dimensions.width - gutter_dimensions.right_padding,
-                    ix as f32 * line_height - (scroll_pixel_position.y % line_height),
+                    ix as f32 * line_height
+                        - (scroll_pixel_position.y % ScrollPixelOffset::from(line_height)).into(),
                 );
                 let centering_offset = point(
                     (gutter_dimensions.fold_area_width() - crease_toggle_size.width) / 2.,
@@ -2047,7 +2057,7 @@ impl EditorElement {
         lines: &[LineWithInvisibles],
         line_height: Pixels,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         em_width: Pixels,
         window: &mut Window,
         cx: &mut App,
@@ -2070,8 +2080,9 @@ impl EditorElement {
                     4. * em_width
                 };
                 let position = point(
-                    scroll_pixel_position.x + line.width + padding,
-                    ix as f32 * line_height - (scroll_pixel_position.y % line_height),
+                    Pixels::from(scroll_pixel_position.x) + line.width + padding,
+                    ix as f32 * line_height
+                        - (scroll_pixel_position.y % ScrollPixelOffset::from(line_height)).into(),
                 );
                 let centering_offset = point(px(0.), (line_height - size.height) / 2.);
                 let origin = content_origin + position + centering_offset;
@@ -2120,7 +2131,8 @@ impl EditorElement {
         crease_trailers: &[Option<CreaseTrailerLayout>],
         row_block_types: &HashMap<DisplayRow, bool>,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         edit_prediction_popover_origin: Option<gpui::Point<Pixels>>,
         start_row: DisplayRow,
         end_row: DisplayRow,
@@ -2220,8 +2232,7 @@ impl EditorElement {
                 continue;
             };
 
-            let pos_y = content_origin.y
-                + line_height * (row.0 as f32 - scroll_pixel_position.y / line_height);
+            let pos_y = content_origin.y + line_height * (row.0 as f64 - scroll_position.y) as f32;
 
             let window_ix = row.0.saturating_sub(start_row.0) as usize;
             let pos_x = {
@@ -2231,11 +2242,16 @@ impl EditorElement {
                 let line_end = if let Some(crease_trailer) = crease_trailer_layout {
                     crease_trailer.bounds.right()
                 } else {
-                    content_origin.x - scroll_pixel_position.x + line_layout.width
+                    Pixels::from(
+                        ScrollPixelOffset::from(content_origin.x + line_layout.width)
+                            - scroll_pixel_position.x,
+                    )
                 };
 
                 let padded_line = line_end + padding;
-                let min_start = content_origin.x - scroll_pixel_position.x + min_x;
+                let min_start = Pixels::from(
+                    ScrollPixelOffset::from(content_origin.x + min_x) - scroll_pixel_position.x,
+                );
 
                 cmp::max(padded_line, min_start)
             };
@@ -2279,7 +2295,8 @@ impl EditorElement {
         &self,
         display_point: DisplayPoint,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_height: Pixels,
         snapshot: &EditorSnapshot,
         window: &mut Window,
@@ -2410,10 +2427,12 @@ impl EditorElement {
             .row();
 
         let start_y = content_origin.y
-            + ((new_display_row.as_f32() - (scroll_pixel_position.y / line_height)) * line_height)
+            + (((new_display_row.as_f64() - scroll_position.y) as f32) * line_height)
             + (line_height / 2.0)
             - (icon_size.square(window, cx) / 2.);
-        let start_x = content_origin.x - scroll_pixel_position.x + (window.rem_size() * 0.1);
+        let start_x = (ScrollPixelOffset::from(content_origin.x) - scroll_pixel_position.x
+            + ScrollPixelOffset::from(window.rem_size() * 0.1))
+        .into();
 
         let absolute_offset = gpui::point(start_x, start_y);
         button.layout_as_root(gpui::AvailableSpace::min_size(), window, cx);
@@ -2434,7 +2453,8 @@ impl EditorElement {
         crease_trailer: Option<&CreaseTrailerLayout>,
         em_width: Pixels,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_height: Pixels,
         text_hitbox: &Hitbox,
         window: &mut Window,
@@ -2474,14 +2494,17 @@ impl EditorElement {
 
         let mut element = render_inline_blame_entry(entry.clone(), &self.style, cx)?;
 
-        let start_y = content_origin.y
-            + line_height * (display_row.as_f32() - scroll_pixel_position.y / line_height);
+        let start_y =
+            content_origin.y + line_height * ((display_row.as_f64() - scroll_position.y) as f32);
 
         let start_x = {
             let line_end = if let Some(crease_trailer) = crease_trailer {
                 crease_trailer.bounds.right()
             } else {
-                content_origin.x - scroll_pixel_position.x + line_layout.width
+                Pixels::from(
+                    ScrollPixelOffset::from(content_origin.x + line_layout.width)
+                        - scroll_pixel_position.x,
+                )
             };
 
             let padded_line_end = line_end + padding;
@@ -2490,7 +2513,10 @@ impl EditorElement {
                 ProjectSettings::get_global(cx).git.inline_blame.min_column as usize,
                 window,
             );
-            let min_start = content_origin.x - scroll_pixel_position.x + min_column_in_pixels;
+            let min_start = Pixels::from(
+                ScrollPixelOffset::from(content_origin.x + min_column_in_pixels)
+                    - scroll_pixel_position.x,
+            );
 
             cmp::max(padded_line_end, min_start)
         };
@@ -2590,7 +2616,7 @@ impl EditorElement {
         &self,
         buffer_rows: &[RowInfo],
         em_width: Pixels,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         line_height: Pixels,
         gutter_hitbox: &Hitbox,
         max_width: Option<Pixels>,
@@ -2615,7 +2641,7 @@ impl EditorElement {
         } else {
             AvailableSpace::MaxContent
         };
-        let scroll_top = scroll_position.y * line_height;
+        let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
         let start_x = em_width;
 
         let mut last_used_color: Option<(Hsla, Oid)> = None;
@@ -2640,7 +2666,8 @@ impl EditorElement {
                     cx,
                 )?;
 
-                let start_y = ix as f32 * line_height - (scroll_top % line_height);
+                let start_y = ix as f32 * line_height
+                    - Pixels::from(scroll_top % ScrollPixelOffset::from(line_height));
                 let absolute_offset = gutter_hitbox.origin + point(start_x, start_y);
 
                 element.prepaint_as_root(
@@ -2662,7 +2689,7 @@ impl EditorElement {
         content_origin: gpui::Point<Pixels>,
         text_origin: gpui::Point<Pixels>,
         visible_buffer_range: Range<MultiBufferRow>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_height: Pixels,
         snapshot: &DisplaySnapshot,
         window: &mut Window,
@@ -2686,7 +2713,10 @@ impl EditorElement {
                     let single_indent_width =
                         self.column_pixels(indent_guide.tab_size as usize, window);
                     let total_width = single_indent_width * indent_guide.depth as f32;
-                    let start_x = content_origin.x + total_width - scroll_pixel_position.x;
+                    let start_x = Pixels::from(
+                        ScrollOffset::from(content_origin.x + total_width)
+                            - scroll_pixel_position.x,
+                    );
                     if start_x >= text_origin.x {
                         let (offset_y, length) = Self::calculate_indent_guide_bounds(
                             indent_guide.start_row..indent_guide.end_row,
@@ -2694,7 +2724,10 @@ impl EditorElement {
                             snapshot,
                         );
 
-                        let start_y = content_origin.y + offset_y - scroll_pixel_position.y;
+                        let start_y = Pixels::from(
+                            ScrollOffset::from(content_origin.y) + offset_y
+                                - scroll_pixel_position.y,
+                        );
 
                         Some(IndentGuideLayout {
                             origin: point(start_x, start_y),
@@ -2715,7 +2748,7 @@ impl EditorElement {
     fn layout_wrap_guides(
         &self,
         em_advance: Pixels,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<f64>,
         content_origin: gpui::Point<Pixels>,
         scrollbar_layout: Option<&EditorScrollbars>,
         vertical_scrollbar_width: Pixels,
@@ -2723,7 +2756,7 @@ impl EditorElement {
         window: &Window,
         cx: &App,
     ) -> SmallVec<[(Pixels, bool); 2]> {
-        let scroll_left = scroll_position.x * em_advance;
+        let scroll_left = scroll_position.x as f32 * em_advance;
         let content_origin = content_origin.x;
         let horizontal_offset = content_origin - scroll_left;
         let vertical_scrollbar_width = scrollbar_layout
@@ -2749,7 +2782,7 @@ impl EditorElement {
         row_range: Range<MultiBufferRow>,
         line_height: Pixels,
         snapshot: &DisplaySnapshot,
-    ) -> (gpui::Pixels, gpui::Pixels) {
+    ) -> (f64, gpui::Pixels) {
         let start_point = Point::new(row_range.start.0, 0);
         let end_point = Point::new(row_range.end.0, 0);
 
@@ -2764,7 +2797,7 @@ impl EditorElement {
         cons_line.row += 1;
         let cons_line = cons_line.to_display_point(snapshot).row();
 
-        let mut offset_y = row_range.start.0 as f32 * line_height;
+        let mut offset_y = row_range.start.as_f64() * f64::from(line_height);
         let mut length = (cons_line.0.saturating_sub(row_range.start.0)) as f32 * line_height;
 
         // If we are at the end of the buffer, ensure that the indent guide extends to the end of the line.
@@ -2789,7 +2822,7 @@ impl EditorElement {
             block_height += block.height();
         }
         if !found_excerpt_header {
-            offset_y -= block_offset as f32 * line_height;
+            offset_y -= block_offset as f64 * f64::from(line_height);
             length += block_height as f32 * line_height;
         }
 
@@ -2817,7 +2850,7 @@ impl EditorElement {
         &self,
         line_height: Pixels,
         range: Range<DisplayRow>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
         gutter_dimensions: &GutterDimensions,
         gutter_hitbox: &Hitbox,
         display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
@@ -2860,7 +2893,7 @@ impl EditorElement {
                         display_row,
                         line_height,
                         gutter_dimensions,
-                        scroll_pixel_position,
+                        scroll_position,
                         gutter_hitbox,
                         display_hunks,
                         window,
@@ -2878,7 +2911,7 @@ impl EditorElement {
         line_height: Pixels,
         range: Range<DisplayRow>,
         row_infos: &[RowInfo],
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
         gutter_dimensions: &GutterDimensions,
         gutter_hitbox: &Hitbox,
         display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
@@ -2971,7 +3004,7 @@ impl EditorElement {
                         display_row,
                         line_height,
                         gutter_dimensions,
-                        scroll_pixel_position,
+                        scroll_position,
                         gutter_hitbox,
                         display_hunks,
                         window,
@@ -2989,7 +3022,7 @@ impl EditorElement {
         gutter_dimensions: GutterDimensions,
         em_width: Pixels,
         line_height: Pixels,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         buffer_rows: &[RowInfo],
         window: &mut Window,
         cx: &mut App,
@@ -3000,7 +3033,7 @@ impl EditorElement {
 
         let editor_font_size = self.style.text.font_size.to_pixels(window.rem_size()) * 1.2;
 
-        let scroll_top = scroll_position.y * line_height;
+        let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
 
         let max_line_number_length = self
             .editor
@@ -3065,7 +3098,9 @@ impl EditorElement {
 
                 let position = point(
                     git_gutter_width + px(1.),
-                    ix as f32 * line_height - (scroll_top % line_height) + px(1.),
+                    ix as f32 * line_height
+                        - Pixels::from(scroll_top % ScrollPixelOffset::from(line_height))
+                        + px(1.),
                 );
                 let origin = gutter_hitbox.origin + position;
 
@@ -3129,7 +3164,7 @@ impl EditorElement {
         gutter_hitbox: Option<&Hitbox>,
         gutter_dimensions: GutterDimensions,
         line_height: Pixels,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         rows: Range<DisplayRow>,
         buffer_rows: &[RowInfo],
         active_rows: &BTreeMap<DisplayRow, LineHighlightSpec>,
@@ -3200,12 +3235,13 @@ impl EditorElement {
                     .unwrap_or_else(|| cx.theme().colors().editor_line_number);
                 let shaped_line =
                     self.shape_line_number(SharedString::from(&line_number), color, window);
-                let scroll_top = scroll_position.y * line_height;
+                let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
                 let line_origin = gutter_hitbox.map(|hitbox| {
                     hitbox.origin
                         + point(
                             hitbox.size.width - shaped_line.width - gutter_dimensions.right_padding,
-                            ix as f32 * line_height - (scroll_top % line_height),
+                            ix as f32 * line_height
+                                - Pixels::from(scroll_top % ScrollPixelOffset::from(line_height)),
                         )
                 });
 
@@ -3517,7 +3553,8 @@ impl EditorElement {
         start_row: DisplayRow,
         line_layouts: &mut [LineWithInvisibles],
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         content_origin: gpui::Point<Pixels>,
         window: &mut Window,
         cx: &mut App,
@@ -3527,6 +3564,7 @@ impl EditorElement {
             let row = start_row + DisplayRow(ix as u32);
             line.prepaint(
                 line_height,
+                scroll_position,
                 scroll_pixel_position,
                 row,
                 content_origin,
@@ -3894,12 +3932,7 @@ impl EditorElement {
                             })
                             .take(1),
                     )
-                    .child(
-                        h_flex()
-                            .size(Pixels(12.0))
-                            .justify_center()
-                            .children(indicator),
-                    )
+                    .child(h_flex().size(px(12.0)).justify_center().children(indicator))
                     .child(
                         h_flex()
                             .cursor_pointer()
@@ -4290,7 +4323,8 @@ impl EditorElement {
         blocks: &mut Vec<BlockLayout>,
         hitbox: &Hitbox,
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         window: &mut Window,
         cx: &mut App,
     ) {
@@ -4299,7 +4333,10 @@ impl EditorElement {
                 hitbox.origin
                     + point(
                         block.x_offset,
-                        row.as_f32() * line_height - scroll_pixel_position.y,
+                        Pixels::from(
+                            (row.as_f64() - scroll_position.y)
+                                * ScrollPixelOffset::from(line_height),
+                        ),
                     )
             } else {
                 // Position the block outside the visible area
@@ -4307,7 +4344,7 @@ impl EditorElement {
             };
 
             if !matches!(block.style, BlockStyle::Sticky) {
-                origin += point(-scroll_pixel_position.x, Pixels::ZERO);
+                origin += point(Pixels::from(-scroll_pixel_position.x), Pixels::ZERO);
             }
 
             let focus_handle =
@@ -4329,7 +4366,7 @@ impl EditorElement {
     fn layout_sticky_buffer_header(
         &self,
         StickyHeaderExcerpt { excerpt }: StickyHeaderExcerpt<'_>,
-        scroll_position: f32,
+        scroll_position: gpui::Point<ScrollOffset>,
         line_height: Pixels,
         right_margin: Pixels,
         snapshot: &EditorSnapshot,
@@ -4341,7 +4378,7 @@ impl EditorElement {
     ) -> AnyElement {
         let jump_data = header_jump_data(
             snapshot,
-            DisplayRow(scroll_position as u32),
+            DisplayRow(scroll_position.y as u32),
             FILE_HEADER_HEIGHT + MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
             excerpt,
         );
@@ -4380,15 +4417,15 @@ impl EditorElement {
                 continue;
             }
 
-            let Some(display_row) = block.row.filter(|row| row.0 > scroll_position as u32) else {
+            let Some(display_row) = block.row.filter(|row| row.0 > scroll_position.y as u32) else {
                 continue;
             };
 
             let max_row = display_row.0.saturating_sub(FILE_HEADER_HEIGHT);
-            let offset = scroll_position - max_row as f32;
+            let offset = scroll_position.y - max_row as f64;
 
             if offset > 0.0 {
-                origin.y -= offset * line_height;
+                origin.y -= Pixels::from(offset * ScrollPixelOffset::from(line_height));
             }
             break;
         }
@@ -4410,7 +4447,7 @@ impl EditorElement {
         content_origin: gpui::Point<Pixels>,
         right_margin: Pixels,
         start_row: DisplayRow,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_layouts: &[LineWithInvisibles],
         cursor: DisplayPoint,
         cursor_point: Point,
@@ -4465,12 +4502,18 @@ impl EditorElement {
             + gpui::Point {
                 x: cmp::max(
                     px(0.),
-                    cursor_row_layout.x_for_index(cursor.column() as usize)
-                        - scroll_pixel_position.x,
+                    Pixels::from(
+                        ScrollPixelOffset::from(
+                            cursor_row_layout.x_for_index(cursor.column() as usize),
+                        ) - scroll_pixel_position.x,
+                    ),
                 ),
                 y: cmp::max(
                     px(0.),
-                    cursor.row().next_row().as_f32() * line_height - scroll_pixel_position.y,
+                    Pixels::from(
+                        cursor.row().next_row().as_f64() * ScrollPixelOffset::from(line_height)
+                            - scroll_pixel_position.y,
+                    ),
                 ),
             };
 
@@ -4623,7 +4666,7 @@ impl EditorElement {
         text_hitbox: &Hitbox,
         content_origin: gpui::Point<Pixels>,
         right_margin: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         gutter_overshoot: Pixels,
         window: &mut Window,
         cx: &mut App,
@@ -4642,7 +4685,10 @@ impl EditorElement {
         let target_position = content_origin
             + gpui::Point {
                 x: -gutter_overshoot,
-                y: gutter_row.next_row().as_f32() * line_height - scroll_pixel_position.y,
+                y: Pixels::from(
+                    gutter_row.next_row().as_f64() * ScrollPixelOffset::from(line_height)
+                        - scroll_pixel_position.y,
+                ),
             };
 
         let (min_height_in_lines, max_height_in_lines) = editor
@@ -5008,7 +5054,7 @@ impl EditorElement {
         hitbox: &Hitbox,
         visible_display_row_range: Range<DisplayRow>,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         line_layouts: &[LineWithInvisibles],
         line_height: Pixels,
         em_width: Pixels,
@@ -5049,9 +5095,12 @@ impl EditorElement {
             &line_layouts[position.row().minus(visible_display_row_range.start) as usize];
 
         // Compute Hovered Point
-        let x =
-            hovered_row_layout.x_for_index(position.column() as usize) - scroll_pixel_position.x;
-        let y = position.row().as_f32() * line_height - scroll_pixel_position.y;
+        let x = hovered_row_layout.x_for_index(position.column() as usize)
+            - Pixels::from(scroll_pixel_position.x);
+        let y = Pixels::from(
+            position.row().as_f64() * ScrollPixelOffset::from(line_height)
+                - scroll_pixel_position.y,
+        );
         let hovered_point = content_origin + point(x, y);
 
         let mut overall_height = Pixels::ZERO;
@@ -5262,7 +5311,7 @@ impl EditorElement {
         newest_cursor_position: Option<DisplayPoint>,
         line_height: Pixels,
         right_margin: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
         highlighted_rows: &BTreeMap<DisplayRow, LineHighlight>,
         editor: Entity<Editor>,
@@ -5326,9 +5375,11 @@ impl EditorElement {
                     .iter()
                     .any(|p| p.is_some_and(|p| display_row_range.contains(&p.row())))
                 {
-                    let y = display_row_range.start.as_f32() * line_height
-                        + text_hitbox.bounds.top()
-                        - scroll_pixel_position.y;
+                    let y = (display_row_range.start.as_f64()
+                        * ScrollPixelOffset::from(line_height)
+                        + ScrollPixelOffset::from(text_hitbox.bounds.top())
+                        - scroll_pixel_position.y)
+                        .into();
 
                     let mut element = render_diff_hunk_controls(
                         display_row_range.start.0,
@@ -5363,7 +5414,7 @@ impl EditorElement {
         &self,
         hitbox: &Hitbox,
         content_origin: gpui::Point<Pixels>,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         newest_selection_head: Option<DisplayPoint>,
         start_row: DisplayRow,
         line_layouts: &[LineWithInvisibles],
@@ -5410,8 +5461,10 @@ impl EditorElement {
         };
 
         let target_x = cursor_row_layout.x_for_index(newest_selection_head.column() as usize)
-            - scroll_pixel_position.x;
-        let target_y = selection_row.as_f32() * line_height - scroll_pixel_position.y;
+            - Pixels::from(scroll_pixel_position.x);
+        let target_y = Pixels::from(
+            selection_row.as_f64() * ScrollPixelOffset::from(line_height) - scroll_pixel_position.y,
+        );
         let target_point = content_origin + point(target_x, target_y);
 
         let actual_size = element.layout_as_root(Size::<AvailableSpace>::default(), window, cx);
@@ -5554,8 +5607,12 @@ impl EditorElement {
                                 origin: point(
                                     range.start,
                                     layout.hitbox.origin.y
-                                        + (start_row.as_f32() - scroll_top)
-                                            * layout.position_map.line_height,
+                                        + Pixels::from(
+                                            (start_row.as_f64() - scroll_top)
+                                                * ScrollPixelOffset::from(
+                                                    layout.position_map.line_height,
+                                                ),
+                                        ),
                                 ),
                                 size: size(
                                     range.end - range.start,
@@ -5582,8 +5639,10 @@ impl EditorElement {
                     let origin = point(
                         origin_x,
                         layout.hitbox.origin.y
-                            + (highlight_row_start.as_f32() - scroll_top)
-                                * layout.position_map.line_height,
+                            + Pixels::from(
+                                (highlight_row_start.as_f64() - scroll_top)
+                                    * ScrollPixelOffset::from(layout.position_map.line_height),
+                            ),
                     );
                     let size = size(
                         width,
@@ -5878,7 +5937,7 @@ impl EditorElement {
                             hunk_bounds,
                             corner_radii,
                             flattened_unstaged_background_color,
-                            Edges::all(Pixels(1.0)),
+                            Edges::all(px(1.0)),
                             flattened_background_color,
                             BorderStyle::Solid,
                         ));
@@ -5899,12 +5958,14 @@ impl EditorElement {
         hunk: &DisplayDiffHunk,
     ) -> Bounds<Pixels> {
         let scroll_position = snapshot.scroll_position();
-        let scroll_top = scroll_position.y * line_height;
+        let scroll_top = scroll_position.y * ScrollPixelOffset::from(line_height);
         let gutter_strip_width = Self::gutter_strip_width(line_height);
 
         match hunk {
             DisplayDiffHunk::Folded { display_row, .. } => {
-                let start_y = display_row.as_f32() * line_height - scroll_top;
+                let start_y = (display_row.as_f64() * ScrollPixelOffset::from(line_height)
+                    - scroll_top)
+                    .into();
                 let end_y = start_y + line_height;
                 let highlight_origin = gutter_bounds.origin + point(px(0.), start_y);
                 let highlight_size = size(gutter_strip_width, end_y - start_y);
@@ -5918,8 +5979,10 @@ impl EditorElement {
                 if status.is_deleted() && display_row_range.is_empty() {
                     let row = display_row_range.start;
 
-                    let offset = line_height / 2.;
-                    let start_y = row.as_f32() * line_height - offset - scroll_top;
+                    let offset = ScrollPixelOffset::from(line_height / 2.);
+                    let start_y =
+                        (row.as_f64() * ScrollPixelOffset::from(line_height) - offset - scroll_top)
+                            .into();
                     let end_y = start_y + line_height;
 
                     let width = (0.35 * line_height).floor();
@@ -5949,8 +6012,13 @@ impl EditorElement {
                         })
                         .unwrap_or(end_row);
 
-                    let start_y = start_row.as_f32() * line_height - scroll_top;
-                    let end_y = end_row_in_current_excerpt.as_f32() * line_height - scroll_top;
+                    let start_y = (start_row.as_f64() * ScrollPixelOffset::from(line_height)
+                        - scroll_top)
+                        .into();
+                    let end_y = Pixels::from(
+                        end_row_in_current_excerpt.as_f64() * ScrollPixelOffset::from(line_height)
+                            - scroll_top,
+                    );
 
                     let highlight_origin = gutter_bounds.origin + point(px(0.), start_y);
                     let highlight_size = size(gutter_strip_width, end_y - start_y);
@@ -6038,11 +6106,17 @@ impl EditorElement {
                 };
 
                 let start_y = layout.gutter_hitbox.top()
-                    + start_row.0 as f32 * layout.position_map.line_height
-                    - layout.position_map.scroll_pixel_position.y;
+                    + Pixels::from(
+                        start_row.0 as f64
+                            * ScrollPixelOffset::from(layout.position_map.line_height)
+                            - layout.position_map.scroll_pixel_position.y,
+                    );
                 let end_y = layout.gutter_hitbox.top()
-                    + (end_row.0 + 1) as f32 * layout.position_map.line_height
-                    - layout.position_map.scroll_pixel_position.y;
+                    + Pixels::from(
+                        (end_row.0 + 1) as f64
+                            * ScrollPixelOffset::from(layout.position_map.line_height)
+                            - layout.position_map.scroll_pixel_position.y,
+                    );
                 let bounds = Bounds::from_corners(
                     point(layout.gutter_hitbox.left(), start_y),
                     point(layout.gutter_hitbox.left() + highlight_width, end_y),
@@ -6408,7 +6482,10 @@ impl EditorElement {
                             .contains(&old_position)
                         {
                             let position = editor.scroll_position(cx).apply_along(axis, |p| {
-                                (p + (new_position - old_position) / *text_unit_size).max(0.)
+                                (p + ScrollOffset::from(
+                                    (new_position - old_position) / *text_unit_size,
+                                ))
+                                .max(0.)
                             });
                             editor.set_scroll_position(position, window, cx);
                         }
@@ -6501,7 +6578,7 @@ impl EditorElement {
 
                             let position = editor
                                 .scroll_position(cx)
-                                .apply_along(axis, |_| start_position as f32);
+                                .apply_along(axis, |_| start_position as ScrollOffset);
 
                             editor.set_scroll_position(position, window, cx);
                         } else {
@@ -6747,8 +6824,10 @@ impl EditorElement {
                 line_height: layout.position_map.line_height,
                 corner_radius,
                 start_y: layout.content_origin.y
-                    + row_range.start.as_f32() * layout.position_map.line_height
-                    - layout.position_map.scroll_pixel_position.y,
+                    + Pixels::from(
+                        (row_range.start.as_f64() - layout.position_map.scroll_position.y)
+                            * ScrollOffset::from(layout.position_map.line_height),
+                    ),
                 lines: row_range
                     .iter_rows()
                     .map(|row| {
@@ -6757,19 +6836,30 @@ impl EditorElement {
                         HighlightedRangeLine {
                             start_x: if row == range.start.row() {
                                 layout.content_origin.x
-                                    + line_layout.x_for_index(range.start.column() as usize)
-                                    - layout.position_map.scroll_pixel_position.x
+                                    + Pixels::from(
+                                        ScrollPixelOffset::from(
+                                            line_layout.x_for_index(range.start.column() as usize),
+                                        ) - layout.position_map.scroll_pixel_position.x,
+                                    )
                             } else {
                                 layout.content_origin.x
-                                    - layout.position_map.scroll_pixel_position.x
+                                    - Pixels::from(layout.position_map.scroll_pixel_position.x)
                             },
                             end_x: if row == range.end.row() {
                                 layout.content_origin.x
-                                    + line_layout.x_for_index(range.end.column() as usize)
-                                    - layout.position_map.scroll_pixel_position.x
+                                    + Pixels::from(
+                                        ScrollPixelOffset::from(
+                                            line_layout.x_for_index(range.end.column() as usize),
+                                        ) - layout.position_map.scroll_pixel_position.x,
+                                    )
                             } else {
-                                layout.content_origin.x + line_layout.width + line_end_overshoot
-                                    - layout.position_map.scroll_pixel_position.x
+                                Pixels::from(
+                                    ScrollPixelOffset::from(
+                                        layout.content_origin.x
+                                            + line_layout.width
+                                            + line_end_overshoot,
+                                    ) - layout.position_map.scroll_pixel_position.x,
+                                )
                             },
                         }
                     })
@@ -6885,8 +6975,10 @@ impl EditorElement {
             }
 
             let minimap_axis = ScrollbarAxis::Vertical;
-            let pixels_per_line = (minimap_hitbox.size.height / layout.max_scroll_top)
-                .min(layout.minimap_line_height);
+            let pixels_per_line = Pixels::from(
+                ScrollPixelOffset::from(minimap_hitbox.size.height) / layout.max_scroll_top,
+            )
+            .min(layout.minimap_line_height);
 
             let mut mouse_position = window.mouse_position();
 
@@ -6912,9 +7004,12 @@ impl EditorElement {
                             {
                                 let position =
                                     editor.scroll_position(cx).apply_along(minimap_axis, |p| {
-                                        (p + (new_position - old_position) / pixels_per_line)
-                                            .max(0.)
+                                        (p + ScrollPixelOffset::from(
+                                            (new_position - old_position) / pixels_per_line,
+                                        ))
+                                        .max(0.)
                                     });
+
                                 editor.set_scroll_position(position, window, cx);
                             }
                             cx.stop_propagation();
@@ -6990,8 +7085,10 @@ impl EditorElement {
                                     .max(Pixels::ZERO);
 
                                 let scroll_offset = (layout.minimap_scroll_top
-                                    + top_position / layout.minimap_line_height)
-                                    .min(layout.max_scroll_top);
+                                    + ScrollPixelOffset::from(
+                                        top_position / layout.minimap_line_height,
+                                    ))
+                                .min(layout.max_scroll_top);
 
                                 let scroll_position = editor
                                     .scroll_position(cx)
@@ -7098,12 +7195,13 @@ impl EditorElement {
                         };
 
                         let current_scroll_position = position_map.snapshot.scroll_position();
-                        let x = (current_scroll_position.x * max_glyph_advance
-                            - (delta.x * scroll_sensitivity))
-                            / max_glyph_advance;
-                        let y = (current_scroll_position.y * line_height
-                            - (delta.y * scroll_sensitivity))
-                            / line_height;
+                        let x = (current_scroll_position.x
+                            * ScrollPixelOffset::from(max_glyph_advance)
+                            - ScrollPixelOffset::from(delta.x * scroll_sensitivity))
+                            / ScrollPixelOffset::from(max_glyph_advance);
+                        let y = (current_scroll_position.y * ScrollPixelOffset::from(line_height)
+                            - ScrollPixelOffset::from(delta.y * scroll_sensitivity))
+                            / ScrollPixelOffset::from(line_height);
                         let mut scroll_position =
                             point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
                         let forbid_vertical_scroll = editor.scroll_manager.forbid_vertical_scroll();
@@ -7422,7 +7520,7 @@ fn prepaint_gutter_button(
     row: DisplayRow,
     line_height: Pixels,
     gutter_dimensions: &GutterDimensions,
-    scroll_pixel_position: gpui::Point<Pixels>,
+    scroll_position: gpui::Point<ScrollOffset>,
     gutter_hitbox: &Hitbox,
     display_hunks: &[(DisplayDiffHunk, Option<Hitbox>)],
     window: &mut Window,
@@ -7462,7 +7560,8 @@ fn prepaint_gutter_button(
         - left_offset;
     x += available_width / 2.;
 
-    let mut y = row.as_f32() * line_height - scroll_pixel_position.y;
+    let mut y =
+        Pixels::from((row.as_f64() - scroll_position.y) * ScrollPixelOffset::from(line_height));
     y += (line_height - indicator_size.height) / 2.;
 
     button.prepaint_as_root(
@@ -7885,15 +7984,17 @@ impl LineWithInvisibles {
     fn prepaint(
         &mut self,
         line_height: Pixels,
-        scroll_pixel_position: gpui::Point<Pixels>,
+        scroll_position: gpui::Point<ScrollOffset>,
+        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
         row: DisplayRow,
         content_origin: gpui::Point<Pixels>,
         line_elements: &mut SmallVec<[AnyElement; 1]>,
         window: &mut Window,
         cx: &mut App,
     ) {
-        let line_y = line_height * (row.as_f32() - scroll_pixel_position.y / line_height);
-        let mut fragment_origin = content_origin + gpui::point(-scroll_pixel_position.x, line_y);
+        let line_y = f32::from(line_height) * Pixels::from(row.as_f64() - scroll_position.y);
+        let mut fragment_origin =
+            content_origin + gpui::point(Pixels::from(-scroll_pixel_position.x), line_y);
         for fragment in &mut self.fragments {
             match fragment {
                 LineFragment::Text(line) => {
@@ -7927,11 +8028,13 @@ impl LineWithInvisibles {
         cx: &mut App,
     ) {
         let line_height = layout.position_map.line_height;
-        let line_y = line_height
-            * (row.as_f32() - layout.position_map.scroll_pixel_position.y / line_height);
+        let line_y = line_height * (row.as_f64() - layout.position_map.scroll_position.y) as f32;
 
-        let mut fragment_origin =
-            content_origin + gpui::point(-layout.position_map.scroll_pixel_position.x, line_y);
+        let mut fragment_origin = content_origin
+            + gpui::point(
+                Pixels::from(-layout.position_map.scroll_pixel_position.x),
+                line_y,
+            );
 
         for fragment in &self.fragments {
             match fragment {

crates/editor/src/items.rs 🔗

@@ -5,7 +5,7 @@ use crate::{
     display_map::HighlightKey,
     editor_settings::SeedQuerySetting,
     persistence::{DB, SerializedEditor},
-    scroll::ScrollAnchor,
+    scroll::{ScrollAnchor, ScrollOffset},
 };
 use anyhow::{Context as _, Result, anyhow};
 use collections::{HashMap, HashSet};
@@ -1338,7 +1338,7 @@ struct EditorRestorationData {
 
 #[derive(Default, Debug)]
 pub struct RestorationData {
-    pub scroll_position: (BufferRow, gpui::Point<f32>),
+    pub scroll_position: (BufferRow, gpui::Point<ScrollOffset>),
     pub folds: Vec<Range<Point>>,
     pub selections: Vec<Range<Point>>,
 }

crates/editor/src/mouse_context_menu.rs 🔗

@@ -54,7 +54,7 @@ impl MouseContextMenu {
         let content_origin = editor.last_bounds?.origin
             + Point {
                 x: editor.gutter_dimensions.width,
-                y: Pixels(0.0),
+                y: Pixels::ZERO,
             };
         let source_position = editor.to_pixel_point(source, &editor_snapshot, window)?;
         let menu_position = MenuPosition::PinnedToEditor {

crates/editor/src/movement.rs 🔗

@@ -2,7 +2,10 @@
 //! in editor given a given motion (e.g. it handles converting a "move left" command into coordinates in editor). It is exposed mostly for use by vim crate.
 
 use super::{Bias, DisplayPoint, DisplaySnapshot, SelectionGoal, ToDisplayPoint};
-use crate::{DisplayRow, EditorStyle, ToOffset, ToPoint, scroll::ScrollAnchor};
+use crate::{
+    DisplayRow, EditorStyle, ToOffset, ToPoint,
+    scroll::{ScrollAnchor, ScrollOffset},
+};
 use gpui::{Pixels, WindowTextSystem};
 use language::{CharClassifier, Point};
 use multi_buffer::{MultiBufferRow, MultiBufferSnapshot};
@@ -27,8 +30,8 @@ pub struct TextLayoutDetails {
     pub(crate) editor_style: EditorStyle,
     pub(crate) rem_size: Pixels,
     pub scroll_anchor: ScrollAnchor,
-    pub visible_rows: Option<f32>,
-    pub vertical_scroll_margin: f32,
+    pub visible_rows: Option<f64>,
+    pub vertical_scroll_margin: ScrollOffset,
 }
 
 /// Returns a column to the left of the current point, wrapping
@@ -1220,13 +1223,13 @@ mod tests {
                 up(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(0), 2),
-                    SelectionGoal::HorizontalPosition(col_2_x.0),
+                    SelectionGoal::HorizontalPosition(f64::from(col_2_x)),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(0), 0),
-                    SelectionGoal::HorizontalPosition(col_2_x.0),
+                    SelectionGoal::HorizontalPosition(f64::from(col_2_x)),
                 ),
             );
             assert_eq!(
@@ -1251,26 +1254,26 @@ mod tests {
                 up(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(1), 4),
-                    SelectionGoal::HorizontalPosition(col_4_x.0),
+                    SelectionGoal::HorizontalPosition(col_4_x.into()),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(0), 3),
-                    SelectionGoal::HorizontalPosition(col_4_x.0)
+                    SelectionGoal::HorizontalPosition(col_4_x.into())
                 ),
             );
             assert_eq!(
                 down(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(0), 3),
-                    SelectionGoal::HorizontalPosition(col_4_x.0),
+                    SelectionGoal::HorizontalPosition(col_4_x.into()),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(1), 4),
-                    SelectionGoal::HorizontalPosition(col_4_x.0)
+                    SelectionGoal::HorizontalPosition(col_4_x.into())
                 ),
             );
 
@@ -1282,26 +1285,26 @@ mod tests {
                 up(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(3), 5),
-                    SelectionGoal::HorizontalPosition(col_5_x.0),
+                    SelectionGoal::HorizontalPosition(col_5_x.into()),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(1), 4),
-                    SelectionGoal::HorizontalPosition(col_5_x.0)
+                    SelectionGoal::HorizontalPosition(col_5_x.into())
                 ),
             );
             assert_eq!(
                 down(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(1), 4),
-                    SelectionGoal::HorizontalPosition(col_5_x.0),
+                    SelectionGoal::HorizontalPosition(col_5_x.into()),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(3), 5),
-                    SelectionGoal::HorizontalPosition(col_5_x.0)
+                    SelectionGoal::HorizontalPosition(col_5_x.into())
                 ),
             );
 
@@ -1326,13 +1329,13 @@ mod tests {
                 down(
                     &snapshot,
                     DisplayPoint::new(DisplayRow(4), 2),
-                    SelectionGoal::HorizontalPosition(max_point_x.0),
+                    SelectionGoal::HorizontalPosition(max_point_x.into()),
                     false,
                     &text_layout_details
                 ),
                 (
                     DisplayPoint::new(DisplayRow(4), 2),
-                    SelectionGoal::HorizontalPosition(max_point_x.0)
+                    SelectionGoal::HorizontalPosition(max_point_x.into())
                 ),
             );
         });

crates/editor/src/persistence.rs 🔗

@@ -235,7 +235,7 @@ impl EditorDb {
 
     // Returns the scroll top row, and offset
     query! {
-        pub fn get_scroll_position(item_id: ItemId, workspace_id: WorkspaceId) -> Result<Option<(u32, f32, f32)>> {
+        pub fn get_scroll_position(item_id: ItemId, workspace_id: WorkspaceId) -> Result<Option<(u32, f64, f64)>> {
             SELECT scroll_top_row, scroll_horizontal_offset, scroll_vertical_offset
             FROM editors
             WHERE item_id = ? AND workspace_id = ?
@@ -247,8 +247,8 @@ impl EditorDb {
             item_id: ItemId,
             workspace_id: WorkspaceId,
             top_row: u32,
-            vertical_offset: f32,
-            horizontal_offset: f32
+            vertical_offset: f64,
+            horizontal_offset: f64
         ) -> Result<()> {
             UPDATE OR IGNORE editors
             SET

crates/editor/src/scroll.rs 🔗

@@ -30,9 +30,11 @@ const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
 
 pub struct WasScrolled(pub(crate) bool);
 
+pub type ScrollOffset = f64;
+pub type ScrollPixelOffset = f64;
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub struct ScrollAnchor {
-    pub offset: gpui::Point<f32>,
+    pub offset: gpui::Point<ScrollOffset>,
     pub anchor: Anchor,
 }
 
@@ -44,12 +46,12 @@ impl ScrollAnchor {
         }
     }
 
-    pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> {
+    pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<ScrollOffset> {
         self.offset.apply_along(Axis::Vertical, |offset| {
             if self.anchor == Anchor::min() {
                 0.
             } else {
-                let scroll_top = self.anchor.to_display_point(snapshot).row().as_f32();
+                let scroll_top = self.anchor.to_display_point(snapshot).row().as_f64();
                 (offset + scroll_top).max(0.)
             }
         })
@@ -147,19 +149,24 @@ impl ActiveScrollbarState {
 }
 
 pub struct ScrollManager {
-    pub(crate) vertical_scroll_margin: f32,
+    pub(crate) vertical_scroll_margin: ScrollOffset,
     anchor: ScrollAnchor,
     ongoing: OngoingScroll,
     /// The second element indicates whether the autoscroll request is local
     /// (true) or remote (false). Local requests are initiated by user actions,
     /// while remote requests come from external sources.
     autoscroll_request: Option<(Autoscroll, bool)>,
-    last_autoscroll: Option<(gpui::Point<f32>, f32, f32, AutoscrollStrategy)>,
+    last_autoscroll: Option<(
+        gpui::Point<ScrollOffset>,
+        ScrollOffset,
+        ScrollOffset,
+        AutoscrollStrategy,
+    )>,
     show_scrollbars: bool,
     hide_scrollbar_task: Option<Task<()>>,
     active_scrollbar: Option<ActiveScrollbarState>,
-    visible_line_count: Option<f32>,
-    visible_column_count: Option<f32>,
+    visible_line_count: Option<f64>,
+    visible_column_count: Option<f64>,
     forbid_vertical_scroll: bool,
     minimap_thumb_state: Option<ScrollbarThumbState>,
 }
@@ -200,13 +207,13 @@ impl ScrollManager {
         self.ongoing.axis = axis;
     }
 
-    pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<f32> {
+    pub fn scroll_position(&self, snapshot: &DisplaySnapshot) -> gpui::Point<ScrollOffset> {
         self.anchor.scroll_position(snapshot)
     }
 
     fn set_scroll_position(
         &mut self,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         map: &DisplaySnapshot,
         local: bool,
         autoscroll: bool,
@@ -219,7 +226,7 @@ impl ScrollManager {
             ScrollBeyondLastLine::OnePage => scroll_top,
             ScrollBeyondLastLine::Off => {
                 if let Some(height_in_lines) = self.visible_line_count {
-                    let max_row = map.max_point().row().0 as f32;
+                    let max_row = map.max_point().row().as_f64();
                     scroll_top.min(max_row - height_in_lines + 1.).max(0.)
                 } else {
                     scroll_top
@@ -227,7 +234,7 @@ impl ScrollManager {
             }
             ScrollBeyondLastLine::VerticalScrollMargin => {
                 if let Some(height_in_lines) = self.visible_line_count {
-                    let max_row = map.max_point().row().0 as f32;
+                    let max_row = map.max_point().row().as_f64();
                     scroll_top
                         .min(max_row - height_in_lines + 1. + self.vertical_scroll_margin)
                         .max(0.)
@@ -251,7 +258,7 @@ impl ScrollManager {
                 anchor: top_anchor,
                 offset: point(
                     scroll_position.x.max(0.),
-                    scroll_top - top_anchor.to_display_point(map).row().as_f32(),
+                    scroll_top - top_anchor.to_display_point(map).row().as_f64(),
                 ),
             },
             scroll_top_buffer_point.row,
@@ -437,7 +444,7 @@ impl ScrollManager {
         self.minimap_thumb_state
     }
 
-    pub fn clamp_scroll_left(&mut self, max: f32) -> bool {
+    pub fn clamp_scroll_left(&mut self, max: f64) -> bool {
         if max < self.anchor.offset.x {
             self.anchor.offset.x = max;
             true
@@ -461,11 +468,11 @@ impl Editor {
     }
 
     pub fn set_vertical_scroll_margin(&mut self, margin_rows: usize, cx: &mut Context<Self>) {
-        self.scroll_manager.vertical_scroll_margin = margin_rows as f32;
+        self.scroll_manager.vertical_scroll_margin = margin_rows as f64;
         cx.notify();
     }
 
-    pub fn visible_line_count(&self) -> Option<f32> {
+    pub fn visible_line_count(&self) -> Option<f64> {
         self.scroll_manager.visible_line_count
     }
 
@@ -474,13 +481,13 @@ impl Editor {
             .map(|line_count| line_count as u32 - 1)
     }
 
-    pub fn visible_column_count(&self) -> Option<f32> {
+    pub fn visible_column_count(&self) -> Option<f64> {
         self.scroll_manager.visible_column_count
     }
 
     pub(crate) fn set_visible_line_count(
         &mut self,
-        lines: f32,
+        lines: f64,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) {
@@ -499,7 +506,7 @@ impl Editor {
         }
     }
 
-    pub(crate) fn set_visible_column_count(&mut self, columns: f32) {
+    pub(crate) fn set_visible_column_count(&mut self, columns: f64) {
         self.scroll_manager.visible_column_count = Some(columns);
     }
 
@@ -514,13 +521,14 @@ impl Editor {
             delta.y = 0.0;
         }
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
-        let position = self.scroll_manager.anchor.scroll_position(&display_map) + delta;
+        let position =
+            self.scroll_manager.anchor.scroll_position(&display_map) + delta.map(f64::from);
         self.set_scroll_position_taking_display_map(position, true, false, display_map, window, cx);
     }
 
     pub fn set_scroll_position(
         &mut self,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         window: &mut Window,
         cx: &mut Context<Self>,
     ) -> WasScrolled {
@@ -556,7 +564,7 @@ impl Editor {
 
     pub(crate) fn set_scroll_position_internal(
         &mut self,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         local: bool,
         autoscroll: bool,
         window: &mut Window,
@@ -575,7 +583,7 @@ impl Editor {
 
     fn set_scroll_position_taking_display_map(
         &mut self,
-        scroll_position: gpui::Point<f32>,
+        scroll_position: gpui::Point<ScrollOffset>,
         local: bool,
         autoscroll: bool,
         display_map: DisplaySnapshot,
@@ -610,7 +618,7 @@ impl Editor {
         editor_was_scrolled
     }
 
-    pub fn scroll_position(&self, cx: &mut Context<Self>) -> gpui::Point<f32> {
+    pub fn scroll_position(&self, cx: &mut Context<Self>) -> gpui::Point<ScrollOffset> {
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         self.scroll_manager.anchor.scroll_position(&display_map)
     }
@@ -697,9 +705,9 @@ impl Editor {
         if matches!(
             settings.defaults.soft_wrap,
             SoftWrap::PreferredLineLength | SoftWrap::Bounded
-        ) && (settings.defaults.preferred_line_length as f32) < visible_column_count
+        ) && (settings.defaults.preferred_line_length as f64) < visible_column_count
         {
-            visible_column_count = settings.defaults.preferred_line_length as f32;
+            visible_column_count = settings.defaults.preferred_line_length as f64;
         }
 
         // If the scroll position is currently at the left edge of the document
@@ -710,7 +718,8 @@ impl Editor {
             && amount.columns(visible_column_count) > 0.
             && let Some(last_position_map) = &self.last_position_map
         {
-            current_position.x += self.gutter_dimensions.margin / last_position_map.em_advance;
+            current_position.x +=
+                f64::from(self.gutter_dimensions.margin / last_position_map.em_advance);
         }
         let new_position = current_position
             + point(

crates/editor/src/scroll/actions.rs 🔗

@@ -2,7 +2,7 @@ use super::Axis;
 use crate::{
     Autoscroll, Editor, EditorMode, NextScreen, NextScrollCursorCenterTopBottom,
     SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT, ScrollCursorBottom, ScrollCursorCenter,
-    ScrollCursorCenterTopBottom, ScrollCursorTop, display_map::DisplayRow,
+    ScrollCursorCenterTopBottom, ScrollCursorTop, display_map::DisplayRow, scroll::ScrollOffset,
 };
 use gpui::{Context, Point, Window};
 
@@ -25,7 +25,7 @@ impl Editor {
 
     pub fn scroll(
         &mut self,
-        scroll_position: Point<f32>,
+        scroll_position: Point<ScrollOffset>,
         axis: Option<Axis>,
         window: &mut Window,
         cx: &mut Context<Self>,

crates/editor/src/scroll/autoscroll.rs 🔗

@@ -1,11 +1,12 @@
 use crate::{
     DisplayRow, Editor, EditorMode, LineWithInvisibles, RowExt, SelectionEffects,
-    display_map::ToDisplayPoint, scroll::WasScrolled,
+    display_map::ToDisplayPoint,
+    scroll::{ScrollOffset, WasScrolled},
 };
-use gpui::{Bounds, Context, Pixels, Window, px};
+use gpui::{Bounds, Context, Pixels, Window};
 use language::Point;
 use multi_buffer::Anchor;
-use std::{cmp, f32};
+use std::cmp;
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
 pub enum Autoscroll {
@@ -106,20 +107,21 @@ impl Editor {
         &mut self,
         bounds: Bounds<Pixels>,
         line_height: Pixels,
-        max_scroll_top: f32,
+        max_scroll_top: ScrollOffset,
         autoscroll_request: Option<(Autoscroll, bool)>,
         window: &mut Window,
         cx: &mut Context<Editor>,
     ) -> (NeedsHorizontalAutoscroll, WasScrolled) {
         let viewport_height = bounds.size.height;
-        let visible_lines = viewport_height / line_height;
+        let visible_lines = ScrollOffset::from(viewport_height / line_height);
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
         let original_y = scroll_position.y;
         if let Some(last_bounds) = self.expect_bounds_change.take()
             && scroll_position.y != 0.
         {
-            scroll_position.y += (bounds.top() - last_bounds.top()) / line_height;
+            scroll_position.y +=
+                ScrollOffset::from((bounds.top() - last_bounds.top()) / line_height);
             if scroll_position.y < 0. {
                 scroll_position.y = 0.;
             }
@@ -143,7 +145,7 @@ impl Editor {
         if let Some(first_highlighted_row) =
             self.highlighted_display_row_for_autoscroll(&display_map)
         {
-            target_top = first_highlighted_row.as_f32();
+            target_top = first_highlighted_row.as_f64();
             target_bottom = target_top + 1.;
         } else {
             let selections = self.selections.all::<Point>(cx);
@@ -154,7 +156,7 @@ impl Editor {
                 .head()
                 .to_display_point(&display_map)
                 .row()
-                .as_f32();
+                .as_f64();
             target_bottom = selections
                 .last()
                 .unwrap()
@@ -162,7 +164,7 @@ impl Editor {
                 .to_display_point(&display_map)
                 .row()
                 .next_row()
-                .as_f32();
+                .as_f64();
 
             let selections_fit = target_bottom - target_top <= visible_lines;
             if matches!(
@@ -178,7 +180,7 @@ impl Editor {
                     .head()
                     .to_display_point(&display_map)
                     .row()
-                    .as_f32();
+                    .as_f64();
                 target_top = newest_selection_top;
                 target_bottom = newest_selection_top + 1.;
             }
@@ -209,7 +211,7 @@ impl Editor {
             }
         };
         if let Autoscroll::Strategy(_, Some(anchor)) = autoscroll {
-            target_top = anchor.to_display_point(&display_map).row().as_f32();
+            target_top = anchor.to_display_point(&display_map).row().as_f64();
             target_bottom = target_top + 1.;
         }
 
@@ -254,11 +256,11 @@ impl Editor {
                 self.set_scroll_position_internal(scroll_position, local, true, window, cx)
             }
             AutoscrollStrategy::TopRelative(lines) => {
-                scroll_position.y = target_top - lines as f32;
+                scroll_position.y = target_top - lines as ScrollOffset;
                 self.set_scroll_position_internal(scroll_position, local, true, window, cx)
             }
             AutoscrollStrategy::BottomRelative(lines) => {
-                scroll_position.y = target_bottom + lines as f32;
+                scroll_position.y = target_bottom + lines as ScrollOffset;
                 self.set_scroll_position_internal(scroll_position, local, true, window, cx)
             }
         };
@@ -284,22 +286,25 @@ impl Editor {
         autoscroll_request: Option<(Autoscroll, bool)>,
         window: &mut Window,
         cx: &mut Context<Self>,
-    ) -> Option<gpui::Point<f32>> {
+    ) -> Option<gpui::Point<ScrollOffset>> {
         let (_, local) = autoscroll_request?;
+        let em_advance = ScrollOffset::from(em_advance);
+        let viewport_width = ScrollOffset::from(viewport_width);
+        let scroll_width = ScrollOffset::from(scroll_width);
 
         let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
         let selections = self.selections.all::<Point>(cx);
         let mut scroll_position = self.scroll_manager.scroll_position(&display_map);
 
         let mut target_left;
-        let mut target_right;
+        let mut target_right: f64;
 
         if self
             .highlighted_display_row_for_autoscroll(&display_map)
             .is_none()
         {
-            target_left = px(f32::INFINITY);
-            target_right = px(0.);
+            target_left = f64::INFINITY;
+            target_right = 0.;
             for selection in selections {
                 let head = selection.head().to_display_point(&display_map);
                 if head.row() >= start_row
@@ -307,21 +312,22 @@ impl Editor {
                 {
                     let start_column = head.column();
                     let end_column = cmp::min(display_map.line_len(head.row()), head.column());
-                    target_left = target_left.min(
+                    target_left = target_left.min(ScrollOffset::from(
                         layouts[head.row().minus(start_row) as usize]
                             .x_for_index(start_column as usize)
                             + self.gutter_dimensions.margin,
-                    );
+                    ));
                     target_right = target_right.max(
-                        layouts[head.row().minus(start_row) as usize]
-                            .x_for_index(end_column as usize)
-                            + em_advance,
+                        ScrollOffset::from(
+                            layouts[head.row().minus(start_row) as usize]
+                                .x_for_index(end_column as usize),
+                        ) + em_advance,
                     );
                 }
             }
         } else {
-            target_left = px(0.);
-            target_right = px(0.);
+            target_left = 0.;
+            target_right = 0.;
         }
 
         target_right = target_right.min(scroll_width);

crates/editor/src/scroll/scroll_amount.rs 🔗

@@ -1,5 +1,5 @@
 use serde::Deserialize;
-use ui::{Pixels, px};
+use ui::Pixels;
 
 #[derive(Debug)]
 pub enum ScrollDirection {
@@ -28,41 +28,41 @@ pub enum ScrollAmount {
 }
 
 impl ScrollAmount {
-    pub fn lines(&self, mut visible_line_count: f32) -> f32 {
+    pub fn lines(&self, mut visible_line_count: f64) -> f64 {
         match self {
-            Self::Line(count) => *count,
+            Self::Line(count) => *count as f64,
             Self::Page(count) => {
                 // for full pages subtract one to leave an anchor line
                 if self.is_full_page() {
                     visible_line_count -= 1.0
                 }
-                (visible_line_count * count).trunc()
+                (visible_line_count * (*count as f64)).trunc()
             }
             Self::Column(_count) => 0.0,
             Self::PageWidth(_count) => 0.0,
         }
     }
 
-    pub fn columns(&self, visible_column_count: f32) -> f32 {
+    pub fn columns(&self, visible_column_count: f64) -> f64 {
         match self {
             Self::Line(_count) => 0.0,
             Self::Page(_count) => 0.0,
-            Self::Column(count) => *count,
-            Self::PageWidth(count) => (visible_column_count * count).trunc(),
+            Self::Column(count) => *count as f64,
+            Self::PageWidth(count) => (visible_column_count * *count as f64).trunc(),
         }
     }
 
     pub fn pixels(&self, line_height: Pixels, height: Pixels) -> Pixels {
         match self {
-            ScrollAmount::Line(x) => px(line_height.0 * x),
-            ScrollAmount::Page(x) => px(height.0 * x),
+            ScrollAmount::Line(x) => line_height * *x,
+            ScrollAmount::Page(x) => height * *x,
             // This function seems to only be leveraged by the popover that is
             // displayed by the editor when, for example, viewing a function's
             // documentation. Right now that only supports vertical scrolling,
             // so I'm leaving this at 0.0 for now to try and make it clear that
             // this should not have an impact on that?
-            ScrollAmount::Column(_) => px(0.0),
-            ScrollAmount::PageWidth(_) => px(0.0),
+            ScrollAmount::Column(_) => Pixels::ZERO,
+            ScrollAmount::PageWidth(_) => Pixels::ZERO,
         }
     }
 

crates/editor/src/test/editor_test_context.rs 🔗

@@ -275,7 +275,8 @@ impl EditorTestContext {
             let details = editor.text_layout_details(window);
 
             let y = pixel_position.y
-                + line_height * (display_point.row().as_f32() - newest_point.row().as_f32());
+                + f32::from(line_height)
+                    * Pixels::from(display_point.row().as_f64() - newest_point.row().as_f64());
             let x = pixel_position.x + snapshot.x_for_display_point(display_point, &details)
                 - snapshot.x_for_display_point(newest_point, &details);
             Point::new(x, y)

crates/file_finder/src/file_finder.rs 🔗

@@ -355,9 +355,9 @@ impl FileFinder {
         match width_setting {
             FileFinderWidth::Small => small_width,
             FileFinderWidth::Full => window_width,
-            FileFinderWidth::XLarge => (window_width - Pixels(512.)).max(small_width),
-            FileFinderWidth::Large => (window_width - Pixels(768.)).max(small_width),
-            FileFinderWidth::Medium => (window_width - Pixels(1024.)).max(small_width),
+            FileFinderWidth::XLarge => (window_width - px(512.)).max(small_width),
+            FileFinderWidth::Large => (window_width - px(768.)).max(small_width),
+            FileFinderWidth::Medium => (window_width - px(1024.)).max(small_width),
         }
     }
 }

crates/git_ui/src/commit_modal.rs 🔗

@@ -40,7 +40,8 @@ impl ModalContainerProperties {
         let font_size = style.font_size.to_pixels(window.rem_size());
 
         if let Ok(em_width) = window.text_system().em_width(font_id, font_size) {
-            modal_width = preferred_char_width as f32 * em_width.0 + (container_padding * 2.0);
+            modal_width =
+                f32::from(preferred_char_width as f32 * em_width + px(container_padding * 2.0));
         }
 
         Self {

crates/go_to_line/src/go_to_line.rs 🔗

@@ -3,7 +3,8 @@ pub mod cursor_position;
 use cursor_position::{LineIndicatorFormat, UserCaretPosition};
 use editor::{
     Anchor, Editor, MultiBufferSnapshot, RowHighlightOptions, SelectionEffects, ToOffset, ToPoint,
-    actions::Tab, scroll::Autoscroll,
+    actions::Tab,
+    scroll::{Autoscroll, ScrollOffset},
 };
 use gpui::{
     App, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, Render, SharedString, Styled,
@@ -26,7 +27,7 @@ pub struct GoToLine {
     line_editor: Entity<Editor>,
     active_editor: Entity<Editor>,
     current_text: SharedString,
-    prev_scroll_position: Option<gpui::Point<f32>>,
+    prev_scroll_position: Option<gpui::Point<ScrollOffset>>,
     _subscriptions: Vec<Subscription>,
 }
 

crates/gpui/examples/image_loading.rs 🔗

@@ -2,9 +2,9 @@ use std::{path::Path, sync::Arc, time::Duration};
 
 use gpui::{
     Animation, AnimationExt, App, Application, Asset, AssetLogger, AssetSource, Bounds, Context,
-    Hsla, ImageAssetLoader, ImageCacheError, ImgResourceLoader, LOADING_DELAY, Length, Pixels,
-    RenderImage, Resource, SharedString, Window, WindowBounds, WindowOptions, black, div, img,
-    prelude::*, pulsating_between, px, red, size,
+    Hsla, ImageAssetLoader, ImageCacheError, ImgResourceLoader, LOADING_DELAY, Length, RenderImage,
+    Resource, SharedString, Window, WindowBounds, WindowOptions, black, div, img, prelude::*,
+    pulsating_between, px, red, size,
 };
 
 struct Assets {}
@@ -105,7 +105,7 @@ impl Render for ImageLoadingExample {
                 div()
                     .flex()
                     .bg(gpui::white())
-                    .size(Length::Definite(Pixels(300.0).into()))
+                    .size(Length::Definite(px(300.0).into()))
                     .justify_center()
                     .items_center()
                     .child({
@@ -199,7 +199,7 @@ fn main() {
             let options = WindowOptions {
                 window_bounds: Some(WindowBounds::Windowed(Bounds::centered(
                     None,
-                    size(px(300.), Pixels(300.)),
+                    size(px(300.), px(300.)),
                     cx,
                 ))),
                 ..Default::default()

crates/gpui/examples/text.rs 🔗

@@ -132,11 +132,11 @@ impl RenderOnce for Specimen {
         let mut line_height = global_style.line_height;
 
         if let Some(style_override) = style_override {
-            font_size = style_override.font_size.to_pixels(rem_size).0;
+            font_size = style_override.font_size.to_pixels(rem_size).into();
             line_height = match style_override.line_height {
                 DefiniteLength::Absolute(absolute_len) => match absolute_len {
-                    AbsoluteLength::Rems(absolute_len) => absolute_len.to_pixels(rem_size).0,
-                    AbsoluteLength::Pixels(absolute_len) => absolute_len.0,
+                    AbsoluteLength::Rems(absolute_len) => absolute_len.to_pixels(rem_size).into(),
+                    AbsoluteLength::Pixels(absolute_len) => absolute_len.into(),
                 },
                 DefiniteLength::Fraction(value) => value,
             };

crates/gpui/src/elements/img.rs 🔗

@@ -352,7 +352,7 @@ impl Element for Img {
                                     Length::Definite(DefiniteLength::Absolute(
                                         AbsoluteLength::Pixels(width),
                                     )) => Length::Definite(
-                                        px(image_size.height.0 * width.0 / image_size.width.0)
+                                        px(image_size.height * f32::from(width) / image_size.width)
                                             .into(),
                                     ),
                                     _ => Length::Definite(image_size.height.into()),

crates/gpui/src/geometry.rs 🔗

@@ -200,9 +200,9 @@ impl Point<Pixels> {
     ///
     /// ```
     /// # use gpui::{Point, Pixels, ScaledPixels};
-    /// let p = Point { x: Pixels(10.0), y: Pixels(20.0) };
+    /// let p = Point { x: Pixels::from(10.0), y: Pixels::from(20.0) };
     /// let scaled_p = p.scale(1.5);
-    /// assert_eq!(scaled_p, Point { x: ScaledPixels(15.0), y: ScaledPixels(30.0) });
+    /// assert_eq!(scaled_p, Point { x: ScaledPixels::from(15.0), y: ScaledPixels::from(30.0) });
     /// ```
     pub fn scale(&self, factor: f32) -> Point<ScaledPixels> {
         Point {
@@ -217,7 +217,7 @@ impl Point<Pixels> {
     ///
     /// ```
     /// # use gpui::{Pixels, Point};
-    /// let p = Point { x: Pixels(3.0), y: Pixels(4.0) };
+    /// let p = Point { x: Pixels::from(3.0), y: Pixels::from(4.0) };
     /// assert_eq!(p.magnitude(), 5.0);
     /// ```
     pub fn magnitude(&self) -> f64 {
@@ -493,9 +493,9 @@ impl Size<Pixels> {
     ///
     /// ```
     /// # use gpui::{Size, Pixels, ScaledPixels};
-    /// let size = Size { width: Pixels(100.0), height: Pixels(50.0) };
+    /// let size = Size { width: Pixels::from(100.0), height: Pixels::from(50.0) };
     /// let scaled_size = size.scale(2.0);
-    /// assert_eq!(scaled_size, Size { width: ScaledPixels(200.0), height: ScaledPixels(100.0) });
+    /// assert_eq!(scaled_size, Size { width: ScaledPixels::from(200.0), height: ScaledPixels::from(100.0) });
     /// ```
     pub fn scale(&self, factor: f32) -> Size<ScaledPixels> {
         Size {
@@ -1628,19 +1628,19 @@ impl Bounds<Pixels> {
     /// ```
     /// # use gpui::{Bounds, Point, Size, Pixels, ScaledPixels, DevicePixels};
     /// let bounds = Bounds {
-    ///     origin: Point { x: Pixels(10.0), y: Pixels(20.0) },
-    ///     size: Size { width: Pixels(30.0), height: Pixels(40.0) },
+    ///     origin: Point { x: Pixels::from(10.0), y: Pixels::from(20.0) },
+    ///     size: Size { width: Pixels::from(30.0), height: Pixels::from(40.0) },
     /// };
     /// let display_scale_factor = 2.0;
     /// let scaled_bounds = bounds.scale(display_scale_factor);
     /// assert_eq!(scaled_bounds, Bounds {
     ///     origin: Point {
-    ///         x: ScaledPixels(20.0),
-    ///         y: ScaledPixels(40.0),
+    ///         x: ScaledPixels::from(20.0),
+    ///         y: ScaledPixels::from(40.0),
     ///     },
     ///     size: Size {
-    ///         width: ScaledPixels(60.0),
-    ///         height: ScaledPixels(80.0)
+    ///         width: ScaledPixels::from(60.0),
+    ///         height: ScaledPixels::from(80.0)
     ///     },
     /// });
     /// ```
@@ -1888,10 +1888,10 @@ impl Edges<Length> {
     /// ```
     /// # use gpui::{DefiniteLength, Edges, Length, Pixels};
     /// let no_edges = Edges::<Length>::zero();
-    /// assert_eq!(no_edges.top, Length::Definite(DefiniteLength::from(Pixels(0.))));
-    /// assert_eq!(no_edges.right, Length::Definite(DefiniteLength::from(Pixels(0.))));
-    /// assert_eq!(no_edges.bottom, Length::Definite(DefiniteLength::from(Pixels(0.))));
-    /// assert_eq!(no_edges.left, Length::Definite(DefiniteLength::from(Pixels(0.))));
+    /// assert_eq!(no_edges.top, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
+    /// assert_eq!(no_edges.right, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
+    /// assert_eq!(no_edges.bottom, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
+    /// assert_eq!(no_edges.left, Length::Definite(DefiniteLength::from(Pixels::ZERO)));
     /// ```
     pub fn zero() -> Self {
         Self {
@@ -1993,10 +1993,10 @@ impl Edges<AbsoluteLength> {
     /// ```
     /// # use gpui::{AbsoluteLength, Edges, Pixels};
     /// let no_edges = Edges::<AbsoluteLength>::zero();
-    /// assert_eq!(no_edges.top, AbsoluteLength::Pixels(Pixels(0.0)));
-    /// assert_eq!(no_edges.right, AbsoluteLength::Pixels(Pixels(0.0)));
-    /// assert_eq!(no_edges.bottom, AbsoluteLength::Pixels(Pixels(0.0)));
-    /// assert_eq!(no_edges.left, AbsoluteLength::Pixels(Pixels(0.0)));
+    /// assert_eq!(no_edges.top, AbsoluteLength::Pixels(Pixels::ZERO));
+    /// assert_eq!(no_edges.right, AbsoluteLength::Pixels(Pixels::ZERO));
+    /// assert_eq!(no_edges.bottom, AbsoluteLength::Pixels(Pixels::ZERO));
+    /// assert_eq!(no_edges.left, AbsoluteLength::Pixels(Pixels::ZERO));
     /// ```
     pub fn zero() -> Self {
         Self {
@@ -2066,16 +2066,16 @@ impl Edges<Pixels> {
     /// ```
     /// # use gpui::{Edges, Pixels, ScaledPixels};
     /// let edges = Edges {
-    ///     top: Pixels(10.0),
-    ///     right: Pixels(20.0),
-    ///     bottom: Pixels(30.0),
-    ///     left: Pixels(40.0),
+    ///     top: Pixels::from(10.0),
+    ///     right: Pixels::from(20.0),
+    ///     bottom: Pixels::from(30.0),
+    ///     left: Pixels::from(40.0),
     /// };
     /// let scaled_edges = edges.scale(2.0);
-    /// assert_eq!(scaled_edges.top, ScaledPixels(20.0));
-    /// assert_eq!(scaled_edges.right, ScaledPixels(40.0));
-    /// assert_eq!(scaled_edges.bottom, ScaledPixels(60.0));
-    /// assert_eq!(scaled_edges.left, ScaledPixels(80.0));
+    /// assert_eq!(scaled_edges.top, ScaledPixels::from(20.0));
+    /// assert_eq!(scaled_edges.right, ScaledPixels::from(40.0));
+    /// assert_eq!(scaled_edges.bottom, ScaledPixels::from(60.0));
+    /// assert_eq!(scaled_edges.left, ScaledPixels::from(80.0));
     /// ```
     pub fn scale(&self, factor: f32) -> Edges<ScaledPixels> {
         Edges {
@@ -2273,18 +2273,18 @@ impl Corners<AbsoluteLength> {
     /// ```
     /// # use gpui::{Corners, AbsoluteLength, Pixels, Rems, Size};
     /// let corners = Corners {
-    ///     top_left: AbsoluteLength::Pixels(Pixels(15.0)),
+    ///     top_left: AbsoluteLength::Pixels(Pixels::from(15.0)),
     ///     top_right: AbsoluteLength::Rems(Rems(1.0)),
-    ///     bottom_right: AbsoluteLength::Pixels(Pixels(30.0)),
+    ///     bottom_right: AbsoluteLength::Pixels(Pixels::from(30.0)),
     ///     bottom_left: AbsoluteLength::Rems(Rems(2.0)),
     /// };
-    /// let rem_size = Pixels(16.0);
+    /// let rem_size = Pixels::from(16.0);
     /// let corners_in_pixels = corners.to_pixels(rem_size);
     ///
-    /// assert_eq!(corners_in_pixels.top_left, Pixels(15.0));
-    /// assert_eq!(corners_in_pixels.top_right, Pixels(16.0)); // 1 rem converted to pixels
-    /// assert_eq!(corners_in_pixels.bottom_right, Pixels(30.0));
-    /// assert_eq!(corners_in_pixels.bottom_left, Pixels(32.0)); // 2 rems converted to pixels
+    /// assert_eq!(corners_in_pixels.top_left, Pixels::from(15.0));
+    /// assert_eq!(corners_in_pixels.top_right, Pixels::from(16.0)); // 1 rem converted to pixels
+    /// assert_eq!(corners_in_pixels.bottom_right, Pixels::from(30.0));
+    /// assert_eq!(corners_in_pixels.bottom_left, Pixels::from(32.0)); // 2 rems converted to pixels
     /// ```
     pub fn to_pixels(self, rem_size: Pixels) -> Corners<Pixels> {
         Corners {
@@ -2314,16 +2314,16 @@ impl Corners<Pixels> {
     /// ```
     /// # use gpui::{Corners, Pixels, ScaledPixels};
     /// let corners = Corners {
-    ///     top_left: Pixels(10.0),
-    ///     top_right: Pixels(20.0),
-    ///     bottom_right: Pixels(30.0),
-    ///     bottom_left: Pixels(40.0),
+    ///     top_left: Pixels::from(10.0),
+    ///     top_right: Pixels::from(20.0),
+    ///     bottom_right: Pixels::from(30.0),
+    ///     bottom_left: Pixels::from(40.0),
     /// };
     /// let scaled_corners = corners.scale(2.0);
-    /// assert_eq!(scaled_corners.top_left, ScaledPixels(20.0));
-    /// assert_eq!(scaled_corners.top_right, ScaledPixels(40.0));
-    /// assert_eq!(scaled_corners.bottom_right, ScaledPixels(60.0));
-    /// assert_eq!(scaled_corners.bottom_left, ScaledPixels(80.0));
+    /// assert_eq!(scaled_corners.top_left, ScaledPixels::from(20.0));
+    /// assert_eq!(scaled_corners.top_right, ScaledPixels::from(40.0));
+    /// assert_eq!(scaled_corners.bottom_right, ScaledPixels::from(60.0));
+    /// assert_eq!(scaled_corners.bottom_left, ScaledPixels::from(80.0));
     /// ```
     #[must_use]
     pub fn scale(&self, factor: f32) -> Corners<ScaledPixels> {
@@ -2391,12 +2391,12 @@ impl<T: Clone + Debug + Default + PartialEq> Corners<T> {
     /// ```
     /// # use gpui::{Corners, Pixels, Rems};
     /// let corners = Corners {
-    ///     top_left: Pixels(10.0),
-    ///     top_right: Pixels(20.0),
-    ///     bottom_right: Pixels(30.0),
-    ///     bottom_left: Pixels(40.0),
+    ///     top_left: Pixels::from(10.0),
+    ///     top_right: Pixels::from(20.0),
+    ///     bottom_right: Pixels::from(30.0),
+    ///     bottom_left: Pixels::from(40.0),
     /// };
-    /// let corners_in_rems = corners.map(|&px| Rems(px.0 / 16.0));
+    /// let corners_in_rems = corners.map(|&px| Rems(f32::from(px) / 16.0));
     /// assert_eq!(corners_in_rems, Corners {
     ///     top_left: Rems(0.625),
     ///     top_right: Rems(1.25),
@@ -2547,11 +2547,11 @@ impl From<Percentage> for Radians {
 /// use gpui::{Pixels, ScaledPixels};
 ///
 /// // Define a length of 10 pixels
-/// let length = Pixels(10.0);
+/// let length = Pixels::from(10.0);
 ///
 /// // Define a length and scale it by a factor of 2
 /// let scaled_length = length.scale(2.0);
-/// assert_eq!(scaled_length, ScaledPixels(20.0));
+/// assert_eq!(scaled_length, ScaledPixels::from(20.0));
 /// ```
 #[derive(
     Clone,
@@ -2570,7 +2570,7 @@ impl From<Percentage> for Radians {
     JsonSchema,
 )]
 #[repr(transparent)]
-pub struct Pixels(pub f32);
+pub struct Pixels(pub(crate) f32);
 
 impl Div for Pixels {
     type Output = f32;
@@ -2945,7 +2945,7 @@ impl From<usize> for DevicePixels {
 /// display resolutions.
 #[derive(Clone, Copy, Default, Add, AddAssign, Sub, SubAssign, Div, DivAssign, PartialEq)]
 #[repr(transparent)]
-pub struct ScaledPixels(pub f32);
+pub struct ScaledPixels(pub(crate) f32);
 
 impl ScaledPixels {
     /// Floors the `ScaledPixels` value to the nearest whole number.
@@ -3011,6 +3011,12 @@ impl From<ScaledPixels> for u32 {
     }
 }
 
+impl From<f32> for ScaledPixels {
+    fn from(pixels: f32) -> Self {
+        Self(pixels)
+    }
+}
+
 impl Div for ScaledPixels {
     type Output = f32;
 
@@ -3180,12 +3186,12 @@ impl AbsoluteLength {
     ///
     /// ```
     /// # use gpui::{AbsoluteLength, Pixels, Rems};
-    /// let length_in_pixels = AbsoluteLength::Pixels(Pixels(42.0));
+    /// let length_in_pixels = AbsoluteLength::Pixels(Pixels::from(42.0));
     /// let length_in_rems = AbsoluteLength::Rems(Rems(2.0));
-    /// let rem_size = Pixels(16.0);
+    /// let rem_size = Pixels::from(16.0);
     ///
-    /// assert_eq!(length_in_pixels.to_pixels(rem_size), Pixels(42.0));
-    /// assert_eq!(length_in_rems.to_pixels(rem_size), Pixels(32.0));
+    /// assert_eq!(length_in_pixels.to_pixels(rem_size), Pixels::from(42.0));
+    /// assert_eq!(length_in_rems.to_pixels(rem_size), Pixels::from(32.0));
     /// ```
     pub fn to_pixels(self, rem_size: Pixels) -> Pixels {
         match self {
@@ -3330,9 +3336,9 @@ impl DefiniteLength {
     /// let base_size = AbsoluteLength::Pixels(px(100.0));
     /// let rem_size = px(16.0);
     ///
-    /// assert_eq!(length_in_pixels.to_pixels(base_size, rem_size), Pixels(42.0));
-    /// assert_eq!(length_in_rems.to_pixels(base_size, rem_size), Pixels(32.0));
-    /// assert_eq!(length_as_fraction.to_pixels(base_size, rem_size), Pixels(50.0));
+    /// assert_eq!(length_in_pixels.to_pixels(base_size, rem_size), Pixels::from(42.0));
+    /// assert_eq!(length_in_rems.to_pixels(base_size, rem_size), Pixels::from(32.0));
+    /// assert_eq!(length_as_fraction.to_pixels(base_size, rem_size), Pixels::from(50.0));
     /// ```
     pub fn to_pixels(self, base_size: AbsoluteLength, rem_size: Pixels) -> Pixels {
         match self {

crates/gpui/src/platform/linux/x11/window.rs 🔗

@@ -1204,7 +1204,7 @@ impl PlatformWindow for X11Window {
             self.0.xcb.query_pointer(self.0.x_window),
         )
         .log_err()
-        .map_or(Point::new(Pixels(0.0), Pixels(0.0)), |reply| {
+        .map_or(Point::new(Pixels::ZERO, Pixels::ZERO), |reply| {
             Point::new((reply.root_x as u32).into(), (reply.root_y as u32).into())
         })
     }

crates/gpui/src/text_system/line.rs 🔗

@@ -585,7 +585,7 @@ fn aligned_origin_x(
 
     match align {
         TextAlign::Left => origin.x,
-        TextAlign::Center => (2.0 * origin.x + align_width - line_width) / 2.0,
+        TextAlign::Center => (origin.x * 2.0 + align_width - line_width) / 2.0,
         TextAlign::Right => origin.x + align_width - line_width,
     }
 }

crates/gpui/src/window.rs 🔗

@@ -4559,7 +4559,7 @@ impl Window {
             if let Some(inspector) = self.inspector.clone() {
                 inspector.update(cx, |inspector, _cx| {
                     if let Some(depth) = inspector.pick_depth.as_mut() {
-                        *depth += delta_y.0 / SCROLL_PIXELS_PER_LAYER;
+                        *depth += f32::from(delta_y) / SCROLL_PIXELS_PER_LAYER;
                         let max_depth = self.mouse_hit_test.ids.len() as f32 - 0.5;
                         if *depth < 0.0 {
                             *depth = 0.0;

crates/image_viewer/src/image_viewer.rs 🔗

@@ -303,10 +303,10 @@ impl Render for ImageView {
                                     _cx: &mut App| {
             let square_size = 32.0;
 
-            let start_y = bounds.origin.y.0;
-            let height = bounds.size.height.0;
-            let start_x = bounds.origin.x.0;
-            let width = bounds.size.width.0;
+            let start_y = bounds.origin.y.into();
+            let height: f32 = bounds.size.height.into();
+            let start_x = bounds.origin.x.into();
+            let width: f32 = bounds.size.width.into();
 
             let mut y = start_y;
             let mut x = start_x;

crates/language_model/src/request.rs 🔗

@@ -119,8 +119,8 @@ impl LanguageModelImage {
                         image_size,
                     );
                     let resized_image = dynamic_image.resize(
-                        new_bounds.size.width.0 as u32,
-                        new_bounds.size.height.0 as u32,
+                        new_bounds.size.width.into(),
+                        new_bounds.size.height.into(),
                         image::imageops::FilterType::Triangle,
                     );
 

crates/markdown/examples/markdown_as_child.rs 🔗

@@ -97,7 +97,7 @@ impl Render for HelloWorld {
         div()
             .flex()
             .bg(rgb(0x2e7d32))
-            .size(Length::Definite(Pixels(700.0).into()))
+            .size(Length::Definite(px(700.0).into()))
             .justify_center()
             .items_center()
             .shadow_lg()

crates/outline/src/outline.rs 🔗

@@ -4,6 +4,7 @@ use std::{
     sync::Arc,
 };
 
+use editor::scroll::ScrollOffset;
 use editor::{Anchor, AnchorRangeExt, Editor, scroll::Autoscroll};
 use editor::{RowHighlightOptions, SelectionEffects};
 use fuzzy::StringMatch;
@@ -130,7 +131,7 @@ struct OutlineViewDelegate {
     active_editor: Entity<Editor>,
     outline: Outline<Anchor>,
     selected_match_index: usize,
-    prev_scroll_position: Option<Point<f32>>,
+    prev_scroll_position: Option<Point<ScrollOffset>>,
     matches: Vec<StringMatch>,
     last_query: String,
 }

crates/outline_panel/src/outline_panel.rs 🔗

@@ -1157,7 +1157,7 @@ impl OutlinePanel {
                         && multi_buffer_snapshot.as_singleton().is_none()
                         && !active_editor.read(cx).is_buffer_folded(buffer_id, cx)
                     {
-                        offset.y = -(active_editor.read(cx).file_header_size() as f32);
+                        offset.y = -(active_editor.read(cx).file_header_size() as f64);
                     }
 
                     active_editor.update(cx, |editor, cx| {

crates/proto/proto/call.proto 🔗

@@ -358,8 +358,10 @@ message UpdateView {
         repeated Selection selections = 3;
         optional Selection pending_selection = 4;
         EditorAnchor scroll_top_anchor = 5;
-        float scroll_x = 6;
-        float scroll_y = 7;
+        reserved 6;
+        reserved 7;
+        double scroll_x = 8;
+        double scroll_y = 9;
     }
 }
 
@@ -381,8 +383,10 @@ message View {
         repeated Selection selections = 4;
         optional Selection pending_selection = 5;
         EditorAnchor scroll_top_anchor = 6;
-        float scroll_x = 7;
-        float scroll_y = 8;
+        reserved 7;
+        reserved 8;
+        double scroll_x = 9;
+        double scroll_y = 10;
     }
 
     message ChannelView {

crates/repl/src/outputs/image.rs 🔗

@@ -3,7 +3,7 @@ use base64::{
     Engine as _, alphabet,
     engine::{DecodePaddingMode, GeneralPurpose, GeneralPurposeConfig},
 };
-use gpui::{App, ClipboardItem, Image, ImageFormat, Pixels, RenderImage, Window, img};
+use gpui::{App, ClipboardItem, Image, ImageFormat, RenderImage, Window, img};
 use std::sync::Arc;
 use ui::{IntoElement, Styled, div, prelude::*};
 
@@ -72,17 +72,17 @@ impl Render for ImageView {
     fn render(&mut self, window: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
         let line_height = window.line_height();
 
-        let (height, width) = if self.height as f32 / line_height.0 == u8::MAX as f32 {
-            let height = u8::MAX as f32 * line_height.0;
+        let (height, width) = if self.height as f32 / f32::from(line_height) == u8::MAX as f32 {
+            let height = u8::MAX as f32 * line_height;
             let width = self.width as f32 * height / self.height as f32;
             (height, width)
         } else {
-            (self.height as f32, self.width as f32)
+            (self.height.into(), self.width.into())
         };
 
         let image = self.image.clone();
 
-        div().h(Pixels(height)).w(Pixels(width)).child(img(image))
+        div().h(height).w(width).child(img(image))
     }
 }
 

crates/repl/src/outputs/plain.rs 🔗

@@ -273,7 +273,7 @@ impl Render for TerminalOutput {
         let cell_width = text_system
             .advance(font_id, font_pixels, 'w')
             .map(|advance| advance.width)
-            .unwrap_or(Pixels(0.0));
+            .unwrap_or(Pixels::ZERO);
 
         canvas(
             // prepaint

crates/search/src/project_search.rs 🔗

@@ -4047,7 +4047,7 @@ pub mod tests {
 
                     // Scroll results all the way down
                     results_editor.scroll(
-                        Point::new(0., f32::MAX),
+                        Point::new(0., f64::MAX),
                         Some(Axis::Vertical),
                         window,
                         cx,

crates/settings_profile_selector/src/settings_profile_selector.rs 🔗

@@ -332,7 +332,7 @@ mod tests {
 
         cx.update(|_, cx| {
             assert!(!cx.has_global::<ActiveSettingsProfileName>());
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 10.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(10.0));
         });
 
         (workspace, cx)
@@ -385,7 +385,7 @@ mod tests {
             assert_eq!(picker.delegate.selected_profile_name, None);
 
             assert_eq!(cx.try_global::<ActiveSettingsProfileName>(), None);
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 10.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(10.0));
         });
 
         cx.dispatch_action(Confirm);
@@ -411,14 +411,14 @@ mod tests {
                 Some(classroom_and_streaming_profile_name.clone())
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 20.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(20.0));
         });
 
         cx.dispatch_action(Cancel);
 
         cx.update(|_, cx| {
             assert_eq!(cx.try_global::<ActiveSettingsProfileName>(), None);
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 10.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(10.0));
         });
 
         cx.dispatch_action(settings_profile_selector::Toggle);
@@ -439,7 +439,7 @@ mod tests {
                 Some(classroom_and_streaming_profile_name.clone())
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 20.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(20.0));
         });
 
         cx.dispatch_action(SelectNext);
@@ -457,7 +457,7 @@ mod tests {
                 Some(demo_videos_profile_name.clone())
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 15.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(15.0));
         });
 
         cx.dispatch_action(Confirm);
@@ -468,7 +468,7 @@ mod tests {
                     .map(|p| p.0.clone()),
                 Some(demo_videos_profile_name.clone())
             );
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 15.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(15.0));
         });
 
         cx.dispatch_action(settings_profile_selector::Toggle);
@@ -486,7 +486,7 @@ mod tests {
                     .map(|p| p.0.clone()),
                 Some(demo_videos_profile_name.clone())
             );
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 15.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(15.0));
         });
 
         cx.dispatch_action(SelectPrevious);
@@ -504,7 +504,7 @@ mod tests {
                 Some(classroom_and_streaming_profile_name.clone())
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 20.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(20.0));
         });
 
         cx.dispatch_action(Cancel);
@@ -516,7 +516,7 @@ mod tests {
                 Some(demo_videos_profile_name.clone())
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 15.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(15.0));
         });
 
         cx.dispatch_action(settings_profile_selector::Toggle);
@@ -535,7 +535,7 @@ mod tests {
                 Some(demo_videos_profile_name)
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 15.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(15.0));
         });
 
         cx.dispatch_action(SelectPrevious);
@@ -553,7 +553,7 @@ mod tests {
                 Some(classroom_and_streaming_profile_name)
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 20.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(20.0));
         });
 
         cx.dispatch_action(SelectPrevious);
@@ -568,14 +568,14 @@ mod tests {
                 None
             );
 
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 10.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(10.0));
         });
 
         cx.dispatch_action(Confirm);
 
         cx.update(|_, cx| {
             assert_eq!(cx.try_global::<ActiveSettingsProfileName>(), None);
-            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx).0, 10.0);
+            assert_eq!(ThemeSettings::get_global(cx).buffer_font_size(cx), px(10.0));
         });
     }
 

crates/storybook/src/stories/with_rem_size.rs 🔗

@@ -54,7 +54,7 @@ impl RenderOnce for Example {
                 .p_2()
                 .border_2()
                 .border_color(self.border_color)
-                .child(Label::new(format!("1rem = {}px", self.rem_size.0)))
+                .child(Label::new(format!("1rem = {}px", f32::from(self.rem_size))))
                 .children(self.children),
         )
     }

crates/terminal_view/src/terminal_element.rs 🔗

@@ -809,12 +809,11 @@ impl Element for TerminalElement {
                 total_lines: _,
             } => {
                 let rem_size = window.rem_size();
-                let line_height = window.text_style().font_size.to_pixels(rem_size)
+                let line_height = f32::from(window.text_style().font_size.to_pixels(rem_size))
                     * TerminalSettings::get_global(cx)
                         .line_height
                         .value()
-                        .to_pixels(rem_size)
-                        .0;
+                        .to_pixels(rem_size);
                 (displayed_lines * line_height).into()
             }
             ContentMode::Scrollable => {
@@ -939,7 +938,7 @@ impl Element for TerminalElement {
                     let rem_size = window.rem_size();
                     let font_pixels = text_style.font_size.to_pixels(rem_size);
                     // TODO: line_height should be an f32 not an AbsoluteLength.
-                    let line_height = font_pixels * line_height.to_pixels(rem_size).0;
+                    let line_height = f32::from(font_pixels) * line_height.to_pixels(rem_size);
                     let font_id = cx.text_system().resolve_font(&text_style.font());
 
                     let cell_width = text_system

crates/terminal_view/src/terminal_scrollbar.rs 🔗

@@ -62,14 +62,14 @@ impl ScrollableHandle for TerminalScrollHandle {
         let state = self.state.borrow();
         let scroll_offset = state.total_lines - state.viewport_lines - state.display_offset;
         Point::new(
-            px(0.),
-            -px(scroll_offset as f32 * self.state.borrow().line_height.0),
+            Pixels::ZERO,
+            -(scroll_offset as f32 * self.state.borrow().line_height),
         )
     }
 
     fn set_offset(&self, point: Point<Pixels>) {
         let state = self.state.borrow();
-        let offset_delta = (point.y.0 / state.line_height.0).round() as i32;
+        let offset_delta = (point.y / state.line_height).round() as i32;
 
         let max_offset = state.total_lines - state.viewport_lines;
         let display_offset = (max_offset as i32 + offset_delta).clamp(0, max_offset as i32);
@@ -83,8 +83,8 @@ impl ScrollableHandle for TerminalScrollHandle {
         Bounds::new(
             Point::new(px(0.), px(0.)),
             size(
-                px(0.),
-                px(state.viewport_lines as f32 * state.line_height.0),
+                Pixels::ZERO,
+                state.viewport_lines as f32 * state.line_height,
             ),
         )
     }

crates/text/src/selection.rs 🔗

@@ -5,8 +5,8 @@ use std::ops::Range;
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum SelectionGoal {
     None,
-    HorizontalPosition(f32),
-    HorizontalRange { start: f32, end: f32 },
+    HorizontalPosition(f64),
+    HorizontalRange { start: f64, end: f64 },
     WrappedHorizontalPosition((u32, f32)),
 }
 

crates/title_bar/src/collab.rs 🔗

@@ -118,7 +118,7 @@ fn render_color_ribbon(color: Hsla) -> impl Element {
         move |bounds, _, window, _| {
             let height = bounds.size.height;
             let horizontal_offset = height;
-            let vertical_offset = px(height.0 / 2.0);
+            let vertical_offset = height / 2.0;
             let mut path = Path::new(bounds.bottom_left());
             path.curve_to(
                 bounds.origin + point(horizontal_offset, vertical_offset),

crates/ui/src/components/keybinding_hint.rs 🔗

@@ -249,7 +249,7 @@ impl RenderOnce for KeybindingHint {
                         blur_radius: px(0.),
                         spread_radius: px(0.),
                     }])
-                    .child(self.keybinding.size(rems_from_px(kb_size.0))),
+                    .child(self.keybinding.size(rems_from_px(kb_size))),
             )
             .children(self.suffix)
     }

crates/ui/src/components/list/list_bullet_item.rs 🔗

@@ -16,7 +16,7 @@ impl ListBulletItem {
 
 impl RenderOnce for ListBulletItem {
     fn render(self, window: &mut Window, _cx: &mut App) -> impl IntoElement {
-        let line_height = 0.85 * window.line_height();
+        let line_height = window.line_height() * 0.85;
 
         ListItem::new("list-item")
             .selectable(false)

crates/ui/src/styles/typography.rs 🔗

@@ -140,8 +140,8 @@ impl TextSize {
             Self::Default => rems_from_px(14.),
             Self::Small => rems_from_px(12.),
             Self::XSmall => rems_from_px(10.),
-            Self::Ui => rems_from_px(theme_settings.ui_font_size(cx).into()),
-            Self::Editor => rems_from_px(theme_settings.buffer_font_size(cx).into()),
+            Self::Ui => rems_from_px(theme_settings.ui_font_size(cx)),
+            Self::Editor => rems_from_px(theme_settings.buffer_font_size(cx)),
         }
     }
 }

crates/ui/src/styles/units.rs 🔗

@@ -10,8 +10,8 @@ pub const BASE_REM_SIZE_IN_PX: f32 = 16.;
 ///
 /// For instance, instead of writing `rems(0.875)` you can write `rems_from_px(14.)`
 #[inline(always)]
-pub fn rems_from_px(px: f32) -> Rems {
-    rems(px / BASE_REM_SIZE_IN_PX)
+pub fn rems_from_px(px: impl Into<f32>) -> Rems {
+    rems(px.into() / BASE_REM_SIZE_IN_PX)
 }
 
 /// Returns a [`Length`] corresponding to the specified percentage of the viewport's width.

crates/ui/src/utils/search_input.rs 🔗

@@ -1,20 +1,20 @@
-use gpui::Pixels;
+use gpui::{Pixels, px};
 
 pub struct SearchInputWidth;
 
 impl SearchInputWidth {
     /// The container size in which the input stops filling the whole width.
-    pub const THRESHOLD_WIDTH: f32 = 1200.0;
+    pub const THRESHOLD_WIDTH: Pixels = px(1200.0);
 
     /// The maximum width for the search input when the container is larger than the threshold.
-    pub const MAX_WIDTH: f32 = 1200.0;
+    pub const MAX_WIDTH: Pixels = px(1200.0);
 
     /// Calculates the actual width in pixels based on the container width.
     pub fn calc_width(container_width: Pixels) -> Pixels {
-        if container_width.0 < Self::THRESHOLD_WIDTH {
+        if container_width < Self::THRESHOLD_WIDTH {
             container_width
         } else {
-            Pixels(container_width.0.min(Self::MAX_WIDTH))
+            container_width.min(Self::MAX_WIDTH)
         }
     }
 }

crates/vim/src/motion.rs 🔗

@@ -1573,12 +1573,12 @@ fn up_down_buffer_rows(
 
     let (goal_wrap, goal_x) = match goal {
         SelectionGoal::WrappedHorizontalPosition((row, x)) => (row, x),
-        SelectionGoal::HorizontalRange { end, .. } => (select_nth_wrapped_row, end),
-        SelectionGoal::HorizontalPosition(x) => (select_nth_wrapped_row, x),
+        SelectionGoal::HorizontalRange { end, .. } => (select_nth_wrapped_row, end as f32),
+        SelectionGoal::HorizontalPosition(x) => (select_nth_wrapped_row, x as f32),
         _ => {
             let x = map.x_for_display_point(point, text_layout_details);
-            goal = SelectionGoal::WrappedHorizontalPosition((select_nth_wrapped_row, x.0));
-            (select_nth_wrapped_row, x.0)
+            goal = SelectionGoal::WrappedHorizontalPosition((select_nth_wrapped_row, x.into()));
+            (select_nth_wrapped_row, x.into())
         }
     };
 

crates/vim/src/normal/scroll.rs 🔗

@@ -121,9 +121,9 @@ fn scroll_editor(
     let amount = match (amount.is_full_page(), editor.visible_line_count()) {
         (true, Some(visible_line_count)) => {
             if amount.direction().is_upwards() {
-                ScrollAmount::Line(amount.lines(visible_line_count) + 1.0)
+                ScrollAmount::Line((amount.lines(visible_line_count) + 1.0) as f32)
             } else {
-                ScrollAmount::Line(amount.lines(visible_line_count) - 1.0)
+                ScrollAmount::Line((amount.lines(visible_line_count) - 1.0) as f32)
             }
         }
         _ => amount,
@@ -308,7 +308,7 @@ mod test {
         let window = cx.window;
         let margin = cx
             .update_window(window, |_, window, _cx| {
-                window.viewport_size().height - line_height * visible_line_count
+                window.viewport_size().height - line_height * visible_line_count as f32
             })
             .unwrap();
         cx.simulate_window_resize(

crates/vim/src/test/neovim_backed_test_context.rs 🔗

@@ -277,7 +277,7 @@ impl NeovimBackedTestContext {
         let window = self.window;
         let margin = self
             .update_window(window, |_, window, _cx| {
-                window.viewport_size().height - line_height * visible_line_count
+                window.viewport_size().height - line_height * (visible_line_count as f32)
             })
             .unwrap();
 

crates/vim/src/visual.rs 🔗

@@ -314,7 +314,7 @@ impl Vim {
             let (start, end) = match s.newest_anchor().goal {
                 SelectionGoal::HorizontalRange { start, end } if preserve_goal => (start, end),
                 SelectionGoal::HorizontalPosition(start) if preserve_goal => (start, start),
-                _ => (tail_x.0, head_x.0),
+                _ => (tail_x.into(), head_x.into()),
             };
             let mut goal = SelectionGoal::HorizontalRange { start, end };
 
@@ -359,8 +359,8 @@ impl Vim {
 
             if !preserve_goal {
                 goal = SelectionGoal::HorizontalRange {
-                    start: positions.start.0,
-                    end: positions.end.0,
+                    start: f64::from(positions.start),
+                    end: f64::from(positions.end),
                 };
             }
 

crates/workspace/src/dock.rs 🔗

@@ -14,7 +14,7 @@ use std::sync::Arc;
 use ui::{ContextMenu, Divider, DividerColor, IconButton, Tooltip, h_flex};
 use ui::{prelude::*, right_click_menu};
 
-pub(crate) const RESIZE_HANDLE_SIZE: Pixels = Pixels(6.);
+pub(crate) const RESIZE_HANDLE_SIZE: Pixels = px(6.);
 
 pub enum PanelEvent {
     ZoomIn,
@@ -732,7 +732,7 @@ impl Dock {
     }
 
     pub fn clamp_panel_size(&mut self, max_size: Pixels, window: &mut Window, cx: &mut App) {
-        let max_size = px((max_size.0 - RESIZE_HANDLE_SIZE.0).abs());
+        let max_size = (max_size - RESIZE_HANDLE_SIZE).abs();
         for panel in self.panel_entries.iter().map(|entry| &entry.panel) {
             if panel.size(window, cx) > max_size {
                 panel.set_size(Some(max_size.max(RESIZE_HANDLE_SIZE)), window, cx);

crates/workspace/src/pane_group.rs 🔗

@@ -1259,11 +1259,11 @@ mod element {
                         origin: child
                             .bounds
                             .origin
-                            .apply_along(Axis::Horizontal, |val| val + Pixels(1.)),
+                            .apply_along(Axis::Horizontal, |val| val + px(1.)),
                         size: child
                             .bounds
                             .size
-                            .apply_along(Axis::Horizontal, |val| val - Pixels(1.)),
+                            .apply_along(Axis::Horizontal, |val| val - px(1.)),
                     };
 
                     if overlay_opacity.is_some()

crates/workspace/src/persistence.rs 🔗

@@ -252,7 +252,7 @@ impl sqlez::bindable::Bind for SerializedPixels {
         statement: &sqlez::statement::Statement,
         start_index: i32,
     ) -> anyhow::Result<i32> {
-        let this: i32 = self.0.0 as i32;
+        let this: i32 = u32::from(self.0) as _;
         this.bind(statement, start_index)
     }
 }

crates/workspace/src/workspace.rs 🔗

@@ -5989,7 +5989,7 @@ impl Workspace {
         self.left_dock.read_with(cx, |left_dock, cx| {
             let left_dock_size = left_dock
                 .active_panel_size(window, cx)
-                .unwrap_or(Pixels(0.0));
+                .unwrap_or(Pixels::ZERO);
             if left_dock_size + size > self.bounds.right() {
                 size = self.bounds.right() - left_dock_size
             }

crates/zed/src/zed.rs 🔗

@@ -746,7 +746,7 @@ fn register_actions(
                         let _ = settings
                             .theme
                             .ui_font_size
-                            .insert(theme::clamp_font_size(ui_font_size).0);
+                            .insert(theme::clamp_font_size(ui_font_size).into());
                     });
                 } else {
                     theme::adjust_ui_font_size(cx, |size| size + px(1.0));
@@ -762,7 +762,7 @@ fn register_actions(
                         let _ = settings
                             .theme
                             .ui_font_size
-                            .insert(theme::clamp_font_size(ui_font_size).0);
+                            .insert(theme::clamp_font_size(ui_font_size).into());
                     });
                 } else {
                     theme::adjust_ui_font_size(cx, |size| size - px(1.0));
@@ -791,7 +791,7 @@ fn register_actions(
                         let _ = settings
                             .theme
                             .buffer_font_size
-                            .insert(theme::clamp_font_size(buffer_font_size).0);
+                            .insert(theme::clamp_font_size(buffer_font_size).into());
                     });
                 } else {
                     theme::adjust_buffer_font_size(cx, |size| size + px(1.0));
@@ -808,7 +808,7 @@ fn register_actions(
                         let _ = settings
                             .theme
                             .buffer_font_size
-                            .insert(theme::clamp_font_size(buffer_font_size).0);
+                            .insert(theme::clamp_font_size(buffer_font_size).into());
                     });
                 } else {
                     theme::adjust_buffer_font_size(cx, |size| size - px(1.0));
@@ -3877,7 +3877,7 @@ mod tests {
         fn active_location(
             workspace: &WindowHandle<Workspace>,
             cx: &mut TestAppContext,
-        ) -> (ProjectPath, DisplayPoint, f32) {
+        ) -> (ProjectPath, DisplayPoint, f64) {
             workspace
                 .update(cx, |workspace, _, cx| {
                     let item = workspace.active_item(cx).unwrap();