@@ -260,7 +260,19 @@ class RunPreviousCellCommand extends RunCommand implements Command {
260260 }
261261}
262262
263+ // More permissive type than `Position` so its easier to construct via a literal
264+ type LineAndCharPos = { line : number , character : number }
265+ // More permissive type than `Range` so its easier to construct via a literal
266+ type LineAndCharRange = { start : LineAndCharPos , end : LineAndCharPos }
267+
268+ function extractRangeFromCode ( code : string , range : LineAndCharRange ) : string {
269+ const extractedRange = lines ( code ) . slice ( range . start . line , range . end . line + 1 )
270+ extractedRange [ 0 ] = extractedRange [ 0 ] . slice ( range . start . character )
271+ extractedRange [ extractedRange . length - 1 ] = extractedRange [ extractedRange . length - 1 ] . slice ( 0 , range . end . character )
272+ return extractedRange . join ( '\n' )
273+ }
263274
275+ // Run the code at the cursor
264276class RunCurrentCommand extends RunCommand implements Command {
265277 constructor (
266278 host : ExtensionHost ,
@@ -337,95 +349,85 @@ class RunCurrentCommand extends RunCommand implements Command {
337349 context : CodeViewActiveBlockContext
338350 ) : Promise < void > {
339351 // get selection and active block
340- let selection = context . selectedText ;
352+ const selection = context . selectedText ;
341353 const activeBlock = context . blocks . find ( block => block . active ) ;
342354
343- // idea: first check that we are in Positron
344- // and leave the others untouched
345-
346- // if the selection is empty and this isn't a knitr document then it resolves to run cell
347- if ( false ) {
348- if ( activeBlock ) {
349- const executor = await this . cellExecutorForLanguage ( activeBlock . language , editor . document , this . engine_ ) ;
350- if ( executor ) {
351- await executeInteractive ( executor , [ activeBlock . code ] , editor . document ) ;
352- await activateIfRequired ( editor ) ;
353- }
355+ const exec = async ( action : CodeViewSelectionAction , selection : string ) => {
356+ const executor = await this . cellExecutorForLanguage ( context . activeLanguage , editor . document , this . engine_ ) ;
357+ if ( executor ) {
358+ await executeInteractive ( executor , [ selection ] , editor . document ) ;
359+ await editor . setBlockSelection ( context , action ) ;
354360 }
355- } else {
356- let action : CodeViewSelectionAction | undefined ;
361+ }
357362
358- // if the selection is empty and we are in Positron:
359- // try to get the statement's range and use that as the selection
360- if ( selection . length <= 0 && activeBlock && hasHooks ( ) ) {
363+ // if in Positron
364+ if ( hasHooks ( ) ) {
365+ if ( activeBlock && selection . length <= 0 ) {
361366 const codeLines = lines ( activeBlock . code )
362367 const vdoc = virtualDocForCode ( codeLines , embeddedLanguage ( activeBlock . language ) ! ) ;
363368 if ( vdoc ) {
364369 const parentUri = Uri . file ( editor . document . fileName ) ;
365370 const injectedLines = ( vdoc . language ?. inject ?. length ?? 0 )
366371
367- const positionIntoVdoc = ( p : { line : number , character : number } ) =>
372+ const positionIntoVdoc = ( p : LineAndCharPos ) =>
368373 new Position ( p . line + injectedLines , p . character )
369- const positionOutOfVdoc = ( p : { line : number , character : number } ) =>
374+ const positionOutOfVdoc = ( p : LineAndCharPos ) =>
370375 new Position ( p . line - injectedLines , p . character )
371-
372- const result = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
373- return await commands . executeCommand < StatementRange > (
374- "vscode.executeStatementRangeProvider" ,
375- uri ,
376- positionIntoVdoc ( context . selection . start )
377- ) ;
378- } ) ;
379- const { range, code } = result
380- if ( code === undefined ) return
381- const adjustedEnd = positionOutOfVdoc ( range . end )
382-
383- selection = code
384- action = "nextline" ;
385-
386- // BEGIN ref: https://github.com/posit-dev/positron/blob/main/src/vs/workbench/contrib/positronConsole/browser/positronConsoleActions.ts#L428
387- // strategy from Positron using `StatementRangeProvider` to find range of next statement
388- // and move cursor based on that.
389- if ( adjustedEnd . line + 1 <= codeLines . length ) {
390- const nextStatementRange = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
376+ const rangeOutOfVdoc = ( r : Range ) : LineAndCharRange => ( {
377+ start : positionOutOfVdoc ( r . start ) ,
378+ end : positionOutOfVdoc ( r . end )
379+ } )
380+ const getStatementRange = async ( pos : LineAndCharPos ) => {
381+ const result = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
391382 return await commands . executeCommand < StatementRange > (
392383 "vscode.executeStatementRangeProvider" ,
393384 uri ,
394- positionIntoVdoc ( new Position ( adjustedEnd . line + 1 , 1 ) ) // look for statement at line after current statement
385+ positionIntoVdoc ( pos )
395386 ) ;
396387 } ) ;
397- const nextStatement = {
398- start : positionOutOfVdoc ( nextStatementRange . range . start ) ,
399- end : positionOutOfVdoc ( nextStatementRange . range . end )
400- } ;
401- if ( nextStatement . start . line > adjustedEnd . line ) {
402- action = nextStatement . start
403- // the nextStatement may start before & end after the current statement if e.g. inside a function:
404- } else if ( nextStatement . end . line > adjustedEnd . line ) {
405- action = nextStatement . end
388+ return rangeOutOfVdoc ( result . range )
389+ }
390+
391+ const range = await getStatementRange ( context . selection . start )
392+ const code = extractRangeFromCode ( activeBlock . code , range )
393+
394+ // BEGIN ref: https://github.com/posit-dev/positron/blob/main/src/vs/workbench/contrib/positronConsole/browser/positronConsoleActions.ts#L428
395+ // strategy from Positron using `StatementRangeProvider` to find range of next statement
396+ // and move cursor based on that.
397+ if ( range . end . line + 1 <= codeLines . length ) {
398+ // get range of statement at line after current statement)
399+ const nextRange = await getStatementRange ( new Position ( range . end . line + 1 , 1 ) )
400+
401+ if ( nextRange . start . line > range . end . line ) {
402+ exec ( nextRange . start , code )
403+ // the next statement range may start before & end after the current statement if e.g. inside a function:
404+ } else if ( nextRange . end . line > range . end . line ) {
405+ exec ( nextRange . end , code )
406+ } else {
407+ exec ( "nextline" , code )
406408 }
409+ } else {
410+ exec ( "nextline" , code )
407411 }
408412 // END ref.
409413 }
410414 }
411-
412- // if the selection is still empty:
413- // take the whole line as the selection
414- if ( selection . length <= 0 && activeBlock ) {
415- selection = lines ( activeBlock . code ) [ context . selection . start . line ] ;
416- action = "nextline" ;
417- }
418-
419- // run code
420- const executor = await this . cellExecutorForLanguage ( context . activeLanguage , editor . document , this . engine_ ) ;
421- if ( executor ) {
422- await executeInteractive ( executor , [ selection ] , editor . document ) ;
423-
424- // advance cursor if necessary
425- //
426- if ( action ) {
427- console . log ( 'action!!!' , action , this . id )
428- await editor . setBlockSelection ( context , action ) ;
415+ // if not in Positron
416+ } else {
417+ // if the selection is empty and this isn't a knitr document then it resolves to run cell
418+ if ( selection . length <= 0 && ! isKnitrDocument ( editor . document , this . engine_ ) ) {
419+ if ( activeBlock ) {
420+ const executor = await this . cellExecutorForLanguage ( activeBlock . language , editor . document , this . engine_ ) ;
421+ if ( executor ) {
422+ await executeInteractive ( executor , [ activeBlock . code ] , editor . document ) ;
423+ await activateIfRequired ( editor ) ;
424+ }
425+ }
426+ } else {
427+ if ( selection . length > 0 ) {
428+ exec ( "nextline" , selection )
429+ } else if ( activeBlock ) { // if the selection is empty take the whole line as the selection
430+ exec ( "nextline" , lines ( activeBlock . code ) [ context . selection . start . line ] )
429431 }
430432 }
431433 }
@@ -441,7 +443,7 @@ class RunSelectionCommand extends RunCurrentCommand implements Command {
441443
442444}
443445
444-
446+ // Run Cell and Advance
445447class RunCurrentAdvanceCommand extends RunCommand implements Command {
446448 constructor ( host : ExtensionHost , engine : MarkdownEngine ) {
447449 super ( host , engine ) ;
0 commit comments