@@ -263,7 +263,19 @@ class RunPreviousCellCommand extends RunCommand implements Command {
263263 }
264264}
265265
266+ // More permissive type than `Position` so its easier to construct via a literal
267+ type LineAndCharPos = { line : number , character : number }
268+ // More permissive type than `Range` so its easier to construct via a literal
269+ type LineAndCharRange = { start : LineAndCharPos , end : LineAndCharPos }
270+
271+ function extractRangeFromCode ( code : string , range : LineAndCharRange ) : string {
272+ const extractedRange = lines ( code ) . slice ( range . start . line , range . end . line + 1 )
273+ extractedRange [ 0 ] = extractedRange [ 0 ] . slice ( range . start . character )
274+ extractedRange [ extractedRange . length - 1 ] = extractedRange [ extractedRange . length - 1 ] . slice ( 0 , range . end . character )
275+ return extractedRange . join ( '\n' )
276+ }
266277
278+ // Run the code at the cursor
267279class RunCurrentCommand extends RunCommand implements Command {
268280 constructor (
269281 host : ExtensionHost ,
@@ -340,95 +352,85 @@ class RunCurrentCommand extends RunCommand implements Command {
340352 context : CodeViewActiveBlockContext
341353 ) : Promise < void > {
342354 // get selection and active block
343- let selection = context . selectedText ;
355+ const selection = context . selectedText ;
344356 const activeBlock = context . blocks . find ( block => block . active ) ;
345357
346- // idea: first check that we are in Positron
347- // and leave the others untouched
348-
349- // if the selection is empty and this isn't a knitr document then it resolves to run cell
350- if ( false ) {
351- if ( activeBlock ) {
352- const executor = await this . cellExecutorForLanguage ( activeBlock . language , editor . document , this . engine_ ) ;
353- if ( executor ) {
354- await executeInteractive ( executor , [ activeBlock . code ] , editor . document ) ;
355- await activateIfRequired ( editor ) ;
356- }
358+ const exec = async ( action : CodeViewSelectionAction , selection : string ) => {
359+ const executor = await this . cellExecutorForLanguage ( context . activeLanguage , editor . document , this . engine_ ) ;
360+ if ( executor ) {
361+ await executeInteractive ( executor , [ selection ] , editor . document ) ;
362+ await editor . setBlockSelection ( context , action ) ;
357363 }
358- } else {
359- let action : CodeViewSelectionAction | undefined ;
364+ }
360365
361- // if the selection is empty and we are in Positron:
362- // try to get the statement's range and use that as the selection
363- if ( selection . length <= 0 && activeBlock && hasHooks ( ) ) {
366+ // if in Positron
367+ if ( hasHooks ( ) ) {
368+ if ( activeBlock && selection . length <= 0 ) {
364369 const codeLines = lines ( activeBlock . code )
365370 const vdoc = virtualDocForCode ( codeLines , embeddedLanguage ( activeBlock . language ) ! ) ;
366371 if ( vdoc ) {
367372 const parentUri = Uri . file ( editor . document . fileName ) ;
368373 const injectedLines = ( vdoc . language ?. inject ?. length ?? 0 )
369374
370- const positionIntoVdoc = ( p : { line : number , character : number } ) =>
375+ const positionIntoVdoc = ( p : LineAndCharPos ) =>
371376 new Position ( p . line + injectedLines , p . character )
372- const positionOutOfVdoc = ( p : { line : number , character : number } ) =>
377+ const positionOutOfVdoc = ( p : LineAndCharPos ) =>
373378 new Position ( p . line - injectedLines , p . character )
374-
375- const result = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
376- return await commands . executeCommand < StatementRange > (
377- "vscode.executeStatementRangeProvider" ,
378- uri ,
379- positionIntoVdoc ( context . selection . start )
380- ) ;
381- } ) ;
382- const { range, code } = result
383- if ( code === undefined ) return
384- const adjustedEnd = positionOutOfVdoc ( range . end )
385-
386- selection = code
387- action = "nextline" ;
388-
389- // BEGIN ref: https://github.com/posit-dev/positron/blob/main/src/vs/workbench/contrib/positronConsole/browser/positronConsoleActions.ts#L428
390- // strategy from Positron using `StatementRangeProvider` to find range of next statement
391- // and move cursor based on that.
392- if ( adjustedEnd . line + 1 <= codeLines . length ) {
393- const nextStatementRange = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
379+ const rangeOutOfVdoc = ( r : Range ) : LineAndCharRange => ( {
380+ start : positionOutOfVdoc ( r . start ) ,
381+ end : positionOutOfVdoc ( r . end )
382+ } )
383+ const getStatementRange = async ( pos : LineAndCharPos ) => {
384+ const result = await withVirtualDocUri ( vdoc , parentUri , "statementRange" , async ( uri ) => {
394385 return await commands . executeCommand < StatementRange > (
395386 "vscode.executeStatementRangeProvider" ,
396387 uri ,
397- positionIntoVdoc ( new Position ( adjustedEnd . line + 1 , 1 ) ) // look for statement at line after current statement
388+ positionIntoVdoc ( pos )
398389 ) ;
399390 } ) ;
400- const nextStatement = {
401- start : positionOutOfVdoc ( nextStatementRange . range . start ) ,
402- end : positionOutOfVdoc ( nextStatementRange . range . end )
403- } ;
404- if ( nextStatement . start . line > adjustedEnd . line ) {
405- action = nextStatement . start
406- // the nextStatement may start before & end after the current statement if e.g. inside a function:
407- } else if ( nextStatement . end . line > adjustedEnd . line ) {
408- action = nextStatement . end
391+ return rangeOutOfVdoc ( result . range )
392+ }
393+
394+ const range = await getStatementRange ( context . selection . start )
395+ const code = extractRangeFromCode ( activeBlock . code , range )
396+
397+ // BEGIN ref: https://github.com/posit-dev/positron/blob/main/src/vs/workbench/contrib/positronConsole/browser/positronConsoleActions.ts#L428
398+ // strategy from Positron using `StatementRangeProvider` to find range of next statement
399+ // and move cursor based on that.
400+ if ( range . end . line + 1 <= codeLines . length ) {
401+ // get range of statement at line after current statement)
402+ const nextRange = await getStatementRange ( new Position ( range . end . line + 1 , 1 ) )
403+
404+ if ( nextRange . start . line > range . end . line ) {
405+ exec ( nextRange . start , code )
406+ // the next statement range may start before & end after the current statement if e.g. inside a function:
407+ } else if ( nextRange . end . line > range . end . line ) {
408+ exec ( nextRange . end , code )
409+ } else {
410+ exec ( "nextline" , code )
409411 }
412+ } else {
413+ exec ( "nextline" , code )
410414 }
411415 // END ref.
412416 }
413417 }
414-
415- // if the selection is still empty:
416- // take the whole line as the selection
417- if ( selection . length <= 0 && activeBlock ) {
418- selection = lines ( activeBlock . code ) [ context . selection . start . line ] ;
419- action = "nextline" ;
420- }
421-
422- // run code
423- const executor = await this . cellExecutorForLanguage ( context . activeLanguage , editor . document , this . engine_ ) ;
424- if ( executor ) {
425- await executeInteractive ( executor , [ selection ] , editor . document ) ;
426-
427- // advance cursor if necessary
428- //
429- if ( action ) {
430- console . log ( 'action!!!' , action , this . id )
431- await editor . setBlockSelection ( context , action ) ;
418+ // if not in Positron
419+ } else {
420+ // if the selection is empty and this isn't a knitr document then it resolves to run cell
421+ if ( selection . length <= 0 && ! isKnitrDocument ( editor . document , this . engine_ ) ) {
422+ if ( activeBlock ) {
423+ const executor = await this . cellExecutorForLanguage ( activeBlock . language , editor . document , this . engine_ ) ;
424+ if ( executor ) {
425+ await executeInteractive ( executor , [ activeBlock . code ] , editor . document ) ;
426+ await activateIfRequired ( editor ) ;
427+ }
428+ }
429+ } else {
430+ if ( selection . length > 0 ) {
431+ exec ( "nextline" , selection )
432+ } else if ( activeBlock ) { // if the selection is empty take the whole line as the selection
433+ exec ( "nextline" , lines ( activeBlock . code ) [ context . selection . start . line ] )
432434 }
433435 }
434436 }
@@ -444,7 +446,7 @@ class RunSelectionCommand extends RunCurrentCommand implements Command {
444446
445447}
446448
447-
449+ // Run Cell and Advance
448450class RunCurrentAdvanceCommand extends RunCommand implements Command {
449451 constructor ( host : ExtensionHost , engine : MarkdownEngine ) {
450452 super ( host , engine ) ;
0 commit comments