@@ -13,6 +13,7 @@ import {
1313import { Context } from '@jupyterlab/docregistry' ;
1414import { NotebookModel } from '@jupyterlab/notebook' ;
1515import * as nbformat from '@jupyterlab/nbformat' ;
16+ import { NotebookCommandIds } from './NotebookCommands' ;
1617
1718export class Notebook2Adapter {
1819 private _commands : CommandRegistry ;
@@ -198,6 +199,209 @@ export class Notebook2Adapter {
198199 NotebookActions . redo ( notebook ) ;
199200 }
200201
202+ /**
203+ * Set the active cell by index.
204+ *
205+ * @param index - The index of the cell to activate (0-based)
206+ *
207+ * @remarks
208+ * This method programmatically selects a cell at the specified index.
209+ * If the index is out of bounds, the operation has no effect.
210+ */
211+ setActiveCell ( index : number ) : void {
212+ const notebook = this . _notebook ;
213+ const cellCount = notebook . model ?. cells . length ?? 0 ;
214+
215+ if ( index >= 0 && index < cellCount ) {
216+ notebook . activeCellIndex = index ;
217+ }
218+ }
219+
220+ /**
221+ * Get all cells from the notebook.
222+ *
223+ * @returns Array of cell data including type, source, and outputs
224+ *
225+ * @remarks
226+ * This method extracts cell information from the notebook model.
227+ * For code cells, outputs are included. Returns an empty array if
228+ * the notebook model is not available.
229+ */
230+ getCells ( ) : Array < {
231+ type : nbformat . CellType ;
232+ source : string ;
233+ outputs ?: unknown [ ] ;
234+ } > {
235+ const cells = this . _notebook . model ?. cells ;
236+ if ( ! cells ) {
237+ return [ ] ;
238+ }
239+
240+ const result : Array < {
241+ type : nbformat . CellType ;
242+ source : string ;
243+ outputs ?: unknown [ ] ;
244+ } > = [ ] ;
245+
246+ for ( let i = 0 ; i < cells . length ; i ++ ) {
247+ const cell = cells . get ( i ) ;
248+ if ( cell ) {
249+ result . push ( {
250+ type : cell . type as nbformat . CellType ,
251+ source : cell . sharedModel . getSource ( ) ,
252+ outputs :
253+ cell . type === 'code' ? ( cell as any ) . outputs ?. toJSON ( ) : undefined ,
254+ } ) ;
255+ }
256+ }
257+
258+ return result ;
259+ }
260+
261+ /**
262+ * Get the total number of cells in the notebook.
263+ *
264+ * @returns The number of cells, or 0 if the notebook model is not available
265+ */
266+ getCellCount ( ) : number {
267+ return this . _notebook . model ?. cells . length ?? 0 ;
268+ }
269+
270+ /**
271+ * Insert a new cell at a specific index.
272+ *
273+ * @param cellIndex - The index where the cell should be inserted (0-based)
274+ * @param source - Optional source code/text for the new cell
275+ *
276+ * @remarks
277+ * This method inserts a cell at the specified position by:
278+ * 1. Setting the active cell to cellIndex
279+ * 2. Calling insertAbove to insert before that cell
280+ *
281+ * Note: The cell type is determined by _defaultCellType, which should be set
282+ * before calling this method (typically done by the store layer).
283+ */
284+ insertAt ( cellIndex : number , source ?: string ) : void {
285+ const cellCount = this . getCellCount ( ) ;
286+
287+ console . log ( '[Notebook2Adapter.insertAt] BEFORE:' , {
288+ cellIndex,
289+ sourceLength : source ?. length || 0 ,
290+ sourcePreview : source ?. substring ( 0 , 50 ) ,
291+ currentActiveCell : this . _notebook . activeCellIndex ,
292+ cellCount,
293+ defaultCellType : this . _defaultCellType ,
294+ } ) ;
295+
296+ // If index is beyond cell count, insert at the end
297+ if ( cellIndex >= cellCount ) {
298+ console . log (
299+ '[Notebook2Adapter.insertAt] Index beyond cell count, inserting at end'
300+ ) ;
301+ this . insertBelow ( source ) ;
302+ return ;
303+ }
304+
305+ this . setActiveCell ( cellIndex ) ;
306+
307+ console . log ( '[Notebook2Adapter.insertAt] AFTER setActiveCell:' , {
308+ newActiveCell : this . _notebook . activeCellIndex ,
309+ } ) ;
310+
311+ this . insertAbove ( source ) ;
312+
313+ console . log ( '[Notebook2Adapter.insertAt] AFTER insertAbove:' , {
314+ cellCount : this . getCellCount ( ) ,
315+ newActiveCell : this . _notebook . activeCellIndex ,
316+ } ) ;
317+ }
318+
319+ /**
320+ * NEW ALIGNED TOOL METHODS
321+ * These methods align 1:1 with tool operation names for seamless integration
322+ */
323+
324+ /**
325+ * Insert a cell at a specific index (aligned with insertCell tool).
326+ *
327+ * @param cellType - Type of cell to insert (code, markdown, or raw)
328+ * @param cellIndex - Index where to insert (0-based). Use large number for end.
329+ * @param source - Optional source code/text for the cell
330+ */
331+ insertCell (
332+ cellType : nbformat . CellType ,
333+ cellIndex : number ,
334+ source ?: string
335+ ) : void {
336+ this . setDefaultCellType ( cellType ) ;
337+ this . insertAt ( cellIndex , source ) ;
338+ }
339+
340+ /**
341+ * Delete the currently active cell (aligned with deleteCell tool).
342+ */
343+ deleteCell ( ) : void {
344+ this . deleteCells ( ) ;
345+ }
346+
347+ /**
348+ * Update a cell's content and/or type (aligned with updateCell tool).
349+ *
350+ * @param cellType - New cell type
351+ * @param source - New source content (optional)
352+ */
353+ updateCell ( cellType : nbformat . CellType , source ?: string ) : void {
354+ if ( source !== undefined && this . _notebook . activeCell ) {
355+ this . _notebook . activeCell . model . sharedModel . setSource ( source ) ;
356+ }
357+ this . changeCellType ( cellType ) ;
358+ }
359+
360+ /**
361+ * Get a cell's content by index or active cell (aligned with getCell tool).
362+ *
363+ * @param index - Optional cell index (0-based). If not provided, returns active cell.
364+ * @returns Cell data or undefined if not found
365+ */
366+ getCell (
367+ index ?: number
368+ ) :
369+ | { type : nbformat . CellType ; source : string ; outputs ?: unknown [ ] }
370+ | undefined {
371+ if ( index !== undefined ) {
372+ // Get cell at specific index
373+ const cells = this . getCells ( ) ;
374+ return cells [ index ] ;
375+ } else {
376+ // Get active cell
377+ const activeCell = this . _notebook . activeCell ;
378+ if ( ! activeCell ) return undefined ;
379+
380+ return {
381+ type : activeCell . model . type ,
382+ source : activeCell . model . sharedModel . getSource ( ) ,
383+ outputs :
384+ activeCell . model . type === 'code'
385+ ? ( activeCell . model as any ) . outputs ?. toJSON ( )
386+ : undefined ,
387+ } ;
388+ }
389+ }
390+
391+ /**
392+ * Run the active cell (aligned with runCell tool).
393+ */
394+ runCell ( ) : void {
395+ this . _commands . execute ( NotebookCommandIds . run ) ;
396+ }
397+
398+ /**
399+ * Run all cells in the notebook (aligned with runAllCells tool).
400+ */
401+ runAllCells ( ) : void {
402+ this . _commands . execute ( NotebookCommandIds . runAll ) ;
403+ }
404+
201405 /**
202406 * Dispose of the adapter.
203407 */
0 commit comments