@@ -18,7 +18,7 @@ use ruff_text_size::TextSize;
1818use crate :: cell:: CellOffsets ;
1919use crate :: index:: NotebookIndex ;
2020use crate :: schema:: { Cell , RawNotebook , SortAlphabetically , SourceValue } ;
21- use crate :: { CellMetadata , RawNotebookMetadata , schema} ;
21+ use crate :: { CellMetadata , CellStart , RawNotebookMetadata , schema} ;
2222
2323/// Run round-trip source code generation on a given Jupyter notebook file path.
2424pub fn round_trip ( path : & Path ) -> anyhow:: Result < String > {
@@ -317,14 +317,22 @@ impl Notebook {
317317 /// of lines visible in the UI is three. The same goes for [`SourceValue::String`]
318318 /// where we need to check for the trailing newline.
319319 ///
320- /// The index building is expensive as it needs to go through the content of
321- /// every valid code cell .
320+ /// The index building is now much more efficient, storing only cell start
321+ /// positions rather than per-row mappings .
322322 fn build_index ( & self ) -> NotebookIndex {
323- let mut row_to_cell = Vec :: new ( ) ;
324- let mut row_to_row_in_cell = Vec :: new ( ) ;
323+ let mut cell_starts = Vec :: with_capacity ( self . valid_code_cells . len ( ) ) ;
324+
325+ let mut current_row = OneIndexed :: MIN ;
325326
326327 for & cell_index in & self . valid_code_cells {
327- let line_count = match & self . raw . cells [ cell_index as usize ] . source ( ) {
328+ let raw_cell_index = cell_index as usize ;
329+ // Record the starting row of this cell
330+ cell_starts. push ( CellStart {
331+ start_row : current_row,
332+ raw_cell_index : OneIndexed :: from_zero_indexed ( raw_cell_index) ,
333+ } ) ;
334+
335+ let line_count = match & self . raw . cells [ raw_cell_index] . source ( ) {
328336 SourceValue :: String ( string) => {
329337 if string. is_empty ( ) {
330338 1
@@ -342,17 +350,11 @@ impl Notebook {
342350 }
343351 }
344352 } ;
345- row_to_cell. extend ( std:: iter:: repeat_n (
346- OneIndexed :: from_zero_indexed ( cell_index as usize ) ,
347- line_count,
348- ) ) ;
349- row_to_row_in_cell. extend ( ( 0 ..line_count) . map ( OneIndexed :: from_zero_indexed) ) ;
350- }
351353
352- NotebookIndex {
353- row_to_cell,
354- row_to_row_in_cell,
354+ current_row = current_row. saturating_add ( line_count) ;
355355 }
356+
357+ NotebookIndex { cell_starts }
356358 }
357359
358360 /// Return the notebook content.
@@ -456,7 +458,7 @@ mod tests {
456458
457459 use ruff_source_file:: OneIndexed ;
458460
459- use crate :: { Cell , Notebook , NotebookError , NotebookIndex } ;
461+ use crate :: { Cell , CellStart , Notebook , NotebookError , NotebookIndex } ;
460462
461463 /// Construct a path to a Jupyter notebook in the `resources/test/fixtures/jupyter` directory.
462464 fn notebook_path ( path : impl AsRef < Path > ) -> std:: path:: PathBuf {
@@ -548,39 +550,27 @@ print("after empty cells")
548550 assert_eq ! (
549551 notebook. index( ) ,
550552 & NotebookIndex {
551- row_to_cell: vec![
552- OneIndexed :: from_zero_indexed( 0 ) ,
553- OneIndexed :: from_zero_indexed( 0 ) ,
554- OneIndexed :: from_zero_indexed( 0 ) ,
555- OneIndexed :: from_zero_indexed( 0 ) ,
556- OneIndexed :: from_zero_indexed( 0 ) ,
557- OneIndexed :: from_zero_indexed( 0 ) ,
558- OneIndexed :: from_zero_indexed( 2 ) ,
559- OneIndexed :: from_zero_indexed( 2 ) ,
560- OneIndexed :: from_zero_indexed( 2 ) ,
561- OneIndexed :: from_zero_indexed( 2 ) ,
562- OneIndexed :: from_zero_indexed( 2 ) ,
563- OneIndexed :: from_zero_indexed( 4 ) ,
564- OneIndexed :: from_zero_indexed( 6 ) ,
565- OneIndexed :: from_zero_indexed( 6 ) ,
566- OneIndexed :: from_zero_indexed( 7 )
567- ] ,
568- row_to_row_in_cell: vec![
569- OneIndexed :: from_zero_indexed( 0 ) ,
570- OneIndexed :: from_zero_indexed( 1 ) ,
571- OneIndexed :: from_zero_indexed( 2 ) ,
572- OneIndexed :: from_zero_indexed( 3 ) ,
573- OneIndexed :: from_zero_indexed( 4 ) ,
574- OneIndexed :: from_zero_indexed( 5 ) ,
575- OneIndexed :: from_zero_indexed( 0 ) ,
576- OneIndexed :: from_zero_indexed( 1 ) ,
577- OneIndexed :: from_zero_indexed( 2 ) ,
578- OneIndexed :: from_zero_indexed( 3 ) ,
579- OneIndexed :: from_zero_indexed( 4 ) ,
580- OneIndexed :: from_zero_indexed( 0 ) ,
581- OneIndexed :: from_zero_indexed( 0 ) ,
582- OneIndexed :: from_zero_indexed( 1 ) ,
583- OneIndexed :: from_zero_indexed( 0 )
553+ cell_starts: vec![
554+ CellStart {
555+ start_row: OneIndexed :: MIN ,
556+ raw_cell_index: OneIndexed :: MIN
557+ } ,
558+ CellStart {
559+ start_row: OneIndexed :: from_zero_indexed( 6 ) ,
560+ raw_cell_index: OneIndexed :: from_zero_indexed( 2 )
561+ } ,
562+ CellStart {
563+ start_row: OneIndexed :: from_zero_indexed( 11 ) ,
564+ raw_cell_index: OneIndexed :: from_zero_indexed( 4 )
565+ } ,
566+ CellStart {
567+ start_row: OneIndexed :: from_zero_indexed( 12 ) ,
568+ raw_cell_index: OneIndexed :: from_zero_indexed( 6 )
569+ } ,
570+ CellStart {
571+ start_row: OneIndexed :: from_zero_indexed( 14 ) ,
572+ raw_cell_index: OneIndexed :: from_zero_indexed( 7 )
573+ }
584574 ] ,
585575 }
586576 ) ;
0 commit comments