pi-edit-session-in-place 0.1.15 → 0.1.16

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,15 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## [0.1.16] - 2026-06-04
8
+
9
+ ### Fixed
10
+ - fixed `Ctrl+Shift+E` after the Pi 0.78.1 update by removing the registered shortcut handler that consumed the key and only showed the placeholder notification
11
+ - added regression coverage that verifies the extension no longer registers a conflicting shortcut handler and still installs the custom editor hotkey path
12
+
13
+ ### Changed
14
+ - removed the custom main-editor wrapper path and returned to the focused custom-editor hotkey path used by the working releases
15
+
7
16
  ## [0.1.15] - 2026-06-04
8
17
 
9
18
  ### Changed
package/README.md CHANGED
@@ -81,7 +81,7 @@ If you clear the message and submit an empty value, the selected message is effe
81
81
  - If the selected message contains images, the extension warns that re-editing or deleting it will drop the images and keep only text behavior
82
82
  - The extension only offers text-bearing user messages for editing; image-only or whitespace-only user messages are skipped
83
83
  - Queued messages must be cleared before using the command
84
- - If another extension has already customized the main editor, this extension wraps it instead of replacing it
84
+ - The `Ctrl+Shift+E` hotkey is handled by this extension's main-editor component so Pi's registered shortcut dispatcher does not consume it first
85
85
 
86
86
  ## Development
87
87
 
@@ -15,7 +15,6 @@ import {
15
15
  DynamicBorder,
16
16
  keyHint,
17
17
  rawKeyHint,
18
- type AppKeybinding,
19
18
  type ExtensionAPI,
20
19
  type ExtensionCommandContext,
21
20
  type KeybindingsManager,
@@ -30,8 +29,6 @@ import {
30
29
  Spacer,
31
30
  Text,
32
31
  matchesKey,
33
- type AutocompleteProvider,
34
- type EditorComponent,
35
32
  type EditorTheme,
36
33
  type Focusable,
37
34
  type TUI,
@@ -572,16 +569,12 @@ const handleEditTurn = async (ctx: ExtensionCommandContext) => {
572
569
  );
573
570
  };
574
571
 
575
- const triggerEditTurnCommand = (editor: Pick<EditorComponent, "getText" | "setText" | "handleInput">) => {
576
- draftBeforeHotkey = editor.getText();
577
- editor.setText(COMMAND_TEXT);
578
- editor.handleInput("\r");
579
- };
580
-
581
572
  class EditSessionInPlaceEditor extends CustomEditor {
582
573
  handleInput(data: string): void {
583
574
  if (matchesKey(data, HOTKEY)) {
584
- triggerEditTurnCommand(this);
575
+ draftBeforeHotkey = this.getText();
576
+ this.setText(COMMAND_TEXT);
577
+ super.handleInput("\r");
585
578
  return;
586
579
  }
587
580
 
@@ -589,152 +582,6 @@ class EditSessionInPlaceEditor extends CustomEditor {
589
582
  }
590
583
  }
591
584
 
592
- type AutocompleteAwareEditor = EditorComponent & {
593
- isShowingAutocomplete?: () => boolean;
594
- };
595
-
596
- class EditSessionInPlaceEditorWrapper implements EditorComponent, Focusable {
597
- public actionHandlers: Map<AppKeybinding, () => void> = new Map();
598
- public onEscape?: () => void;
599
- public onCtrlD?: () => void;
600
- public onPasteImage?: () => void;
601
- public onExtensionShortcut?: (data: string) => boolean | undefined;
602
-
603
- constructor(
604
- private readonly base: EditorComponent,
605
- private readonly keybindings: KeybindingsManager,
606
- ) {}
607
-
608
- get focused(): boolean {
609
- return "focused" in this.base && typeof this.base.focused === "boolean" ? this.base.focused : false;
610
- }
611
-
612
- set focused(value: boolean) {
613
- if ("focused" in this.base) {
614
- (this.base as EditorComponent & Focusable).focused = value;
615
- }
616
- }
617
-
618
- get wantsKeyRelease(): boolean | undefined {
619
- return this.base.wantsKeyRelease;
620
- }
621
-
622
- set wantsKeyRelease(value: boolean | undefined) {
623
- this.base.wantsKeyRelease = value;
624
- }
625
-
626
- get onSubmit(): ((text: string) => void) | undefined {
627
- return this.base.onSubmit;
628
- }
629
-
630
- set onSubmit(value: ((text: string) => void) | undefined) {
631
- this.base.onSubmit = value;
632
- }
633
-
634
- get onChange(): ((text: string) => void) | undefined {
635
- return this.base.onChange;
636
- }
637
-
638
- set onChange(value: ((text: string) => void) | undefined) {
639
- this.base.onChange = value;
640
- }
641
-
642
- get borderColor(): ((str: string) => string) | undefined {
643
- return this.base.borderColor;
644
- }
645
-
646
- set borderColor(value: ((str: string) => string) | undefined) {
647
- this.base.borderColor = value;
648
- }
649
-
650
- render(width: number): string[] {
651
- return this.base.render(width);
652
- }
653
-
654
- invalidate(): void {
655
- this.base.invalidate();
656
- }
657
-
658
- getText(): string {
659
- return this.base.getText();
660
- }
661
-
662
- setText(text: string): void {
663
- this.base.setText(text);
664
- }
665
-
666
- handleInput(data: string): void {
667
- if (matchesKey(data, HOTKEY)) {
668
- triggerEditTurnCommand(this.base);
669
- return;
670
- }
671
-
672
- if (this.onExtensionShortcut?.(data)) {
673
- return;
674
- }
675
-
676
- if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
677
- this.onPasteImage?.();
678
- return;
679
- }
680
-
681
- if (this.keybindings.matches(data, "app.interrupt")) {
682
- const isShowingAutocomplete = (this.base as AutocompleteAwareEditor).isShowingAutocomplete?.() ?? false;
683
- if (!isShowingAutocomplete) {
684
- const handler = this.onEscape ?? this.actionHandlers.get("app.interrupt");
685
- if (handler) {
686
- handler();
687
- return;
688
- }
689
- }
690
-
691
- this.base.handleInput(data);
692
- return;
693
- }
694
-
695
- if (this.keybindings.matches(data, "app.exit") && this.base.getText().length === 0) {
696
- const handler = this.onCtrlD ?? this.actionHandlers.get("app.exit");
697
- if (handler) {
698
- handler();
699
- }
700
- return;
701
- }
702
-
703
- for (const [action, handler] of this.actionHandlers) {
704
- if (action !== "app.interrupt" && action !== "app.exit" && this.keybindings.matches(data, action)) {
705
- handler();
706
- return;
707
- }
708
- }
709
-
710
- this.base.handleInput(data);
711
- }
712
-
713
- addToHistory(text: string): void {
714
- this.base.addToHistory?.(text);
715
- }
716
-
717
- insertTextAtCursor(text: string): void {
718
- this.base.insertTextAtCursor?.(text);
719
- }
720
-
721
- getExpandedText(): string {
722
- return this.base.getExpandedText?.() ?? this.base.getText();
723
- }
724
-
725
- setAutocompleteProvider(provider: AutocompleteProvider): void {
726
- this.base.setAutocompleteProvider?.(provider);
727
- }
728
-
729
- setPaddingX(padding: number): void {
730
- this.base.setPaddingX?.(padding);
731
- }
732
-
733
- setAutocompleteMaxVisible(maxVisible: number): void {
734
- this.base.setAutocompleteMaxVisible?.(maxVisible);
735
- }
736
- }
737
-
738
585
  export default function editSessionInPlace(pi: ExtensionAPI) {
739
586
  pi.registerCommand(COMMAND_NAME, {
740
587
  description: `Select and re-edit a previous user message on the current branch (${HOTKEY_LABEL})`,
@@ -743,27 +590,10 @@ export default function editSessionInPlace(pi: ExtensionAPI) {
743
590
  },
744
591
  });
745
592
 
746
- // Shortcut handlers receive ExtensionContext, so the custom editor hotkey path performs
747
- // the command execution while this registration keeps the hotkey discoverable.
748
- pi.registerShortcut(HOTKEY, {
749
- description: `Edit a previous user message (${HOTKEY_LABEL})`,
750
- handler: (ctx) => {
751
- if (!ctx.hasUI) {
752
- return;
753
- }
754
-
755
- ctx.ui.notify(`Press ${HOTKEY_LABEL} in the main editor to edit a previous message.`, "info");
756
- },
757
- });
758
-
759
593
  pi.on("session_start", (_event, ctx) => {
760
594
  clearSavedDraft();
761
595
  if (ctx.mode === "tui") {
762
- const previousEditor = ctx.ui.getEditorComponent();
763
- ctx.ui.setEditorComponent((tui, theme, keybindings) => {
764
- const baseEditor = previousEditor?.(tui, theme, keybindings);
765
- return baseEditor ? new EditSessionInPlaceEditorWrapper(baseEditor, keybindings) : new EditSessionInPlaceEditor(tui, theme, keybindings);
766
- });
596
+ ctx.ui.setEditorComponent((tui, theme, keybindings) => new EditSessionInPlaceEditor(tui, theme, keybindings));
767
597
  }
768
598
  });
769
599
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-edit-session-in-place",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "pi extension that lets you re-edit or delete an earlier user message in the current session branch",
5
5
  "author": "Mitch Fultz (https://github.com/fitchmultz)",
6
6
  "license": "MIT",