Skip to content
Open
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
24 changes: 24 additions & 0 deletions blocksuite/framework/std/src/view/element/lit-host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,28 @@ export class EditorHost extends SignalWatcher(
)}`;
};

private readonly _handlePaste = (e: ClipboardEvent) => {
const files = e.clipboardData?.files;
if (!files || files.length === 0) {
return;
}

// when copy-pasting from some websites, the clipboard may contain both an image file
// and an html string with a `blob:` url. The `blob:` url is not accessible,
// so we should prioritize handling the image file.
const imageFile = Array.from(files).find(file =>
file.type.startsWith('image/')
);

if (imageFile) {
e.preventDefault();
e.stopPropagation();
this.command.execute('editor:insert-file', {
file: imageFile,
});
}
};
Comment on lines +107 to +127
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Add error handling for command execution.

The command.execute call lacks error handling. If the editor:insert-file command fails or throws an exception, it will propagate uncaught and potentially break the paste operation or leave the editor in an inconsistent state.

Consider wrapping the command execution in a try-catch block:

     if (imageFile) {
       e.preventDefault();
       e.stopPropagation();
-      this.command.execute('editor:insert-file', {
-        file: imageFile,
-      });
+      try {
+        this.command.execute('editor:insert-file', {
+          file: imageFile,
+        });
+      } catch (error) {
+        console.error('Failed to insert image file:', error);
+        // Optionally re-enable default paste behavior or show user feedback
+      }
     }

Verify the command API and its availability.

Please confirm that the editor:insert-file command exists in the command registry and accepts a file parameter of type File. Also verify that this command is always registered when the editor is mounted.

Run the following script to verify the command registration and usage:


🏁 Script executed:

#!/bin/bash
# Description: Search for editor:insert-file command registration and usage

# Search for command registration
echo "=== Searching for editor:insert-file command registration ==="
rg -n "editor:insert-file" --type=ts -C3

# Search for command manager execute calls to understand error handling patterns
echo -e "\n=== Searching for command.execute patterns ==="
rg -n "command\.execute\(" --type=ts -A2 -B2 | head -50

Length of output: 1110


I need to verify more about the command system and error handling patterns. Let me search for command initialization and registration.


---

🏁 Script executed:

```shell
#!/bin/bash
# Find where this.command is initialized in lit-host.ts and related files

echo "=== Searching for 'this.command' initialization in lit-host.ts ==="
rg -n "this\.command\s*=" --type=ts -B5 -A5 blocksuite/framework/std/src/view/element/lit-host.ts

echo -e "\n=== Searching for class/interface definition in lit-host.ts ==="
rg -n "export\s+(class|interface)" --type=ts blocksuite/framework/std/src/view/element/lit-host.ts

echo -e "\n=== Searching for command property/field definition ==="
rg -n "command\s*:" --type=ts -B2 -A2 blocksuite/framework/std/src/view/element/lit-host.ts | head -30

echo -e "\n=== Searching for command registration patterns (register) ==="
rg -n "\.register.*command\|registerCommand" --type=ts -C2 | head -50

Length of output: 302



---

🏁 Script executed:

```shell
#!/bin/bash
# Find where command property comes from and error handling patterns

echo "=== Searching for SignalWatcher definition ==="
rg -n "export.*SignalWatcher|class SignalWatcher" --type=ts -A5 | head -30

echo -e "\n=== Searching for 'this.command' usage in codebase (not just lit-host) ==="
rg -n "this\.command\." --type=ts -B2 -A2 | head -50

echo -e "\n=== Searching for command.execute with try-catch or error handling ==="
rg -n "command\.execute" --type=ts -B3 -A3 | grep -E "(try|catch|error|Error|throw)" -C5 | head -40

echo -e "\n=== Searching for EditorHost full class structure ==="
rg -n "export class EditorHost" --type=ts -A30 | head -50

Length of output: 6492



---

🏁 Script executed:

```shell
#!/bin/bash
# Find EditorHost constructor, command initialization, and command definition

echo "=== Searching for EditorHost constructor and command setup ==="
rg -n "constructor|@property|@attribute|command\s*\?:" --type=ts blocksuite/framework/std/src/view/element/lit-host.ts -A2 | head -40

echo -e "\n=== Searching for editor:insert-file command definition ==="
rg -n "editor:insert-file|insert-file" --type=ts -B3 -A3

echo -e "\n=== Searching for command execution in entire codebase with context ==="
rg -n "\.execute\(" --type=ts -B2 -A2 | grep -i "command\|execute" -A3 -B3 | head -60

echo -e "\n=== Searching for command property provider or injection ==="
rg -n "command.*=" --type=ts blocksuite/framework/std/src/view/element/lit-host.ts -B2 -A2

Length of output: 3513



---

🏁 Script executed:

```shell
#!/bin/bash
# Find BlockStdScope definition and command property, check full EditorHost class

echo "=== Searching for BlockStdScope definition ==="
rg -n "export.*BlockStdScope|class BlockStdScope|interface BlockStdScope" --type=ts -A10 | head -40

echo -e "\n=== Searching for command property in BlockStdScope or related types ==="
rg -n "command.*:\s*" --type=ts | grep -i "scope\|std" -B2 -A2 | head -30

echo -e "\n=== Full EditorHost class to find all properties ==="
rg -n "export class EditorHost" --type=ts -A80 | head -100

echo -e "\n=== Search for command registration or creation ==="
rg -n "\.command\s*=|new Command|createCommand" --type=ts -B2 -A2 | head -40

Length of output: 16397



---

🏁 Script executed:

```shell
#!/bin/bash
# Search exhaustively for editor:insert-file command registration or definition

echo "=== Exact search for editor:insert-file with all context ==="
rg -n "editor:insert-file" --type=ts -B5 -A5

echo -e "\n=== Search for insert-file command registration ==="
rg -n "insert-file" --type=ts -B3 -A3

echo -e "\n=== Search for CommandManager.register or .execute implementation ==="
rg -n "class CommandManager|execute\s*\(" --type=ts blocksuite/framework/std/src/command/manager.ts -A10 | head -60

echo -e "\n=== Search for command registration in BlockStdScope ==="
rg -n "BlockStdScope" --type=ts blocksuite/framework/std/src -A5 | head -50

echo -e "\n=== Check if command property has null safety ==="
cat blocksuite/framework/std/src/view/element/lit-host.ts | sed -n '107,135p'

Length of output: 7096



---

🏁 Script executed:

```shell
#!/bin/bash
# Final verification: search for where editor:insert-file command might be registered
# Check if it's in a different package or file structure

echo "=== Search entire repo for insert command registration patterns ==="
rg -n "register.*insert|'insert.*'|\"insert.*\"" --type=ts | grep -i "command\|execute" -B2 -A2 | head -50

echo -e "\n=== Search for any file containing command registrations ==="
rg -n "\.register\(" --type=ts -B1 -A1 | head -40

echo -e "\n=== Check BlockStdScope file for command initialization ==="
fd -n "std-scope\|BlockStdScope" --type=ts | head -5

Length of output: 3079


Add error handling and verify command registration for editor:insert-file.

The command.execute() call lacks error handling, and the editor:insert-file command does not appear to be registered anywhere in the codebase. This will cause unhandled exceptions and broken paste functionality.

  1. Error handling required: Wrap the command execution in try-catch.
  2. Command registration missing: Ensure editor:insert-file command is registered before use.

Without these fixes, the paste handler will fail silently or throw uncaught exceptions.

     if (imageFile) {
       e.preventDefault();
       e.stopPropagation();
-      this.command.execute('editor:insert-file', {
-        file: imageFile,
-      });
+      try {
+        this.command.execute('editor:insert-file', {
+          file: imageFile,
+        });
+      } catch (error) {
+        console.error('Failed to insert image file:', error);
+      }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private readonly _handlePaste = (e: ClipboardEvent) => {
const files = e.clipboardData?.files;
if (!files || files.length === 0) {
return;
}
// when copy-pasting from some websites, the clipboard may contain both an image file
// and an html string with a `blob:` url. The `blob:` url is not accessible,
// so we should prioritize handling the image file.
const imageFile = Array.from(files).find(file =>
file.type.startsWith('image/')
);
if (imageFile) {
e.preventDefault();
e.stopPropagation();
this.command.execute('editor:insert-file', {
file: imageFile,
});
}
};
private readonly _handlePaste = (e: ClipboardEvent) => {
const files = e.clipboardData?.files;
if (!files || files.length === 0) {
return;
}
// when copy-pasting from some websites, the clipboard may contain both an image file
// and an html string with a `blob:` url. The `blob:` url is not accessible,
// so we should prioritize handling the image file.
const imageFile = Array.from(files).find(file =>
file.type.startsWith('image/')
);
if (imageFile) {
e.preventDefault();
e.stopPropagation();
try {
this.command.execute('editor:insert-file', {
file: imageFile,
});
} catch (error) {
console.error('Failed to insert image file:', error);
}
}
};
🤖 Prompt for AI Agents
In blocksuite/framework/std/src/view/element/lit-host.ts around lines 107 to
127, the paste handler calls this.command.execute('editor:insert-file', ...)
without error handling and the command may not be registered; wrap the execute
call in a try-catch to handle/log errors and prevent uncaught exceptions, and
before invoking ensure the command is registered (either by checking
this.command.has('editor:insert-file') or registering a no-op/handler during
component initialization); if the command is missing, either register the
handler that inserts the file or fall back to an alternative paste behavior and
log a clear warning.


get command(): CommandManager {
return this.std.command;
}
Expand Down Expand Up @@ -136,11 +158,13 @@ export class EditorHost extends SignalWatcher(

this.std.mount();
this.tabIndex = 0;
this.addEventListener('paste', this._handlePaste);
}

override disconnectedCallback() {
super.disconnectedCallback();
this.std.unmount();
this.removeEventListener('paste', this._handlePaste);
}

override async getUpdateComplete(): Promise<boolean> {
Expand Down