Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion emain/preload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2025, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

import { contextBridge, ipcRenderer, Rectangle, WebviewTag } from "electron";
import { contextBridge, ipcRenderer, Rectangle, webUtils, WebviewTag } from "electron";

// update type in custom.d.ts (ElectronApi type)
contextBridge.exposeInMainWorld("api", {
Expand Down Expand Up @@ -69,6 +69,7 @@ contextBridge.exposeInMainWorld("api", {
openBuilder: (appId?: string) => ipcRenderer.send("open-builder", appId),
setBuilderWindowAppId: (appId: string) => ipcRenderer.send("set-builder-window-appid", appId),
doRefresh: () => ipcRenderer.send("do-refresh"),
getPathForFile: (file: File): string => webUtils.getPathForFile(file),
});

// Custom event for "new-window"
Expand Down
26 changes: 26 additions & 0 deletions frontend/app/view/term/termwrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TabRpcClient } from "@/app/store/wshrpcutil";
import {
atoms,
fetchWaveFile,
getApi,
getOverrideConfigAtom,
getSettingsKeyAtom,
globalStore,
Expand Down Expand Up @@ -197,6 +198,31 @@ export class TermWrap {
this.heldData = [];
this.handleResize_debounced = debounce(50, this.handleResize.bind(this));
this.terminal.open(this.connectElem);

this.connectElem.addEventListener("dragover", (e: DragEvent) => {
e.preventDefault();
if (e.dataTransfer) {
e.dataTransfer.dropEffect = "copy";
}
});
this.connectElem.addEventListener("drop", (e: DragEvent) => {
e.preventDefault();
if (!e.dataTransfer || e.dataTransfer.files.length === 0) {
return;
}
const paths: string[] = [];
for (let i = 0; i < e.dataTransfer.files.length; i++) {
const file = e.dataTransfer.files[i];
const filePath = getApi().getPathForFile(file);
if (filePath) {
const quoted = "'" + filePath.replace(/'/g, "'\\''") + "'";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

WARNING: Shell quoting issue on Windows

The POSIX-style quoting '\'' won't work correctly on Windows shells (cmd.exe, PowerShell). Windows uses different quoting rules:

  • cmd.exe: Uses " for quoting and ^ for escaping
  • PowerShell: Uses " for quoting and ` for escaping

Consider adding platform-specific quoting:

import { PLATFORM, PlatformWindows } from "@/util/platformutil";

// In the drop handler:
if (filePath) {
    let quoted: string;
    if (PLATFORM === PlatformWindows) {
        // Windows: use double quotes and escape internal quotes
        quoted = '"' + filePath.replace(/"/g, '""') + '"';
    } else {
        // POSIX: use single quotes and escape internal quotes
        quoted = "'" + filePath.replace(/'/g, "'\\''" + "'";
    }
    paths.push(quoted);
}

paths.push(quoted);
}
}
if (paths.length > 0) {
this.terminal.paste(paths.join(" "));
}
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
this.handleResize();
const pasteHandler = this.pasteHandler.bind(this);
this.connectElem.addEventListener("paste", pasteHandler, true);
Expand Down
1 change: 1 addition & 0 deletions frontend/types/custom.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ declare global {
openBuilder: (appId?: string) => void; // open-builder
setBuilderWindowAppId: (appId: string) => void; // set-builder-window-appid
doRefresh: () => void; // do-refresh
getPathForFile: (file: File) => string; // webUtils.getPathForFile
};

type ElectronContextMenuItem = {
Expand Down