Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 85 additions & 4 deletions src/execute/julia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { join } from "../deno_ral/path.ts";
import { MappedString, mappedStringFromFile } from "../core/mapped-text.ts";
import { partitionMarkdown } from "../core/pandoc/pandoc-partition.ts";
import { readYamlFromMarkdown } from "../core/yaml.ts";
import { asMappedString } from "../core/lib/mapped-text.ts";
import {
asMappedString,
mappedIndexToLineCol,
mappedLines,
} from "../core/lib/mapped-text.ts";
import { ProjectContext } from "../project/types.ts";
import {
DependenciesOptions,
Expand Down Expand Up @@ -52,6 +56,13 @@ import {
isJupyterPercentScript,
markdownFromJupyterPercentScript,
} from "./jupyter/percent.ts";
import { resolve } from "path";

export interface SourceRange {
lines: [number, number];
file?: string;
sourceLines?: [number, number];
}

export interface JuliaExecuteOptions extends ExecuteOptions {
oneShot: boolean; // if true, the file's worker process is closed before and after running
Expand Down Expand Up @@ -578,6 +589,64 @@ function getConsoleColumns(): number | null {
}
}

function buildSourceRanges(markdown: MappedString): Array<SourceRange> {
const lines = mappedLines(markdown);
const sourceRanges: Array<SourceRange> = [];
let currentRange: SourceRange | null = null;

lines.forEach((line, index) => {
// Get mapping info directly from the line's MappedString
const mapResult = line.map(0, true);
if (mapResult) {
const { originalString } = mapResult;
const lineColFunc = mappedIndexToLineCol(originalString);
const lineCol = lineColFunc(mapResult.index);
const fileName = originalString.fileName
? resolve(originalString.fileName) // resolve to absolute path using cwd
: undefined;
const sourceLineNum = lineCol.line;

// Check if this line continues the current range
if (
currentRange &&
currentRange.file === fileName &&
fileName !== undefined &&
currentRange.sourceLines &&
currentRange.sourceLines[1] === sourceLineNum
) {
// Extend current range
currentRange.lines[1] = index + 1; // +1 because lines are 1-indexed
currentRange.sourceLines[1] = sourceLineNum + 1;
} else {
// Start new range
if (currentRange) {
sourceRanges.push(currentRange);
}
currentRange = {
lines: [index + 1, index + 1], // +1 because lines are 1-indexed
};
if (fileName !== undefined) {
currentRange.file = fileName;
currentRange.sourceLines = [sourceLineNum + 1, sourceLineNum + 1];
}
}
} else {
// No mapping available - treat as separate range
if (currentRange) {
sourceRanges.push(currentRange);
currentRange = null;
}
}
});

// Don't forget the last range
if (currentRange) {
sourceRanges.push(currentRange);
}

return sourceRanges;
}

async function executeJulia(
options: JuliaExecuteOptions,
): Promise<JupyterNotebook> {
Expand All @@ -600,9 +669,12 @@ async function executeJulia(
);
}
}

const sourceRanges = buildSourceRanges(options.target.markdown);

const response = await writeJuliaCommand(
conn,
{ type: "run", content: { file, options } },
{ type: "run", content: { file, options, sourceRanges } },
transportOptions.key,
options,
(update: ProgressUpdate) => {
Expand Down Expand Up @@ -643,7 +715,14 @@ interface ProgressUpdate {
type empty = Record<string | number | symbol, never>;

type ServerCommand =
| { type: "run"; content: { file: string; options: JuliaExecuteOptions } }
| {
type: "run";
content: {
file: string;
options: JuliaExecuteOptions;
sourceRanges: Array<SourceRange>;
};
}
| { type: "close"; content: { file: string } }
| { type: "forceclose"; content: { file: string } }
| { type: "isopen"; content: { file: string } }
Expand Down Expand Up @@ -854,7 +933,9 @@ function populateJuliaEngineCommand(command: Command) {
"Get status information on the currently running Julia server process.",
).action(logStatus)
.command("kill", "Kill server")
.description("Kill the control server if it is currently running. This will also kill all notebook worker processes.")
.description(
"Kill the control server if it is currently running. This will also kill all notebook worker processes.",
)
.action(killJuliaServer)
.command("log", "Print julia server log")
.description(
Expand Down
7 changes: 5 additions & 2 deletions src/resources/julia/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
[deps]
QuartoNotebookRunner = "4c0109c6-14e9-4c88-93f0-2b974d3468f4"

[compat]
QuartoNotebookRunner = "=0.17.3"
# [compat]
# QuartoNotebookRunner = "=0.17.3"

[sources]
QuartoNotebookRunner = {url = "https://github.com/PumasAI/QuartoNotebookRunner.jl", rev = "jk/source-ranges"}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cscheid this shouldn't have gone in until I have time to review that PR, otherwise quarto master is using a reference to a branch that will change/get deleted soon.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I'm sorry. We do try to keep main working (and I will no longer merge these before your ok!).

With that said, we can tolerate some minor amount of breakage here. Can you let me know when the new release is up so we can just bump QNR to (I assume) 0.17.4?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might get to it this week, might not though, so it's probably best to just revert for the time being.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. But just to understand: in the meantime, the branch exists and presumably works (since the tests passed?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But just to understand: in the meantime, the branch exists and presumably works (since the tests passed?)

Correct, it'll keep working until we go and merge and delete the branch then stuff here will begin failing.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, I think I'm comfortable with this living on main for the time being. We're very early on in 1.9; this looks safe to me!

3 changes: 3 additions & 0 deletions tests/docs/smoke-all/julia/_included.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```{julia}
"$(@__FILE__):$(@__LINE__)"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's really great that you can do this in the julia engine!

```
16 changes: 16 additions & 0 deletions tests/docs/smoke-all/julia/source-ranges-test.qmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: "Test Julia source ranges with includes"
format: markdown
engine: julia
_quarto:
tests:
markdown:
ensureFileRegexMatches:
- ['source-ranges-test\.qmd:15', '_included\.qmd:2']
---

{{< include _included.qmd >}}

```{julia}
"$(@__FILE__):$(@__LINE__)"
```
Loading