editor: Prevent panics in `BlockChunks` if the block spans more than 128 lines (#38763)

Lukas Wirth created

Not an ideal fix, but a proper one will require restructuring the
iterator state (which would be easier if Rust had first class
generators)
Fixes ZED-1MB

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/editor/src/display_map/block_map.rs | 10 ++++++----
crates/editor/src/display_map/tab_map.rs   |  4 ++--
2 files changed, 8 insertions(+), 6 deletions(-)

Detailed changes

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

@@ -26,7 +26,7 @@ use sum_tree::{Bias, Dimensions, SumTree, Summary, TreeMap};
 use text::{BufferId, Edit};
 use ui::ElementId;
 
-const NEWLINES: &[u8] = &[b'\n'; u8::MAX as usize];
+const NEWLINES: &[u8] = &[b'\n'; u128::BITS as usize];
 const BULLETS: &str = "********************************************************************************************************************************";
 
 /// Tracks custom blocks such as diagnostics that should be displayed within buffer.
@@ -1726,12 +1726,13 @@ impl<'a> Iterator for BlockChunks<'a> {
 
             let start_in_block = self.output_row - block_start;
             let end_in_block = cmp::min(self.max_output_row, block_end) - block_start;
-            let line_count = end_in_block - start_in_block;
+            // todo: We need to split the chunk here?
+            let line_count = cmp::min(end_in_block - start_in_block, u128::BITS);
             self.output_row += line_count;
 
             return Some(Chunk {
                 text: unsafe { std::str::from_utf8_unchecked(&NEWLINES[..line_count as usize]) },
-                chars: (1 << line_count) - 1,
+                chars: 1u128.unbounded_shl(line_count) - 1,
                 ..Default::default()
             });
         }
@@ -1746,6 +1747,7 @@ impl<'a> Iterator for BlockChunks<'a> {
                     if self.transforms.item().is_some() {
                         return Some(Chunk {
                             text: "\n",
+                            chars: 1,
                             ..Default::default()
                         });
                     }
@@ -1773,7 +1775,7 @@ impl<'a> Iterator for BlockChunks<'a> {
             let chars_count = prefix.chars().count();
             let bullet_len = chars_count;
             prefix = &BULLETS[..bullet_len];
-            chars = (1 << bullet_len) - 1;
+            chars = 1u128.unbounded_shl(bullet_len as u32) - 1;
             tabs = 0;
         }
 

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

@@ -551,7 +551,7 @@ impl TabChunks<'_> {
         self.chunk = Chunk {
             text: &SPACES[0..(to_next_stop as usize)],
             is_tab: true,
-            chars: (1u128 << to_next_stop) - 1,
+            chars: 1u128.unbounded_shl(to_next_stop) - 1,
             ..Default::default()
         };
         self.inside_leading_tab = to_next_stop > 0;
@@ -623,7 +623,7 @@ impl<'a> Iterator for TabChunks<'a> {
                         return Some(Chunk {
                             text: &SPACES[..len as usize],
                             is_tab: true,
-                            chars: (1 << len) - 1,
+                            chars: 1u128.unbounded_shl(len) - 1,
                             tabs: 0,
                             ..self.chunk.clone()
                         });