@@ -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 ,
@@ -52,6 +56,13 @@ import {
5256 isJupyterPercentScript ,
5357 markdownFromJupyterPercentScript ,
5458} from "./jupyter/percent.ts" ;
59+ import { resolve } from "path" ;
60+
61+ export interface SourceRange {
62+ lines : [ number , number ] ;
63+ file ?: string ;
64+ sourceLines ?: [ number , number ] ;
65+ }
5566
5667export interface JuliaExecuteOptions extends ExecuteOptions {
5768 oneShot : boolean ; // if true, the file's worker process is closed before and after running
@@ -578,6 +589,64 @@ function getConsoleColumns(): number | null {
578589 }
579590}
580591
592+ function buildSourceRanges ( markdown : MappedString ) : Array < SourceRange > {
593+ const lines = mappedLines ( markdown ) ;
594+ const sourceRanges : Array < SourceRange > = [ ] ;
595+ let currentRange : SourceRange | null = null ;
596+
597+ lines . forEach ( ( line , index ) => {
598+ // Get mapping info directly from the line's MappedString
599+ const mapResult = line . map ( 0 , true ) ;
600+ if ( mapResult ) {
601+ const { originalString } = mapResult ;
602+ const lineColFunc = mappedIndexToLineCol ( originalString ) ;
603+ const lineCol = lineColFunc ( mapResult . index ) ;
604+ const fileName = originalString . fileName
605+ ? resolve ( originalString . fileName ) // resolve to absolute path using cwd
606+ : undefined ;
607+ const sourceLineNum = lineCol . line ;
608+
609+ // Check if this line continues the current range
610+ if (
611+ currentRange &&
612+ currentRange . file === fileName &&
613+ fileName !== undefined &&
614+ currentRange . sourceLines &&
615+ currentRange . sourceLines [ 1 ] === sourceLineNum
616+ ) {
617+ // Extend current range
618+ currentRange . lines [ 1 ] = index + 1 ; // +1 because lines are 1-indexed
619+ currentRange . sourceLines [ 1 ] = sourceLineNum + 1 ;
620+ } else {
621+ // Start new range
622+ if ( currentRange ) {
623+ sourceRanges . push ( currentRange ) ;
624+ }
625+ currentRange = {
626+ lines : [ index + 1 , index + 1 ] , // +1 because lines are 1-indexed
627+ } ;
628+ if ( fileName !== undefined ) {
629+ currentRange . file = fileName ;
630+ currentRange . sourceLines = [ sourceLineNum + 1 , sourceLineNum + 1 ] ;
631+ }
632+ }
633+ } else {
634+ // No mapping available - treat as separate range
635+ if ( currentRange ) {
636+ sourceRanges . push ( currentRange ) ;
637+ currentRange = null ;
638+ }
639+ }
640+ } ) ;
641+
642+ // Don't forget the last range
643+ if ( currentRange ) {
644+ sourceRanges . push ( currentRange ) ;
645+ }
646+
647+ return sourceRanges ;
648+ }
649+
581650async function executeJulia (
582651 options : JuliaExecuteOptions ,
583652) : Promise < JupyterNotebook > {
@@ -600,9 +669,12 @@ async function executeJulia(
600669 ) ;
601670 }
602671 }
672+
673+ const sourceRanges = buildSourceRanges ( options . target . markdown ) ;
674+
603675 const response = await writeJuliaCommand (
604676 conn ,
605- { type : "run" , content : { file, options } } ,
677+ { type : "run" , content : { file, options, sourceRanges } } ,
606678 transportOptions . key ,
607679 options ,
608680 ( update : ProgressUpdate ) => {
@@ -643,7 +715,14 @@ interface ProgressUpdate {
643715type empty = Record < string | number | symbol , never > ;
644716
645717type ServerCommand =
646- | { type : "run" ; content : { file : string ; options : JuliaExecuteOptions } }
718+ | {
719+ type : "run" ;
720+ content : {
721+ file : string ;
722+ options : JuliaExecuteOptions ;
723+ sourceRanges : Array < SourceRange > ;
724+ } ;
725+ }
647726 | { type : "close" ; content : { file : string } }
648727 | { type : "forceclose" ; content : { file : string } }
649728 | { type : "isopen" ; content : { file : string } }
@@ -854,7 +933,9 @@ function populateJuliaEngineCommand(command: Command) {
854933 "Get status information on the currently running Julia server process." ,
855934 ) . action ( logStatus )
856935 . command ( "kill" , "Kill server" )
857- . description ( "Kill the control server if it is currently running. This will also kill all notebook worker processes." )
936+ . description (
937+ "Kill the control server if it is currently running. This will also kill all notebook worker processes." ,
938+ )
858939 . action ( killJuliaServer )
859940 . command ( "log" , "Print julia server log" )
860941 . description (
0 commit comments