@@ -3,7 +3,11 @@ import { join } from "../deno_ral/path.ts";
33import { MappedString , mappedStringFromFile } from "../core/mapped-text.ts" ;
44import { partitionMarkdown } from "../core/pandoc/pandoc-partition.ts" ;
55import { readYamlFromMarkdown } from "../core/yaml.ts" ;
6- import { asMappedString } from "../core/lib/mapped-text.ts" ;
6+ import {
7+ asMappedString ,
8+ mappedIndexToLineCol ,
9+ mappedLines ,
10+ } from "../core/lib/mapped-text.ts" ;
711import { ProjectContext } from "../project/types.ts" ;
812import {
913 DependenciesOptions ,
@@ -53,6 +57,12 @@ import {
5357 markdownFromJupyterPercentScript ,
5458} from "./jupyter/percent.ts" ;
5559
60+ export interface SourceRange {
61+ lines : [ number , number ] ;
62+ file ?: string ;
63+ sourceLines ?: [ number , number ] ;
64+ }
65+
5666export interface JuliaExecuteOptions extends ExecuteOptions {
5767 oneShot : boolean ; // if true, the file's worker process is closed before and after running
5868}
@@ -578,6 +588,62 @@ function getConsoleColumns(): number | null {
578588 }
579589}
580590
591+ function buildSourceRanges ( markdown : MappedString ) : Array < SourceRange > {
592+ const lines = mappedLines ( markdown ) ;
593+ const sourceRanges : Array < SourceRange > = [ ] ;
594+ let currentRange : SourceRange | null = null ;
595+
596+ lines . forEach ( ( line , index ) => {
597+ // Get mapping info directly from the line's MappedString
598+ const mapResult = line . map ( 0 , true ) ;
599+ if ( mapResult ) {
600+ const { originalString } = mapResult ;
601+ const lineColFunc = mappedIndexToLineCol ( originalString ) ;
602+ const lineCol = lineColFunc ( mapResult . index ) ;
603+ const fileName = originalString . fileName ;
604+ const sourceLineNum = lineCol . line ;
605+
606+ // Check if this line continues the current range
607+ if (
608+ currentRange &&
609+ currentRange . file === fileName &&
610+ fileName !== undefined &&
611+ currentRange . sourceLines &&
612+ currentRange . sourceLines [ 1 ] === sourceLineNum
613+ ) {
614+ // Extend current range
615+ currentRange . lines [ 1 ] = index + 1 ; // +1 because lines are 1-indexed
616+ currentRange . sourceLines [ 1 ] = sourceLineNum + 1 ;
617+ } else {
618+ // Start new range
619+ if ( currentRange ) {
620+ sourceRanges . push ( currentRange ) ;
621+ }
622+ currentRange = {
623+ lines : [ index + 1 , index + 1 ] , // +1 because lines are 1-indexed
624+ } ;
625+ if ( fileName !== undefined ) {
626+ currentRange . file = fileName ;
627+ currentRange . sourceLines = [ sourceLineNum + 1 , sourceLineNum + 1 ] ;
628+ }
629+ }
630+ } else {
631+ // No mapping available - treat as separate range
632+ if ( currentRange ) {
633+ sourceRanges . push ( currentRange ) ;
634+ currentRange = null ;
635+ }
636+ }
637+ } ) ;
638+
639+ // Don't forget the last range
640+ if ( currentRange ) {
641+ sourceRanges . push ( currentRange ) ;
642+ }
643+
644+ return sourceRanges ;
645+ }
646+
581647async function executeJulia (
582648 options : JuliaExecuteOptions ,
583649) : Promise < JupyterNotebook > {
@@ -600,9 +666,12 @@ async function executeJulia(
600666 ) ;
601667 }
602668 }
669+
670+ const sourceRanges = buildSourceRanges ( options . target . markdown ) ;
671+
603672 const response = await writeJuliaCommand (
604673 conn ,
605- { type : "run" , content : { file, options } } ,
674+ { type : "run" , content : { file, options, sourceRanges } } ,
606675 transportOptions . key ,
607676 options ,
608677 ( update : ProgressUpdate ) => {
@@ -643,7 +712,14 @@ interface ProgressUpdate {
643712type empty = Record < string | number | symbol , never > ;
644713
645714type ServerCommand =
646- | { type : "run" ; content : { file : string ; options : JuliaExecuteOptions } }
715+ | {
716+ type : "run" ;
717+ content : {
718+ file : string ;
719+ options : JuliaExecuteOptions ;
720+ sourceRanges : Array < SourceRange > ;
721+ } ;
722+ }
647723 | { type : "close" ; content : { file : string } }
648724 | { type : "forceclose" ; content : { file : string } }
649725 | { type : "isopen" ; content : { file : string } }
@@ -854,7 +930,9 @@ function populateJuliaEngineCommand(command: Command) {
854930 "Get status information on the currently running Julia server process." ,
855931 ) . action ( logStatus )
856932 . command ( "kill" , "Kill server" )
857- . description ( "Kill the control server if it is currently running. This will also kill all notebook worker processes." )
933+ . description (
934+ "Kill the control server if it is currently running. This will also kill all notebook worker processes." ,
935+ )
858936 . action ( killJuliaServer )
859937 . command ( "log" , "Print julia server log" )
860938 . description (
0 commit comments