pi-studio 0.9.61 → 0.9.62

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 CHANGED
@@ -4,6 +4,14 @@ All notable changes to `pi-studio` are documented here.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.62] — 2026-10-08
8
+
9
+ ### Fixed
10
+ - With syntax highlighting on, the cursor could end up several characters away from the text being typed, mostly in Safari and other WebKit browsers such as Muxy and cmux. It happened when an edit let a word move back up a line. The editor now re-lays out its text after each edit, so the cursor and text stay together. A line that is exactly full can still show a brief mismatch, which corrects itself on the next key.
11
+
12
+ ### Added
13
+ - `Ctrl+Shift+H` toggles syntax highlighting without leaving the editor.
14
+
7
15
  ## [0.9.61] — 2026-09-30
8
16
 
9
17
  ### Fixed
@@ -2587,6 +2587,7 @@
2587
2587
  let pendingResponseScrollReset = false;
2588
2588
  let editorMetaUpdateRaf = null;
2589
2589
  let editorHighlightEnabled = false;
2590
+ let editorWrapCompositionActive = false;
2590
2591
  let editorLanguage = "markdown";
2591
2592
  let responseHighlightEnabled = false;
2592
2593
  let completionSuggestionState = null;
@@ -17999,6 +18000,40 @@
17999
18000
  return EXT_TO_LANG[ext] || "";
18000
18001
  }
18001
18002
 
18003
+ function repairEditorTextareaWrap(event) {
18004
+ if (!editorHighlightEnabled || editorView !== "markdown" || editorWrapCompositionActive || event?.isComposing) return false;
18005
+ // WebKit can keep the previous soft-wrap layout after a native edit,
18006
+ // while the rebuilt overlay has already moved a word onto its prior line.
18007
+ // Force both layouts without replacing text or touching native undo/IME.
18008
+ const width = sourceTextEl.style.width;
18009
+ const priority = sourceTextEl.style.getPropertyPriority("width");
18010
+ const top = sourceTextEl.scrollTop, left = sourceTextEl.scrollLeft;
18011
+ try {
18012
+ sourceTextEl.style.setProperty("width", "calc(" + (width || "100%") + " - 1px)", priority);
18013
+ void sourceTextEl.offsetWidth;
18014
+ } finally {
18015
+ if (width) sourceTextEl.style.setProperty("width", width, priority);
18016
+ else sourceTextEl.style.removeProperty("width");
18017
+ void sourceTextEl.offsetWidth;
18018
+ sourceTextEl.scrollTop = top; sourceTextEl.scrollLeft = left;
18019
+ }
18020
+ syncEditorHighlightScroll();
18021
+ return true;
18022
+ }
18023
+
18024
+ function handleEditorHighlightShortcut(event) {
18025
+ if (!event || event.defaultPrevented || event.isComposing || editorWrapCompositionActive || event.target !== sourceTextEl
18026
+ || editorView !== "markdown" || sourceTextEl.disabled || sourceTextEl.readOnly || studioModalBlocksDraftAction()
18027
+ || !event.ctrlKey || !event.shiftKey || event.metaKey || event.altKey
18028
+ || !(event.code === "KeyH" || String(event.key || "").toLowerCase() === "h")) return false;
18029
+ event.preventDefault(); event.stopPropagation();
18030
+ if (!event.repeat) {
18031
+ setEditorHighlightEnabled(!editorHighlightEnabled);
18032
+ repairEditorTextareaWrap();
18033
+ }
18034
+ return true;
18035
+ }
18036
+
18002
18037
  function renderEditorHighlightNow() {
18003
18038
  if (!sourceHighlightEl) return;
18004
18039
  if (!editorHighlightEnabled || editorView !== "markdown") {
@@ -24944,8 +24979,15 @@
24944
24979
  });
24945
24980
 
24946
24981
  sourceTextEl.addEventListener("keydown", handleSourceTextTabKey);
24982
+ sourceTextEl.addEventListener("keydown", handleEditorHighlightShortcut);
24983
+ sourceTextEl.addEventListener("compositionstart", () => { editorWrapCompositionActive = true; });
24984
+ sourceTextEl.addEventListener("compositionend", () => {
24985
+ editorWrapCompositionActive = false;
24986
+ repairEditorTextareaWrap();
24987
+ });
24947
24988
 
24948
- sourceTextEl.addEventListener("input", () => {
24989
+ sourceTextEl.addEventListener("input", event => {
24990
+ repairEditorTextareaWrap(event);
24949
24991
  if (completionSuggestionState && sourceTextEl.value !== completionSuggestionState.baseText) {
24950
24992
  hideCompletionSuggestion();
24951
24993
  }
package/index.ts CHANGED
@@ -12515,7 +12515,7 @@ ${cssVarsBlock}
12515
12515
  <button id="showMeResponseBtn" type="button" hidden title="Explain the response displayed in the right pane using the smallest useful visual or structural representation.">Explain displayed response</button>
12516
12516
  <button id="askAsideBtn" type="button" title="Open a separate side-question thread without adding it to the main Pi conversation.">Side question</button>
12517
12517
  <button id="quizBtn" type="button" title="Open an active quiz for the current editor selection or document.">Quiz me</button>
12518
- <select id="highlightSelect" class="studio-flat-select" aria-label="Editor syntax highlighting">
12518
+ <select id="highlightSelect" class="studio-flat-select" aria-label="Editor syntax highlighting" aria-keyshortcuts="Control+Shift+H">
12519
12519
  <option value="off">Syntax highlight: Off</option>
12520
12520
  <option value="bash">Syntax highlight: Bash</option>
12521
12521
  <option value="c">Syntax highlight: C</option>
@@ -12806,6 +12806,7 @@ ${cssVarsBlock}
12806
12806
  <div><dt>Tab</dt><dd>Insert a visible completion suggestion; otherwise indent selected editor text</dd></div>
12807
12807
  <div><dt>Esc</dt><dd>Dismiss a visible completion suggestion, close overlays, exit pane focus, or stop an active request</dd></div>
12808
12808
  <div><dt>Shift+Tab</dt><dd>Unindent selected editor text</dd></div>
12809
+ <div><dt>Ctrl+Shift+H</dt><dd>Toggle editor syntax highlighting</dd></div>
12809
12810
  </dl>
12810
12811
  </section>
12811
12812
  <section class="shortcuts-group shortcuts-full-only">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-studio",
3
- "version": "0.9.61",
3
+ "version": "0.9.62",
4
4
  "description": "Two-pane browser workspace for pi with prompt/response editing, annotations, critiques, active quiz, prompt/response history, live previews, and tmux-backed REPL/literate REPL workflows",
5
5
  "type": "module",
6
6
  "license": "MIT",