pi-studio 0.9.37 → 0.9.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +4 -1
- package/client/studio-client.js +537 -16
- package/client/studio.css +253 -0
- package/index.ts +474 -5
- package/package.json +1 -1
- package/shared/studio-mermaid.js +39 -3
- package/shared/studio-quarto-preview.js +169 -0
package/client/studio-client.js
CHANGED
|
@@ -180,11 +180,12 @@
|
|
|
180
180
|
: "full";
|
|
181
181
|
const isEditorOnlyMode = studioMode === "editor-only";
|
|
182
182
|
const isSshStudioSession = Boolean(document.body && document.body.dataset && document.body.dataset.sshSession === "1");
|
|
183
|
-
const EDITOR_ONLY_RIGHT_VIEW_ALLOWED = new Set(["editor-preview", "files", "changes", "repl"]);
|
|
183
|
+
const EDITOR_ONLY_RIGHT_VIEW_ALLOWED = new Set(["editor-preview", "editor-quarto-preview", "files", "changes", "repl"]);
|
|
184
184
|
const RIGHT_VIEW_LABELS = {
|
|
185
185
|
markdown: "Response (Raw)",
|
|
186
186
|
preview: "Response (Preview)",
|
|
187
187
|
"editor-preview": "Editor (Preview)",
|
|
188
|
+
"editor-quarto-preview": "Editor (Quarto Preview)",
|
|
188
189
|
trace: "Working",
|
|
189
190
|
changes: "Changes",
|
|
190
191
|
files: "Files",
|
|
@@ -276,17 +277,22 @@
|
|
|
276
277
|
? "preview"
|
|
277
278
|
: (raw === "editor-preview"
|
|
278
279
|
? "editor-preview"
|
|
279
|
-
: (raw === "
|
|
280
|
-
? "
|
|
281
|
-
: (raw === "
|
|
282
|
-
? "
|
|
283
|
-
: (raw === "
|
|
284
|
-
? "
|
|
285
|
-
: (
|
|
280
|
+
: (raw === "editor-quarto-preview"
|
|
281
|
+
? "editor-quarto-preview"
|
|
282
|
+
: (raw === "repl"
|
|
283
|
+
? "repl"
|
|
284
|
+
: (raw === "files"
|
|
285
|
+
? "files"
|
|
286
|
+
: (raw === "changes"
|
|
287
|
+
? "changes"
|
|
288
|
+
: ((raw === "trace" || raw === "thinking") ? "trace" : "markdown"))))));
|
|
286
289
|
}
|
|
287
290
|
|
|
288
291
|
function normalizeRightViewValue(nextView) {
|
|
289
292
|
const normalized = canonicalRightViewValue(nextView);
|
|
293
|
+
if (normalized === "editor-quarto-preview" && !isCurrentStudioQuartoDocument()) {
|
|
294
|
+
return "editor-preview";
|
|
295
|
+
}
|
|
290
296
|
if (isEditorOnlyMode && !EDITOR_ONLY_RIGHT_VIEW_ALLOWED.has(normalized)) {
|
|
291
297
|
return "editor-preview";
|
|
292
298
|
}
|
|
@@ -295,6 +301,7 @@
|
|
|
295
301
|
|
|
296
302
|
function isRightViewAvailableInCurrentMode(view) {
|
|
297
303
|
const normalized = canonicalRightViewValue(view);
|
|
304
|
+
if (normalized === "editor-quarto-preview" && !isCurrentStudioQuartoDocument()) return false;
|
|
298
305
|
return !isEditorOnlyMode || EDITOR_ONLY_RIGHT_VIEW_ALLOWED.has(normalized);
|
|
299
306
|
}
|
|
300
307
|
|
|
@@ -309,13 +316,16 @@
|
|
|
309
316
|
|
|
310
317
|
function syncRightViewModeOptions() {
|
|
311
318
|
if (!rightViewSelect || !rightViewSelect.options) return;
|
|
319
|
+
const quartoRelevant = isCurrentStudioQuartoDocument();
|
|
312
320
|
Array.from(rightViewSelect.options).forEach((option) => {
|
|
313
321
|
if (!option) return;
|
|
314
|
-
|
|
322
|
+
const isQuartoOption = option.value === "editor-quarto-preview";
|
|
323
|
+
if (isQuartoOption) option.hidden = !quartoRelevant;
|
|
324
|
+
option.disabled = (isEditorOnlyMode && !EDITOR_ONLY_RIGHT_VIEW_ALLOWED.has(option.value)) || (isQuartoOption && !quartoRelevant);
|
|
315
325
|
});
|
|
316
326
|
rightViewSelect.title = isEditorOnlyMode
|
|
317
|
-
? "Editor-only views: Editor Preview, Changes, Files, or REPL. F7 cycles; Cmd/Ctrl+Alt+3/5/6/7 switch directly to
|
|
318
|
-
: "Right pane view mode. F7 cycles; Cmd/Ctrl+Alt+1–7 switches directly between
|
|
327
|
+
? "Editor-only views: Editor Preview, contextual Quarto Preview for .qmd/.md/.markdown files, Changes, Files, or REPL. F7 cycles; Cmd/Ctrl+Alt+3/5/6/7 switch directly to numbered right-pane views."
|
|
328
|
+
: "Right pane view mode. F7 cycles, including contextual Quarto Preview for file-backed .qmd, .md, and .markdown documents; Cmd/Ctrl+Alt+1–7 switches directly between the numbered views. Cmd/Ctrl+Alt+P/E/W keep their mnemonic Preview/Editor Preview/Working shortcuts.";
|
|
319
329
|
}
|
|
320
330
|
|
|
321
331
|
function getInitialRightView(source) {
|
|
@@ -2009,6 +2019,22 @@
|
|
|
2009
2019
|
path: initialSourceState.path,
|
|
2010
2020
|
draftId: initialSourceState.draftId,
|
|
2011
2021
|
};
|
|
2022
|
+
let quartoPreviewContext = null;
|
|
2023
|
+
let quartoPreviewCheckRequestId = null;
|
|
2024
|
+
let quartoPreviewCheckSourcePath = "";
|
|
2025
|
+
let quartoPreviewActionRequestId = null;
|
|
2026
|
+
let quartoPreviewLogVisible = false;
|
|
2027
|
+
let quartoPreviewState = {
|
|
2028
|
+
status: "idle",
|
|
2029
|
+
sourcePath: "",
|
|
2030
|
+
url: "",
|
|
2031
|
+
log: "",
|
|
2032
|
+
error: null,
|
|
2033
|
+
context: null,
|
|
2034
|
+
startedAt: null,
|
|
2035
|
+
updatedAt: 0,
|
|
2036
|
+
actionRequestId: null,
|
|
2037
|
+
};
|
|
2012
2038
|
let fileBackedBaselineText = null;
|
|
2013
2039
|
let activePane = "left";
|
|
2014
2040
|
let paneFocusTarget = "off";
|
|
@@ -3908,7 +3934,7 @@
|
|
|
3908
3934
|
function getSelectEnabledValues(selectEl) {
|
|
3909
3935
|
if (!selectEl || !selectEl.options) return [];
|
|
3910
3936
|
return Array.from(selectEl.options)
|
|
3911
|
-
.filter((option) => option && !option.disabled)
|
|
3937
|
+
.filter((option) => option && !option.disabled && !option.hidden)
|
|
3912
3938
|
.map((option) => option.value)
|
|
3913
3939
|
.filter((value) => typeof value === "string" && value);
|
|
3914
3940
|
}
|
|
@@ -4743,6 +4769,22 @@
|
|
|
4743
4769
|
return;
|
|
4744
4770
|
}
|
|
4745
4771
|
|
|
4772
|
+
if (rightView === "editor-quarto-preview") {
|
|
4773
|
+
const context = getCurrentStudioQuartoContext();
|
|
4774
|
+
const current = getStudioQuartoProcessStatusForCurrentSource();
|
|
4775
|
+
const label = context && context.projectLabel ? context.projectLabel : (sourceState.label || "Quarto document");
|
|
4776
|
+
const statusLabel = quartoPreviewCheckRequestId
|
|
4777
|
+
? "checking"
|
|
4778
|
+
: (context && !context.available
|
|
4779
|
+
? "unavailable"
|
|
4780
|
+
: (current.sameSource
|
|
4781
|
+
? (current.status === "running" ? "running" : (current.status === "starting" ? "starting" : (current.status === "error" ? "error" : "stopped")))
|
|
4782
|
+
: ((quartoPreviewState.status === "running" || quartoPreviewState.status === "starting") ? "another preview running" : "ready to start")));
|
|
4783
|
+
referenceBadgeEl.textContent = "Quarto: " + label + " · " + statusLabel + " · saved-file preview"
|
|
4784
|
+
+ (isStudioQuartoEditorDirty() ? " · unsaved changes excluded" : "");
|
|
4785
|
+
return;
|
|
4786
|
+
}
|
|
4787
|
+
|
|
4746
4788
|
if (rightView === "editor-preview") {
|
|
4747
4789
|
const hasResponse = Boolean(latestResponseMarkdown && latestResponseMarkdown.trim());
|
|
4748
4790
|
if (hasResponse) {
|
|
@@ -8182,6 +8224,7 @@
|
|
|
8182
8224
|
critiqueViewEl.addEventListener("click", handleReplPaneClick);
|
|
8183
8225
|
critiqueViewEl.addEventListener("click", handleFilesPaneClick);
|
|
8184
8226
|
critiqueViewEl.addEventListener("click", handleGitChangesPaneClick);
|
|
8227
|
+
critiqueViewEl.addEventListener("click", handleStudioQuartoPreviewClick);
|
|
8185
8228
|
critiqueViewEl.addEventListener("change", handleReplPaneChange);
|
|
8186
8229
|
critiqueViewEl.addEventListener("change", (event) => {
|
|
8187
8230
|
void handleFilesPaneChange(event);
|
|
@@ -8207,7 +8250,7 @@
|
|
|
8207
8250
|
|
|
8208
8251
|
function applyPendingResponseScrollReset() {
|
|
8209
8252
|
if (!pendingResponseScrollReset || !critiqueViewEl) return false;
|
|
8210
|
-
if (rightView === "editor-preview") return false;
|
|
8253
|
+
if (rightView === "editor-preview" || rightView === "editor-quarto-preview") return false;
|
|
8211
8254
|
|
|
8212
8255
|
pendingResponseScrollReset = false;
|
|
8213
8256
|
let targetEl = replaceResponsePaneWithClone();
|
|
@@ -8216,7 +8259,7 @@
|
|
|
8216
8259
|
: (cb) => window.setTimeout(cb, 16);
|
|
8217
8260
|
const resetScroll = () => {
|
|
8218
8261
|
if (!targetEl || !targetEl.isConnected) return;
|
|
8219
|
-
if (rightView === "editor-preview") return;
|
|
8262
|
+
if (rightView === "editor-preview" || rightView === "editor-quarto-preview") return;
|
|
8220
8263
|
targetEl.scrollTop = 0;
|
|
8221
8264
|
targetEl.scrollLeft = 0;
|
|
8222
8265
|
};
|
|
@@ -10548,8 +10591,289 @@
|
|
|
10548
10591
|
}
|
|
10549
10592
|
}
|
|
10550
10593
|
|
|
10594
|
+
function getStudioQuartoProcessStatusForCurrentSource() {
|
|
10595
|
+
const sourcePath = getCurrentStudioQuartoSourcePath();
|
|
10596
|
+
return {
|
|
10597
|
+
sameSource: studioQuartoPathsMatch(quartoPreviewState.sourcePath, sourcePath)
|
|
10598
|
+
|| Boolean(quartoPreviewState.context && studioQuartoPathsMatch(quartoPreviewState.context.requestedSourcePath, sourcePath)),
|
|
10599
|
+
sourcePath,
|
|
10600
|
+
status: quartoPreviewState.status,
|
|
10601
|
+
};
|
|
10602
|
+
}
|
|
10603
|
+
|
|
10604
|
+
function isStudioQuartoEditorDirty() {
|
|
10605
|
+
return Boolean(isCurrentStudioQuartoDocument() && editorDiffersFromFileBackedBaseline());
|
|
10606
|
+
}
|
|
10607
|
+
|
|
10608
|
+
function requestStudioQuartoPreviewCheck(force) {
|
|
10609
|
+
const sourcePath = getCurrentStudioQuartoSourcePath();
|
|
10610
|
+
if (!isCurrentStudioQuartoDocument()) return false;
|
|
10611
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) return false;
|
|
10612
|
+
if (!force && getCurrentStudioQuartoContext()) return true;
|
|
10613
|
+
if (!force && quartoPreviewCheckRequestId && studioQuartoPathsMatch(quartoPreviewCheckSourcePath, sourcePath)) return true;
|
|
10614
|
+
const requestId = makeRequestId();
|
|
10615
|
+
quartoPreviewCheckRequestId = requestId;
|
|
10616
|
+
quartoPreviewCheckSourcePath = sourcePath;
|
|
10617
|
+
quartoPreviewContext = null;
|
|
10618
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
10619
|
+
const sent = sendMessage({ type: "quarto_preview_check_request", requestId, sourcePath });
|
|
10620
|
+
if (!sent) {
|
|
10621
|
+
quartoPreviewCheckRequestId = null;
|
|
10622
|
+
quartoPreviewCheckSourcePath = "";
|
|
10623
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
10624
|
+
}
|
|
10625
|
+
return sent;
|
|
10626
|
+
}
|
|
10627
|
+
|
|
10628
|
+
function requestStudioQuartoPreviewStart() {
|
|
10629
|
+
const sourcePath = getCurrentStudioQuartoSourcePath();
|
|
10630
|
+
if (!isCurrentStudioQuartoDocument()) {
|
|
10631
|
+
setStatus("Quarto preview requires a file-backed .qmd, .md, or .markdown document.", "warning");
|
|
10632
|
+
return false;
|
|
10633
|
+
}
|
|
10634
|
+
if (quartoPreviewActionRequestId) return false;
|
|
10635
|
+
const requestId = makeRequestId();
|
|
10636
|
+
quartoPreviewActionRequestId = requestId;
|
|
10637
|
+
const sent = sendMessage({ type: "quarto_preview_start_request", requestId, sourcePath });
|
|
10638
|
+
if (!sent) quartoPreviewActionRequestId = null;
|
|
10639
|
+
renderQuartoPreviewView();
|
|
10640
|
+
if (sent) setStatus("Starting Quarto preview with computational cell execution disabled…", "warning");
|
|
10641
|
+
return sent;
|
|
10642
|
+
}
|
|
10643
|
+
|
|
10644
|
+
function requestStudioQuartoPreviewStop() {
|
|
10645
|
+
if (quartoPreviewActionRequestId) return false;
|
|
10646
|
+
const requestId = makeRequestId();
|
|
10647
|
+
quartoPreviewActionRequestId = requestId;
|
|
10648
|
+
const sent = sendMessage({ type: "quarto_preview_stop_request", requestId });
|
|
10649
|
+
if (!sent) quartoPreviewActionRequestId = null;
|
|
10650
|
+
renderQuartoPreviewView();
|
|
10651
|
+
if (sent) setStatus("Stopping Quarto preview…", "warning");
|
|
10652
|
+
return sent;
|
|
10653
|
+
}
|
|
10654
|
+
|
|
10655
|
+
function openStudioQuartoPreviewInBrowser() {
|
|
10656
|
+
const rawUrl = String(quartoPreviewState.url || "").trim();
|
|
10657
|
+
if (!rawUrl) {
|
|
10658
|
+
setStatus("Quarto preview is not running yet.", "warning");
|
|
10659
|
+
return false;
|
|
10660
|
+
}
|
|
10661
|
+
try {
|
|
10662
|
+
const parsed = new URL(rawUrl);
|
|
10663
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
10664
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("Unsupported preview protocol.");
|
|
10665
|
+
if (hostname !== "127.0.0.1" && hostname !== "localhost" && hostname !== "::1") throw new Error("Preview URL is not loopback-only.");
|
|
10666
|
+
const opened = window.open(parsed.href, "_blank");
|
|
10667
|
+
if (!opened) {
|
|
10668
|
+
setStatus("Browser blocked the Quarto preview tab. Allow pop-ups and try again.", "warning");
|
|
10669
|
+
return false;
|
|
10670
|
+
}
|
|
10671
|
+
try { opened.opener = null; } catch {}
|
|
10672
|
+
setStatus("Opening Quarto preview in a browser tab.", "success");
|
|
10673
|
+
return true;
|
|
10674
|
+
} catch (error) {
|
|
10675
|
+
setStatus("Could not open Quarto preview: " + ((error && error.message) ? error.message : String(error)), "error");
|
|
10676
|
+
return false;
|
|
10677
|
+
}
|
|
10678
|
+
}
|
|
10679
|
+
|
|
10680
|
+
function openStudioQuartoInstallationInstructions() {
|
|
10681
|
+
try {
|
|
10682
|
+
const opened = window.open("https://quarto.org/docs/get-started/", "_blank");
|
|
10683
|
+
if (!opened) {
|
|
10684
|
+
setStatus("Browser blocked the Quarto installation page.", "warning");
|
|
10685
|
+
return;
|
|
10686
|
+
}
|
|
10687
|
+
try { opened.opener = null; } catch {}
|
|
10688
|
+
} catch (error) {
|
|
10689
|
+
setStatus("Could not open Quarto installation instructions.", "warning");
|
|
10690
|
+
}
|
|
10691
|
+
}
|
|
10692
|
+
|
|
10693
|
+
function buildStudioQuartoLogDetails(log, open) {
|
|
10694
|
+
const text = String(log || "").trim();
|
|
10695
|
+
if (!text) return "";
|
|
10696
|
+
return "<details class='quarto-preview-log-details'" + (open ? " open" : "") + ">"
|
|
10697
|
+
+ "<summary>Quarto log</summary>"
|
|
10698
|
+
+ "<pre>" + escapeHtml(text) + "</pre>"
|
|
10699
|
+
+ "</details>";
|
|
10700
|
+
}
|
|
10701
|
+
|
|
10702
|
+
function buildStudioQuartoContextSummary(context) {
|
|
10703
|
+
if (!context) return "Quarto document";
|
|
10704
|
+
const kind = context.isProject
|
|
10705
|
+
? (context.projectType ? (context.projectType.charAt(0).toUpperCase() + context.projectType.slice(1) + " project") : "Quarto project")
|
|
10706
|
+
: "Standalone document";
|
|
10707
|
+
return kind + (context.version ? " · Quarto " + context.version : "");
|
|
10708
|
+
}
|
|
10709
|
+
|
|
10710
|
+
function updateStudioQuartoRunningShell() {
|
|
10711
|
+
const context = getCurrentStudioQuartoContext() || quartoPreviewState.context;
|
|
10712
|
+
const url = String(quartoPreviewState.url || "");
|
|
10713
|
+
let shell = critiqueViewEl ? critiqueViewEl.querySelector(".quarto-preview-shell[data-preview-url]") : null;
|
|
10714
|
+
if (!shell || shell.getAttribute("data-preview-url") !== url) {
|
|
10715
|
+
const label = context && context.projectLabel ? context.projectLabel : (sourceState.label || "Quarto document");
|
|
10716
|
+
critiqueViewEl.innerHTML = ""
|
|
10717
|
+
+ "<div class='quarto-preview-shell' data-preview-url='" + escapeHtml(url) + "'>"
|
|
10718
|
+
+ "<div class='quarto-preview-toolbar'>"
|
|
10719
|
+
+ "<div class='quarto-preview-title-group'>"
|
|
10720
|
+
+ "<span class='quarto-preview-title'>" + escapeHtml(label) + "</span>"
|
|
10721
|
+
+ "<span class='quarto-preview-subtitle'>" + escapeHtml(buildStudioQuartoContextSummary(context)) + "</span>"
|
|
10722
|
+
+ "</div>"
|
|
10723
|
+
+ "<div class='quarto-preview-actions'>"
|
|
10724
|
+
+ "<button type='button' data-quarto-action='open'>Open in browser ↗</button>"
|
|
10725
|
+
+ "<button type='button' data-quarto-action='restart'>Restart</button>"
|
|
10726
|
+
+ "<button type='button' data-quarto-action='toggle-log'>Show log</button>"
|
|
10727
|
+
+ "<button type='button' data-quarto-action='stop'>Stop</button>"
|
|
10728
|
+
+ "</div>"
|
|
10729
|
+
+ "</div>"
|
|
10730
|
+
+ "<div class='quarto-preview-dirty-warning' hidden>Unsaved editor changes are not included. Save the editor to update Quarto.</div>"
|
|
10731
|
+
+ "<iframe class='quarto-preview-frame' src='" + escapeHtml(url) + "' title='Quarto preview for " + escapeHtml(label) + "' sandbox='allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads' allow='clipboard-write; fullscreen' allowfullscreen referrerpolicy='no-referrer'></iframe>"
|
|
10732
|
+
+ "<div class='quarto-preview-live-log' hidden><pre></pre></div>"
|
|
10733
|
+
+ "</div>";
|
|
10734
|
+
shell = critiqueViewEl.querySelector(".quarto-preview-shell[data-preview-url]");
|
|
10735
|
+
}
|
|
10736
|
+
const warningEl = shell ? shell.querySelector(".quarto-preview-dirty-warning") : null;
|
|
10737
|
+
if (warningEl) warningEl.hidden = !isStudioQuartoEditorDirty();
|
|
10738
|
+
const logPanelEl = shell ? shell.querySelector(".quarto-preview-live-log") : null;
|
|
10739
|
+
const logPreEl = logPanelEl ? logPanelEl.querySelector("pre") : null;
|
|
10740
|
+
if (logPanelEl) logPanelEl.hidden = !quartoPreviewLogVisible;
|
|
10741
|
+
if (logPreEl && logPreEl.textContent !== quartoPreviewState.log) logPreEl.textContent = quartoPreviewState.log;
|
|
10742
|
+
const toggleLogBtn = shell ? shell.querySelector("[data-quarto-action='toggle-log']") : null;
|
|
10743
|
+
if (toggleLogBtn) toggleLogBtn.textContent = quartoPreviewLogVisible ? "Hide log" : "Show log";
|
|
10744
|
+
if (shell) {
|
|
10745
|
+
shell.querySelectorAll("button[data-quarto-action]").forEach((button) => {
|
|
10746
|
+
if (button.getAttribute("data-quarto-action") === "open" || button.getAttribute("data-quarto-action") === "toggle-log") return;
|
|
10747
|
+
button.disabled = Boolean(quartoPreviewActionRequestId);
|
|
10748
|
+
});
|
|
10749
|
+
}
|
|
10750
|
+
}
|
|
10751
|
+
|
|
10752
|
+
function renderQuartoPreviewView() {
|
|
10753
|
+
if (!critiqueViewEl) return;
|
|
10754
|
+
finishPreviewRender(critiqueViewEl);
|
|
10755
|
+
if (!isCurrentStudioQuartoDocument()) {
|
|
10756
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card'><h2>Quarto preview unavailable</h2><p>Open a file-backed <code>.qmd</code>, <code>.md</code>, or <code>.markdown</code> document to use this view.</p></div>";
|
|
10757
|
+
return;
|
|
10758
|
+
}
|
|
10759
|
+
|
|
10760
|
+
const current = getStudioQuartoProcessStatusForCurrentSource();
|
|
10761
|
+
const context = getCurrentStudioQuartoContext();
|
|
10762
|
+
const checking = Boolean(quartoPreviewCheckRequestId && studioQuartoPathsMatch(quartoPreviewCheckSourcePath, current.sourcePath));
|
|
10763
|
+
const actionPending = Boolean(quartoPreviewActionRequestId);
|
|
10764
|
+
if (current.sameSource && current.status === "running" && quartoPreviewState.url) {
|
|
10765
|
+
updateStudioQuartoRunningShell();
|
|
10766
|
+
return;
|
|
10767
|
+
}
|
|
10768
|
+
|
|
10769
|
+
if (checking && !context) {
|
|
10770
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card quarto-preview-card-centered'>"
|
|
10771
|
+
+ "<div class='quarto-preview-spinner' aria-hidden='true'></div>"
|
|
10772
|
+
+ "<h2>Checking Quarto…</h2>"
|
|
10773
|
+
+ "<p>Inspecting the saved document and its project configuration.</p>"
|
|
10774
|
+
+ "</div>";
|
|
10775
|
+
return;
|
|
10776
|
+
}
|
|
10777
|
+
|
|
10778
|
+
if (!context) {
|
|
10779
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card quarto-preview-card-centered'>"
|
|
10780
|
+
+ "<h2>Editor (Quarto Preview)</h2>"
|
|
10781
|
+
+ "<p>Check the installed Quarto version and this saved document before starting a preview.</p>"
|
|
10782
|
+
+ "<div class='quarto-preview-card-actions'><button type='button' data-quarto-action='check'>Check Quarto</button></div>"
|
|
10783
|
+
+ "</div>";
|
|
10784
|
+
return;
|
|
10785
|
+
}
|
|
10786
|
+
|
|
10787
|
+
if (!context.available) {
|
|
10788
|
+
const missing = context.reason === "not-found";
|
|
10789
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card quarto-preview-card-centered'>"
|
|
10790
|
+
+ "<h2>" + (missing ? "Quarto not found" : "Quarto preview unavailable") + "</h2>"
|
|
10791
|
+
+ "<p>" + escapeHtml(context.error || "Studio could not inspect this Quarto document.") + "</p>"
|
|
10792
|
+
+ (missing ? "<p class='quarto-preview-note'>Studio could not find <code>quarto</code> on its PATH.</p>" : "")
|
|
10793
|
+
+ "<div class='quarto-preview-card-actions'>"
|
|
10794
|
+
+ "<button type='button' data-quarto-action='check'>Check again</button>"
|
|
10795
|
+
+ (missing ? "<button type='button' data-quarto-action='install'>Installation instructions ↗</button>" : "")
|
|
10796
|
+
+ "</div>"
|
|
10797
|
+
+ buildStudioQuartoLogDetails(context.inspectLog, true)
|
|
10798
|
+
+ "</div>";
|
|
10799
|
+
return;
|
|
10800
|
+
}
|
|
10801
|
+
|
|
10802
|
+
const runningAnother = !current.sameSource && (current.status === "running" || current.status === "starting" || current.status === "stopping");
|
|
10803
|
+
const dirtyWarning = isStudioQuartoEditorDirty()
|
|
10804
|
+
? "<div class='quarto-preview-dirty-warning'>Unsaved editor changes are not included. Save before starting or refreshing Quarto.</div>"
|
|
10805
|
+
: "";
|
|
10806
|
+
if (current.sameSource && (current.status === "starting" || current.status === "stopping")) {
|
|
10807
|
+
const stopping = current.status === "stopping";
|
|
10808
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card quarto-preview-card-centered'>"
|
|
10809
|
+
+ "<div class='quarto-preview-spinner' aria-hidden='true'></div>"
|
|
10810
|
+
+ "<h2>" + (stopping ? "Stopping Quarto preview…" : "Starting Quarto preview…") + "</h2>"
|
|
10811
|
+
+ "<p>" + escapeHtml(buildStudioQuartoContextSummary(context)) + " · computational cells will not be executed.</p>"
|
|
10812
|
+
+ dirtyWarning
|
|
10813
|
+
+ (!stopping ? "<div class='quarto-preview-card-actions'><button type='button' data-quarto-action='stop'" + (actionPending ? " disabled" : "") + ">Stop</button></div>" : "")
|
|
10814
|
+
+ buildStudioQuartoLogDetails(quartoPreviewState.log, true)
|
|
10815
|
+
+ "</div>";
|
|
10816
|
+
return;
|
|
10817
|
+
}
|
|
10818
|
+
|
|
10819
|
+
const sameSourceError = current.sameSource && current.status === "error";
|
|
10820
|
+
const label = context.projectLabel || sourceState.label || "Quarto document";
|
|
10821
|
+
critiqueViewEl.innerHTML = "<div class='quarto-preview-card quarto-preview-card-centered'>"
|
|
10822
|
+
+ "<h2>" + (sameSourceError ? "Quarto preview stopped with an error" : "Ready to preview with Quarto") + "</h2>"
|
|
10823
|
+
+ "<p><strong>" + escapeHtml(label) + "</strong><br>" + escapeHtml(buildStudioQuartoContextSummary(context)) + "</p>"
|
|
10824
|
+
+ (sameSourceError ? "<div class='quarto-preview-error'>" + escapeHtml(quartoPreviewState.error || "Quarto preview failed.") + "</div>" : "")
|
|
10825
|
+
+ (runningAnother ? "<div class='quarto-preview-note'>Another Quarto document is currently being previewed. Starting this one will replace it.</div>" : "")
|
|
10826
|
+
+ dirtyWarning
|
|
10827
|
+
+ "<div class='quarto-preview-safety-note'><strong>Saved-file preview.</strong> Studio starts Quarto on <code>127.0.0.1</code> with <code>--no-execute</code>, so computational cells are not run. Quarto still processes the project's trusted configuration, extensions, filters, and render hooks, controls the page styling, and may create or update its normal rendered output files.</div>"
|
|
10828
|
+
+ "<div class='quarto-preview-card-actions'>"
|
|
10829
|
+
+ "<button type='button' class='quarto-preview-primary' data-quarto-action='start'" + (actionPending ? " disabled" : "") + ">" + (sameSourceError ? "Retry Quarto preview" : (runningAnother ? "Preview this document" : "Start Quarto preview")) + "</button>"
|
|
10830
|
+
+ (runningAnother && quartoPreviewState.url ? "<button type='button' data-quarto-action='open'>Open running preview ↗</button>" : "")
|
|
10831
|
+
+ (runningAnother ? "<button type='button' data-quarto-action='stop'" + (actionPending ? " disabled" : "") + ">Stop running preview</button>" : "")
|
|
10832
|
+
+ "</div>"
|
|
10833
|
+
+ buildStudioQuartoLogDetails(sameSourceError ? quartoPreviewState.log : context.inspectLog, sameSourceError)
|
|
10834
|
+
+ "</div>";
|
|
10835
|
+
}
|
|
10836
|
+
|
|
10837
|
+
function syncStudioQuartoDirtyUi() {
|
|
10838
|
+
if (rightView !== "editor-quarto-preview") return;
|
|
10839
|
+
const warningEl = critiqueViewEl ? critiqueViewEl.querySelector(".quarto-preview-dirty-warning") : null;
|
|
10840
|
+
if (warningEl && warningEl.classList && warningEl.closest(".quarto-preview-shell")) {
|
|
10841
|
+
warningEl.hidden = !isStudioQuartoEditorDirty();
|
|
10842
|
+
}
|
|
10843
|
+
updateReferenceBadge();
|
|
10844
|
+
}
|
|
10845
|
+
|
|
10846
|
+
function handleStudioQuartoPreviewClick(event) {
|
|
10847
|
+
if (rightView !== "editor-quarto-preview") return;
|
|
10848
|
+
const target = event && event.target instanceof Element ? event.target.closest("[data-quarto-action]") : null;
|
|
10849
|
+
if (!target || !critiqueViewEl.contains(target)) return;
|
|
10850
|
+
event.preventDefault();
|
|
10851
|
+
const action = target.getAttribute("data-quarto-action");
|
|
10852
|
+
if (action === "check") {
|
|
10853
|
+
requestStudioQuartoPreviewCheck(true);
|
|
10854
|
+
} else if (action === "start" || action === "restart") {
|
|
10855
|
+
requestStudioQuartoPreviewStart();
|
|
10856
|
+
} else if (action === "stop") {
|
|
10857
|
+
requestStudioQuartoPreviewStop();
|
|
10858
|
+
} else if (action === "open") {
|
|
10859
|
+
openStudioQuartoPreviewInBrowser();
|
|
10860
|
+
} else if (action === "install") {
|
|
10861
|
+
openStudioQuartoInstallationInstructions();
|
|
10862
|
+
} else if (action === "toggle-log") {
|
|
10863
|
+
quartoPreviewLogVisible = !quartoPreviewLogVisible;
|
|
10864
|
+
updateStudioQuartoRunningShell();
|
|
10865
|
+
}
|
|
10866
|
+
}
|
|
10867
|
+
|
|
10551
10868
|
function renderActiveResult() {
|
|
10552
|
-
if (critiqueViewEl)
|
|
10869
|
+
if (critiqueViewEl) {
|
|
10870
|
+
critiqueViewEl.classList.toggle("git-changes-host", rightView === "changes");
|
|
10871
|
+
critiqueViewEl.classList.toggle("quarto-preview-host", rightView === "editor-quarto-preview");
|
|
10872
|
+
}
|
|
10873
|
+
if (rightView === "editor-quarto-preview") {
|
|
10874
|
+
renderQuartoPreviewView();
|
|
10875
|
+
return;
|
|
10876
|
+
}
|
|
10553
10877
|
if (rightView === "trace") {
|
|
10554
10878
|
renderTraceView();
|
|
10555
10879
|
return;
|
|
@@ -10648,7 +10972,7 @@
|
|
|
10648
10972
|
: normalizeForCompare(sourceTextEl.value);
|
|
10649
10973
|
const responseLoaded = hasResponse && normalizedEditor === latestResponseNormalized;
|
|
10650
10974
|
const isCritiqueResponse = hasResponse && latestResponseIsStructuredCritique;
|
|
10651
|
-
const showingAuxiliaryRightPane = rightView === "trace" || rightView === "repl" || rightView === "files" || rightView === "changes";
|
|
10975
|
+
const showingAuxiliaryRightPane = rightView === "trace" || rightView === "repl" || rightView === "files" || rightView === "changes" || rightView === "editor-quarto-preview";
|
|
10652
10976
|
|
|
10653
10977
|
if (responseWrapEl) {
|
|
10654
10978
|
responseWrapEl.hidden = showingAuxiliaryRightPane;
|
|
@@ -10732,6 +11056,7 @@
|
|
|
10732
11056
|
: (exportingReplJournal ? "Export the Studio REPL record as standalone HTML and open it in the default browser." : "Export the current right-pane preview as standalone HTML and open it in the default browser.");
|
|
10733
11057
|
}
|
|
10734
11058
|
if (exportPreviewControlsEl) {
|
|
11059
|
+
exportPreviewControlsEl.hidden = rightView === "editor-quarto-preview";
|
|
10735
11060
|
exportPreviewControlsEl.title = canExportPreview
|
|
10736
11061
|
? (exportingReplJournal
|
|
10737
11062
|
? "Choose a format and export destination for the Studio REPL record."
|
|
@@ -10746,6 +11071,7 @@
|
|
|
10746
11071
|
pullLatestBtn.textContent = queuedLatestResponse ? "Fetch latest response *" : "Fetch latest response";
|
|
10747
11072
|
|
|
10748
11073
|
updateSyncBadge(normalizedEditor);
|
|
11074
|
+
syncStudioQuartoDirtyUi();
|
|
10749
11075
|
}
|
|
10750
11076
|
|
|
10751
11077
|
function refreshResponseUi() {
|
|
@@ -10802,6 +11128,86 @@
|
|
|
10802
11128
|
return null;
|
|
10803
11129
|
}
|
|
10804
11130
|
|
|
11131
|
+
function normalizeStudioQuartoClientPath(value) {
|
|
11132
|
+
const normalized = String(value || "").trim().replace(/\\/g, "/").replace(/\/+$/, "");
|
|
11133
|
+
return /^[A-Za-z]:\//.test(normalized) ? normalized.toLowerCase() : normalized;
|
|
11134
|
+
}
|
|
11135
|
+
|
|
11136
|
+
function getCurrentStudioQuartoSourcePath() {
|
|
11137
|
+
return sourceState && typeof sourceState.path === "string" ? sourceState.path.trim() : "";
|
|
11138
|
+
}
|
|
11139
|
+
|
|
11140
|
+
function isCurrentStudioQuartoDocument() {
|
|
11141
|
+
return /\.(?:qmd|md|markdown)$/i.test(getCurrentStudioQuartoSourcePath());
|
|
11142
|
+
}
|
|
11143
|
+
|
|
11144
|
+
function studioQuartoPathsMatch(left, right) {
|
|
11145
|
+
const a = normalizeStudioQuartoClientPath(left);
|
|
11146
|
+
const b = normalizeStudioQuartoClientPath(right);
|
|
11147
|
+
return Boolean(a && b && a === b);
|
|
11148
|
+
}
|
|
11149
|
+
|
|
11150
|
+
function normalizeStudioQuartoContext(value) {
|
|
11151
|
+
if (!value || typeof value !== "object") return null;
|
|
11152
|
+
return {
|
|
11153
|
+
sourcePath: typeof value.sourcePath === "string" ? value.sourcePath : "",
|
|
11154
|
+
requestedSourcePath: typeof value.requestedSourcePath === "string" ? value.requestedSourcePath : (typeof value.sourcePath === "string" ? value.sourcePath : ""),
|
|
11155
|
+
available: value.available === true,
|
|
11156
|
+
reason: typeof value.reason === "string" ? value.reason : "inspect-error",
|
|
11157
|
+
version: typeof value.version === "string" ? value.version : "",
|
|
11158
|
+
projectRoot: typeof value.projectRoot === "string" ? value.projectRoot : "",
|
|
11159
|
+
projectType: typeof value.projectType === "string" ? value.projectType : "",
|
|
11160
|
+
projectLabel: typeof value.projectLabel === "string" ? value.projectLabel : "Quarto document",
|
|
11161
|
+
outputFile: typeof value.outputFile === "string" ? value.outputFile : "",
|
|
11162
|
+
isProject: value.isProject === true,
|
|
11163
|
+
error: typeof value.error === "string" && value.error ? value.error : null,
|
|
11164
|
+
inspectLog: typeof value.inspectLog === "string" ? value.inspectLog : "",
|
|
11165
|
+
};
|
|
11166
|
+
}
|
|
11167
|
+
|
|
11168
|
+
function normalizeStudioQuartoPreviewState(value) {
|
|
11169
|
+
if (!value || typeof value !== "object") return {
|
|
11170
|
+
status: "idle",
|
|
11171
|
+
sourcePath: "",
|
|
11172
|
+
url: "",
|
|
11173
|
+
log: "",
|
|
11174
|
+
error: null,
|
|
11175
|
+
context: null,
|
|
11176
|
+
startedAt: null,
|
|
11177
|
+
updatedAt: 0,
|
|
11178
|
+
actionRequestId: null,
|
|
11179
|
+
};
|
|
11180
|
+
const allowedStatuses = new Set(["idle", "starting", "running", "stopping", "stopped", "error"]);
|
|
11181
|
+
return {
|
|
11182
|
+
status: allowedStatuses.has(value.status) ? value.status : "idle",
|
|
11183
|
+
sourcePath: typeof value.sourcePath === "string" ? value.sourcePath : "",
|
|
11184
|
+
url: typeof value.url === "string" ? value.url : "",
|
|
11185
|
+
log: typeof value.log === "string" ? value.log : "",
|
|
11186
|
+
error: typeof value.error === "string" && value.error ? value.error : null,
|
|
11187
|
+
context: normalizeStudioQuartoContext(value.context),
|
|
11188
|
+
startedAt: typeof value.startedAt === "number" && Number.isFinite(value.startedAt) ? value.startedAt : null,
|
|
11189
|
+
updatedAt: typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt) ? value.updatedAt : 0,
|
|
11190
|
+
actionRequestId: typeof value.actionRequestId === "string" ? value.actionRequestId : null,
|
|
11191
|
+
};
|
|
11192
|
+
}
|
|
11193
|
+
|
|
11194
|
+
function getCurrentStudioQuartoContext() {
|
|
11195
|
+
const sourcePath = getCurrentStudioQuartoSourcePath();
|
|
11196
|
+
if (quartoPreviewContext && (
|
|
11197
|
+
studioQuartoPathsMatch(quartoPreviewContext.sourcePath, sourcePath)
|
|
11198
|
+
|| studioQuartoPathsMatch(quartoPreviewContext.requestedSourcePath, sourcePath)
|
|
11199
|
+
)) {
|
|
11200
|
+
return quartoPreviewContext;
|
|
11201
|
+
}
|
|
11202
|
+
if (quartoPreviewState.context && (
|
|
11203
|
+
studioQuartoPathsMatch(quartoPreviewState.context.sourcePath, sourcePath)
|
|
11204
|
+
|| studioQuartoPathsMatch(quartoPreviewState.context.requestedSourcePath, sourcePath)
|
|
11205
|
+
)) {
|
|
11206
|
+
return quartoPreviewState.context;
|
|
11207
|
+
}
|
|
11208
|
+
return null;
|
|
11209
|
+
}
|
|
11210
|
+
|
|
10805
11211
|
function getHtmlPreviewResourceContextOptions() {
|
|
10806
11212
|
const sourcePath = getEffectiveSavePath() || sourceState.path || "";
|
|
10807
11213
|
const resourceDir = getCurrentResourceDirValue();
|
|
@@ -10917,6 +11323,7 @@
|
|
|
10917
11323
|
|
|
10918
11324
|
function setSourceState(next, options) {
|
|
10919
11325
|
const previousDescriptor = getCurrentStudioDocumentDescriptor();
|
|
11326
|
+
const previousQuartoPath = getCurrentStudioQuartoSourcePath();
|
|
10920
11327
|
const nextPath = next && next.path ? next.path : null;
|
|
10921
11328
|
sourceState = {
|
|
10922
11329
|
source: next && next.source ? next.source : "blank",
|
|
@@ -10926,9 +11333,24 @@
|
|
|
10926
11333
|
? null
|
|
10927
11334
|
: (next && next.draftId ? next.draftId : makeStudioDraftId()),
|
|
10928
11335
|
};
|
|
11336
|
+
const nextQuartoPath = getCurrentStudioQuartoSourcePath();
|
|
11337
|
+
const quartoSourceChanged = !studioQuartoPathsMatch(previousQuartoPath, nextQuartoPath);
|
|
11338
|
+
if (quartoSourceChanged) {
|
|
11339
|
+
quartoPreviewContext = null;
|
|
11340
|
+
quartoPreviewCheckRequestId = null;
|
|
11341
|
+
quartoPreviewCheckSourcePath = "";
|
|
11342
|
+
quartoPreviewActionRequestId = null;
|
|
11343
|
+
quartoPreviewLogVisible = false;
|
|
11344
|
+
}
|
|
10929
11345
|
if (!sourceState.path) {
|
|
10930
11346
|
clearFileBackedBaseline();
|
|
10931
11347
|
}
|
|
11348
|
+
syncRightViewModeOptions();
|
|
11349
|
+
const leavingUnavailableQuartoView = rightView === "editor-quarto-preview" && !isCurrentStudioQuartoDocument();
|
|
11350
|
+
if (leavingUnavailableQuartoView) {
|
|
11351
|
+
rightView = "editor-preview";
|
|
11352
|
+
rightViewSelect.value = rightView;
|
|
11353
|
+
}
|
|
10932
11354
|
updateStudioDocumentUrlState(sourceState);
|
|
10933
11355
|
updateSourceBadge();
|
|
10934
11356
|
syncActionButtons();
|
|
@@ -10942,6 +11364,9 @@
|
|
|
10942
11364
|
previousDescriptor: previousDescriptor,
|
|
10943
11365
|
carryCurrentMetadataToNewDocument: Boolean(options && options.carryCurrentMetadataToNewDocument),
|
|
10944
11366
|
});
|
|
11367
|
+
const refreshChangedQuartoView = rightView === "editor-quarto-preview" && quartoSourceChanged && isCurrentStudioQuartoDocument();
|
|
11368
|
+
if (refreshChangedQuartoView) requestStudioQuartoPreviewCheck(false);
|
|
11369
|
+
if (leavingUnavailableQuartoView || refreshChangedQuartoView) refreshResponseUi();
|
|
10945
11370
|
scheduleWorkspacePersistence();
|
|
10946
11371
|
}
|
|
10947
11372
|
|
|
@@ -11759,6 +12184,9 @@
|
|
|
11759
12184
|
if (rightView !== "editor-preview") {
|
|
11760
12185
|
clearPreviewJumpHighlight(critiqueViewEl);
|
|
11761
12186
|
}
|
|
12187
|
+
if (rightView === "editor-quarto-preview") {
|
|
12188
|
+
requestStudioQuartoPreviewCheck(false);
|
|
12189
|
+
}
|
|
11762
12190
|
|
|
11763
12191
|
refreshResponseUi();
|
|
11764
12192
|
syncActionButtons();
|
|
@@ -19038,6 +19466,80 @@
|
|
|
19038
19466
|
return;
|
|
19039
19467
|
}
|
|
19040
19468
|
|
|
19469
|
+
if (message.type === "quarto_preview_context") {
|
|
19470
|
+
const requestId = typeof message.requestId === "string" ? message.requestId : "";
|
|
19471
|
+
const context = normalizeStudioQuartoContext(message.context);
|
|
19472
|
+
const matchesCheck = Boolean(requestId && quartoPreviewCheckRequestId === requestId);
|
|
19473
|
+
const matchesAction = Boolean(requestId && quartoPreviewActionRequestId === requestId);
|
|
19474
|
+
if (!matchesCheck && !matchesAction) return;
|
|
19475
|
+
if (matchesCheck) {
|
|
19476
|
+
quartoPreviewCheckRequestId = null;
|
|
19477
|
+
quartoPreviewCheckSourcePath = "";
|
|
19478
|
+
}
|
|
19479
|
+
if (context) quartoPreviewContext = context;
|
|
19480
|
+
if (matchesAction && (!context || !context.available)) {
|
|
19481
|
+
quartoPreviewActionRequestId = null;
|
|
19482
|
+
}
|
|
19483
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
19484
|
+
updateReferenceBadge();
|
|
19485
|
+
return;
|
|
19486
|
+
}
|
|
19487
|
+
|
|
19488
|
+
if (message.type === "quarto_preview_state") {
|
|
19489
|
+
const previousQuartoStatus = quartoPreviewState.status;
|
|
19490
|
+
quartoPreviewState = normalizeStudioQuartoPreviewState(message.preview);
|
|
19491
|
+
if (quartoPreviewState.actionRequestId && quartoPreviewActionRequestId === quartoPreviewState.actionRequestId) {
|
|
19492
|
+
quartoPreviewActionRequestId = null;
|
|
19493
|
+
}
|
|
19494
|
+
if (quartoPreviewState.context && (
|
|
19495
|
+
studioQuartoPathsMatch(quartoPreviewState.context.sourcePath, getCurrentStudioQuartoSourcePath())
|
|
19496
|
+
|| studioQuartoPathsMatch(quartoPreviewState.context.requestedSourcePath, getCurrentStudioQuartoSourcePath())
|
|
19497
|
+
)) {
|
|
19498
|
+
quartoPreviewContext = quartoPreviewState.context;
|
|
19499
|
+
}
|
|
19500
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
19501
|
+
updateReferenceBadge();
|
|
19502
|
+
syncActionButtons();
|
|
19503
|
+
if (quartoPreviewState.status !== previousQuartoStatus) {
|
|
19504
|
+
if (quartoPreviewState.status === "running") {
|
|
19505
|
+
setStatus("Quarto preview is running with computational cell execution disabled.", "success");
|
|
19506
|
+
} else if (quartoPreviewState.status === "error" && quartoPreviewState.error) {
|
|
19507
|
+
setStatus(quartoPreviewState.error, "error");
|
|
19508
|
+
} else if (quartoPreviewState.status === "stopped") {
|
|
19509
|
+
setStatus("Quarto preview stopped.");
|
|
19510
|
+
}
|
|
19511
|
+
}
|
|
19512
|
+
return;
|
|
19513
|
+
}
|
|
19514
|
+
|
|
19515
|
+
if (message.type === "quarto_preview_action_error") {
|
|
19516
|
+
const requestId = typeof message.requestId === "string" ? message.requestId : "";
|
|
19517
|
+
if (requestId && quartoPreviewCheckRequestId === requestId) {
|
|
19518
|
+
quartoPreviewCheckRequestId = null;
|
|
19519
|
+
quartoPreviewCheckSourcePath = "";
|
|
19520
|
+
}
|
|
19521
|
+
if (requestId && quartoPreviewActionRequestId === requestId) quartoPreviewActionRequestId = null;
|
|
19522
|
+
const messageText = typeof message.message === "string" ? message.message : "Quarto preview request failed.";
|
|
19523
|
+
quartoPreviewContext = {
|
|
19524
|
+
sourcePath: getCurrentStudioQuartoSourcePath(),
|
|
19525
|
+
requestedSourcePath: getCurrentStudioQuartoSourcePath(),
|
|
19526
|
+
available: false,
|
|
19527
|
+
reason: "inspect-error",
|
|
19528
|
+
version: "",
|
|
19529
|
+
projectRoot: "",
|
|
19530
|
+
projectType: "",
|
|
19531
|
+
projectLabel: sourceState.label || "Quarto document",
|
|
19532
|
+
outputFile: "",
|
|
19533
|
+
isProject: false,
|
|
19534
|
+
error: messageText,
|
|
19535
|
+
inspectLog: "",
|
|
19536
|
+
};
|
|
19537
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
19538
|
+
updateReferenceBadge();
|
|
19539
|
+
setStatus(messageText, "error");
|
|
19540
|
+
return;
|
|
19541
|
+
}
|
|
19542
|
+
|
|
19041
19543
|
if (message.type === "hello_ack") {
|
|
19042
19544
|
const busy = Boolean(message.busy);
|
|
19043
19545
|
agentBusyFromServer = Boolean(message.agentBusy);
|
|
@@ -19050,6 +19552,15 @@
|
|
|
19050
19552
|
}
|
|
19051
19553
|
updatePiSessionModelState(message);
|
|
19052
19554
|
updatePiThemeState(message);
|
|
19555
|
+
if (message.quartoPreview && typeof message.quartoPreview === "object") {
|
|
19556
|
+
quartoPreviewState = normalizeStudioQuartoPreviewState(message.quartoPreview);
|
|
19557
|
+
if (quartoPreviewState.context && (
|
|
19558
|
+
studioQuartoPathsMatch(quartoPreviewState.context.sourcePath, getCurrentStudioQuartoSourcePath())
|
|
19559
|
+
|| studioQuartoPathsMatch(quartoPreviewState.context.requestedSourcePath, getCurrentStudioQuartoSourcePath())
|
|
19560
|
+
)) {
|
|
19561
|
+
quartoPreviewContext = quartoPreviewState.context;
|
|
19562
|
+
}
|
|
19563
|
+
}
|
|
19053
19564
|
if (typeof message.terminalSessionLabel === "string") {
|
|
19054
19565
|
terminalSessionLabel = message.terminalSessionLabel;
|
|
19055
19566
|
}
|
|
@@ -19130,6 +19641,11 @@
|
|
|
19130
19641
|
handleIncomingResponse(lastMarkdown, lastResponseKind, message.lastResponse.timestamp, message.lastResponse.thinking);
|
|
19131
19642
|
}
|
|
19132
19643
|
|
|
19644
|
+
if (rightView === "editor-quarto-preview") {
|
|
19645
|
+
requestStudioQuartoPreviewCheck(false);
|
|
19646
|
+
renderQuartoPreviewView();
|
|
19647
|
+
}
|
|
19648
|
+
|
|
19133
19649
|
if (pendingRequestId) {
|
|
19134
19650
|
if (busy) {
|
|
19135
19651
|
setStatus(getStudioBusyStatus(pendingKind), "warning");
|
|
@@ -19840,6 +20356,10 @@
|
|
|
19840
20356
|
if (ws === socket) {
|
|
19841
20357
|
ws = null;
|
|
19842
20358
|
}
|
|
20359
|
+
quartoPreviewCheckRequestId = null;
|
|
20360
|
+
quartoPreviewCheckSourcePath = "";
|
|
20361
|
+
quartoPreviewActionRequestId = null;
|
|
20362
|
+
if (rightView === "editor-quarto-preview") renderQuartoPreviewView();
|
|
19843
20363
|
setBusy(true);
|
|
19844
20364
|
|
|
19845
20365
|
if (kind === "invalidated") {
|
|
@@ -21295,6 +21815,7 @@
|
|
|
21295
21815
|
resourceDirInput.value = normalizeStudioResourceDirValue(initialResourceDir);
|
|
21296
21816
|
}
|
|
21297
21817
|
setSourceState(initialSourceState);
|
|
21818
|
+
if (initialSourceState.path) markFileBackedBaseline(sourceTextEl.value);
|
|
21298
21819
|
refreshResponseUi();
|
|
21299
21820
|
updateAnnotatedReplyHeaderButton();
|
|
21300
21821
|
setActivePane("left");
|