дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
feat(composer): inline @file and /skill tags, commands anywhere, project drag-and-drop (#2066)
Closes #1981 @file references and /skill commands become inline tags anywhere in the prompt, in Home and in a conversation. Tags are edited as a unit (Backspace/Delete, arrows) and are not committed mid-IME composition. Files and folders dragged from the Project view become references, mapped into the task worktree; paths outside the project, traversal and relative paths are rejected, and a deleted reference can be dropped again. Co-authored-by: panda-student <[email protected]>
Цей коміт міститься в:
1 джерело
45a1132ece
коміт
ff7473a277
17 files changed
+545
-115
No files matched your search
@@ -57,6 +57,11 @@ import { CodeBreadcrumbs } from "./StatusItems";
|
||||
import styles from "./EditorArea.module.css";
|
||||
import { tx } from "@/platform/i18n";
|
||||
|
||||
/** The documents of a project-files drag: folders (trailing `/`) are not opened as editors. */
|
||||
function droppedFiles(payload: string): string[] {
|
||||
return payload.split("\n").filter((p) => !!p && !p.endsWith("/"));
|
||||
}
|
||||
|
||||
export function EditorAreaView() {
|
||||
const layout = useTabs((s) => s.layout);
|
||||
const empty = useTabs((s) => Object.values(s.panes).every((p) => p.tabs.length === 0));
|
||||
@@ -77,14 +82,14 @@ function EmptyEditorArea() {
|
||||
if (!el) return;
|
||||
return registerDropTarget(el, {
|
||||
accepts: (type) => type === EDITOR_TAB_MIME || type === FILES_DRAG || acceptsEditorDrop(type),
|
||||
over: () => setOver(true),
|
||||
over: (data) => setOver(data.type !== FILES_DRAG || droppedFiles(data.payload).length > 0),
|
||||
leave: () => setOver(false),
|
||||
drop: (data) => {
|
||||
setOver(false);
|
||||
const paneId = Object.keys(useTabs.getState().panes)[0];
|
||||
if (!paneId) return;
|
||||
if (data.type === FILES_DRAG) {
|
||||
void editorController().openFilesIn(data.payload.split("\n").filter(Boolean), paneId, "center");
|
||||
void editorController().openFilesIn(droppedFiles(data.payload), paneId, "center");
|
||||
return;
|
||||
}
|
||||
if (data.type !== EDITOR_TAB_MIME) {
|
||||
@@ -253,14 +258,16 @@ function PaneView({ paneId }: { paneId: string }) {
|
||||
const zoneAt = (x: number, y: number) => dropZoneAt(x, y, el.getBoundingClientRect());
|
||||
return registerDropTarget(el, {
|
||||
accepts: (type) => type === EDITOR_TAB_MIME || type === FILES_DRAG || acceptsEditorDrop(type),
|
||||
over: (data, x, y) =>
|
||||
setDropZone(data.type === EDITOR_TAB_MIME || data.type === FILES_DRAG ? zoneAt(x, y) : "center"),
|
||||
over: (data, x, y) => {
|
||||
if (data.type === FILES_DRAG) setDropZone(droppedFiles(data.payload).length ? zoneAt(x, y) : null);
|
||||
else setDropZone(data.type === EDITOR_TAB_MIME ? zoneAt(x, y) : "center");
|
||||
},
|
||||
leave: () => setDropZone(null),
|
||||
drop: (data, x, y) => {
|
||||
const zone = zoneAt(x, y);
|
||||
setDropZone(null);
|
||||
if (data.type === FILES_DRAG) {
|
||||
void ctrl.openFilesIn(data.payload.split("\n").filter(Boolean), paneId, zone);
|
||||
void ctrl.openFilesIn(droppedFiles(data.payload), paneId, zone);
|
||||
return;
|
||||
}
|
||||
if (data.type !== EDITOR_TAB_MIME) {
|
||||
|
||||
Reference in new issue
Заблокувати користувача