From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp11.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms8.migadu.com with LMTPS id cK1WLFojb2XUUQAA9RJhRA:P1 (envelope-from ) for ; Tue, 05 Dec 2023 14:19:22 +0100 Received: from aspmx1.migadu.com ([2001:41d0:403:4876::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp11.migadu.com with LMTPS id cK1WLFojb2XUUQAA9RJhRA (envelope-from ) for ; Tue, 05 Dec 2023 14:19:22 +0100 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 319BC5BD8C for ; Tue, 5 Dec 2023 14:19:22 +0100 (CET) Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=RHNxQu07; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gmail.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1701782362; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=CnyXtWiJUBDy+cAMV5i68GJyYl300vKewqwdiKkL9Ss=; b=TZP8vSzc9ywLsFKf18dJ0q5PhKH6pnbjIpzSHOt9tiopu/vuV7wTH9IOZPmI4wCZ1nKYop 9RtkKenjrLF7mGYOU/kUuM9T4Z7y9oEwyX2xnNGSkNVjs0syzpvomchKLk1RUBXnOrqR2N gbD99b1iHsfQz2UceQwQQLIyZ1fyRIJw2R34CHSqQO1YBJWey79kE3Ua5K4BhcC0wxOQK+ omqwbuBoEx7V+UwzfDWsE3+tSeeY80+J/IrPGTBpV9BcqP1LNhqbHME3ghUw81oaMJpA+V 8YGUoxIb6BlE7j1iF2Oa2KunzkgYF/qkCDRSRwplYvX0z8a4GVACjIpMYB02lA== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=RHNxQu07; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org"; dmarc=pass (policy=none) header.from=gmail.com ARC-Seal: i=1; s=key1; d=yhetil.org; t=1701782362; a=rsa-sha256; cv=none; b=acBTsDDx95th9kVE1JwmI1in6ey1Ji3xfrAIyQ4lccBkBURoceLwdtENegMDfo5PbCH/My 39aJZY+o/s1lFSj3tD150nTcOJjVvY5Sm0FqnteniJH05qb2ogyHgtriby6edPCDK3apcr ToGJYeVl+dveFOkSWEzD1eEP4uTTnWtaLvEksglwmheLu0ALMMCH5yvk81Q3lcP5N3EjHd q6VC37AdZEJi+2uI5ZNfriFn+6Us82RkvwwS0JkOajHnraPYkMS9U4HwhIRe5GRnoOR7tc H8aAckIUuVWpY4QBXNJMijuMx6dNhdo9urhulzVXquabiQtt0js8Zx/zebYNgw== Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1rAVJg-0007sV-5P; Tue, 05 Dec 2023 08:18:24 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1rAVJf-0007sH-7A for emacs-orgmode@gnu.org; Tue, 05 Dec 2023 08:18:23 -0500 Received: from mail-pf1-x442.google.com ([2607:f8b0:4864:20::442]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1rAVJc-000739-CA for emacs-orgmode@gnu.org; Tue, 05 Dec 2023 08:18:22 -0500 Received: by mail-pf1-x442.google.com with SMTP id d2e1a72fcca58-6ce6d926f76so466767b3a.1 for ; Tue, 05 Dec 2023 05:18:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1701782298; x=1702387098; darn=gnu.org; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:from:to:cc:subject:date:message-id:reply-to; bh=CnyXtWiJUBDy+cAMV5i68GJyYl300vKewqwdiKkL9Ss=; b=RHNxQu07uTSgS4zmDnujxpOTE5GexijoBnv6tCvOZ86Cd/iH3JYSFiM5JC+Gm5ChU/ 6P6OgPX1RYvmnGub01k46Wzh7a/5V6UPNcHVn92XtMmX8tjsGnbWF2NpYHEsyCtxYNd4 +zwv5lryBBBj4/yS1SGp6gk7I8+OYA5Ac/I/VqhCuej1C/TY3hsIUAvt0c3J8uwIdNta zAujYePqP2SHxENeA704tCwNDQT8DbJBq0cfNwvYRMCukzih2siZxxpB7e7fdjGZSS1a 9mEslo/UcpwlphzJmu5KhIawEymX074uISakHaU2kAf5yh2HAJy41TDCk/OqS1gWlpYw aMpQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1701782298; x=1702387098; h=mime-version:user-agent:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=CnyXtWiJUBDy+cAMV5i68GJyYl300vKewqwdiKkL9Ss=; b=OzRSBUjRipChbB3mACSDpSaRCgHQ2HxJ6THS+w4pB2E/3F6JLL+kgZaC3jxphPMDGt xf7LgDChOPB3RniL9EKwt8L2j3bPjNmIggIvUbiHlkeeN/T1rF8LP+3l0UkDX+Ujr55H ozMESgku+107R8o/B1qpp8K86zL1opIAAuGiYKmC/HV1fiBjfJ4c8VRGi5PYS6NcZZEA gqqqK2Tm5C0sv1U/cHvb1BsaptOLN5743HaTn8SIi9kNg4VE1mCqAvFGBDE6fuyOvCc6 yvd7PRxj9iJFEPDUFRpZLDGOlXEmJn845uCeMmp3/RS9nrWHrW4QGoxqIwa6SmmFyU7i 6dsQ== X-Gm-Message-State: AOJu0YzzAw0twAKzgmdk4fsUBkT+s1+Qhmx6db+Nbqe2vPRPQdodvFZW nB3L/3JwKaCQ6z8PxyVa+nE= X-Google-Smtp-Source: AGHT+IHtZnWAGX0zd/r3vlh3iUoiG4gVdp+2Z1hcDNgoB/3BR9RHntEdaIp93lluMEX8qsZf3FGrZQ== X-Received: by 2002:a05:6a20:734e:b0:18f:9c4:d334 with SMTP id v14-20020a056a20734e00b0018f09c4d334mr1978292pzc.36.1701782298299; Tue, 05 Dec 2023 05:18:18 -0800 (PST) Received: from localhost ([115.240.90.130]) by smtp.gmail.com with ESMTPSA id z12-20020aa785cc000000b006cb6ba5fe72sm1543081pfn.122.2023.12.05.05.18.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 Dec 2023 05:18:17 -0800 (PST) From: Visuwesh To: Ihor Radchenko Cc: Po Lu , emacs-orgmode@gnu.org Subject: Re: [BUG] [PATCH] Add yank-media and DND handler [9.6.7 (9.6.7-g6eb773 @ /home/viz/lib/emacs/straight/build/org/)] In-Reply-To: <87cywo5rwy.fsf@localhost> (Ihor Radchenko's message of "Sun, 05 Nov 2023 12:02:53 +0000") References: <87jzsintv0.fsf@gmail.com> <87lecx2nff.fsf@localhost> <87bkdsomm2.fsf@gmail.com> <87a5tamm3j.fsf@gmail.com> <877cnyzlda.fsf@localhost> <87a5sur51r.fsf@gmail.com> <875y3ir0lu.fsf@gmail.com> <87ttr1pild.fsf@localhost> <87v8bhpdg8.fsf@gmail.com> <87edi4m4my.fsf@localhost> <87wmvf89ha.fsf@gmail.com> <875y2xaf6d.fsf@localhost> <87a5s98x67.fsf@gmail.com> <87il6tzk6w.fsf@yahoo.com> <87cywo5rwy.fsf@localhost> Date: Tue, 05 Dec 2023 18:48:14 +0530 Message-ID: <87fs0gwzxl.fsf@gmail.com> User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::442; envelope-from=visuweshm@gmail.com; helo=mail-pf1-x442.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Queue-Id: 319BC5BD8C X-Spam-Score: -9.46 X-Migadu-Scanner: mx10.migadu.com X-Migadu-Spam-Score: -9.46 X-TUID: X3oZa18pc1Fr --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable [=E0=AE=9E=E0=AE=BE=E0=AE=AF=E0=AE=BF=E0=AE=B1=E0=AF=81 =E0=AE=A8=E0=AE=B5= =E0=AE=AE=E0=AF=8D=E0=AE=AA=E0=AE=B0=E0=AF=8D 05, 2023] Ihor Radchenko wrot= e: > Po Lu writes: > >> I have now installed an interface to this end into Emacs 30. The >> pertinent documentation is under the ``Drag and Drop'' node in the Lisp >> reference manual. > > Thanks! > > [...] > > Visuwesh, do you want to update your patch accordingly? I have now adjusted the patch to insert a space between links when the Emacs version in <30, and when more than one file is dropped. --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Add-support-for-yank-media-and-DND.patch >From 93db10f9f0c618be5512fbd67cd7b7676d6b1b0c Mon Sep 17 00:00:00 2001 From: Visuwesh Date: Fri, 22 Sep 2023 20:11:41 +0530 Subject: [PATCH] Add support for yank-media and DND * lisp/org.el (org-mode): Call the setup function for yank-media and DND. (org-setup-yank-dnd-handlers): Register yank-media-handler and DND handler. (org-yank-image-save-method, org-yank-image-file-name-function) (org-yank-dnd-method, org-yank-dnd-default-attach-method): New defcustoms. (org--image-yank-media-handler, org--copied-files-yank-media-handler) (org--dnd-rmc, org--dnd-multi-local-file-handler) (org--dnd-local-file-handler, org--dnd-attach-file, org--dnd-xds-method) (org--dnd-xds-function): Add yank-media and DND handlers. * doc/org-manual.org: (Drag and Drop & ~yank-media~): Describe the new feature in the manual. * etc/ORG-NEWS: Advertise the new features. --- doc/org-manual.org | 45 ++++++++ etc/ORG-NEWS | 24 +++++ lisp/org.el | 248 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 316 insertions(+), 1 deletion(-) diff --git a/doc/org-manual.org b/doc/org-manual.org index 3e9d42f55..7b14eb937 100644 --- a/doc/org-manual.org +++ b/doc/org-manual.org @@ -21095,6 +21095,51 @@ most recent since the mobile application searches files that were last pulled. To get an updated agenda view with changes since the last pull, pull again. +** Drag and Drop & ~yank-media~ +:PROPERTIES: +:DESCRIPTION: Dropping and pasting files and images +:END: + +#+cindex: dropping files +#+cindex: dragging files +#+cindex: drag and drop +#+cindex: dnd +#+vindex: org-yank-dnd-method +Org mode supports drag and drop (DnD) of files. By default, Org asks +the user what must be done with the dropped file: attach it, insert +=file:= link, or open the file. Customize ~org-yank-dnd-method~ to +set the default DnD action. + +When DnD method is "attach", Org mode first consults DnD metadata to +decide the attach method. For example, when file/files are dragged +from a file manager, Org may attach by copying or by moving. + +#+vindex: org-yank-dnd-default-attach-method +If Org cannot figure out which attachment method to use from the +metadata, it defaults to ~org-yank-dnd-default-attach-method~ [fn::By +default, ~org-yank-dnd-default-attach-method~ is set to nil -- use the same +value as ~org-attach-method~ (~cp~ by default).] + +#+cindex: pasting files, images from clipboard +Starting from Emacs 29, Org mode supports ~yank-media~ command to yank +images from the clipboard and files from a file manager. + +#+vindex: org-yank-image-save-method +When yanking images from clipboard, Org saves the image on disk and +inserts the image link to Org buffer. Images are either saved as +attachments to heading (default) or to a globally defined directory. +The save location is controlled by ~org-yank-image-save-method~. + +#+vindex: org-yank-image-file-name-function +The yanked images are saved under automatically generated name. You +can customize ~org-yank-image-file-name-function~ to make Org query +the image names or change the naming scheme. + +When yanking files copied from a file manager, Org respects the value +of ~org-yank-dnd-method~. Image files pasted this way also respect +the value of ~org-yank-image-save-method~ when the action to perform +is =attach=. + * Hacking :PROPERTIES: :DESCRIPTION: How to hack your way around. diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 252c5a9f9..7c40ec0fe 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -596,6 +596,30 @@ return a matplotlib Figure object to plot. For output results, the current figure (as returned by =pyplot.gcf()=) is cleared before evaluation, and then plotted afterwards. +*** Images and files in clipboard can be pasted + +Org asks the user what must be done when pasting images and files +copied to the clipboard from a file manager using the ~yank-media~ +command. The default action can be set by customizing +~org-yank-dnd-method~. The ~yank-media~ command was added in Emacs +29. + +Images can be saved to a separate directory instead of being attached, +customize ~org-yank-image-save-method~. + +Image filename chosen can be customized by setting +~org-yank-image-file-name-function~ which by default autogenerates a +filename based on the current time. + +*** Files and images can be attached by dropping onto Emacs + +By default, Org asks the user what to do with the dropped file like +for pasted files. The same user option ~org-yank-dnd-method~ is +respected. + +Images dropped also respect the value of ~org-yank-image-save-method~ +when ~org-yank-dnd-method~ is =attach=. + ** New functions and changes in function arguments *** =TYPES= argument in ~org-element-lineage~ can now be a symbol diff --git a/lisp/org.el b/lisp/org.el index d0b2355ea..086b3dff5 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -4999,7 +4999,10 @@ The following commands are available: (org--set-faces-extend '(org-block-begin-line org-block-end-line) org-fontify-whole-block-delimiter-line) (org--set-faces-extend org-level-faces org-fontify-whole-heading-line) - (setq-local org-mode-loading nil)) + (setq-local org-mode-loading nil) + + ;; `yank-media' handler and DND support. + (org-setup-yank-dnd-handlers)) ;; Update `customize-package-emacs-version-alist' (add-to-list 'customize-package-emacs-version-alist @@ -20254,6 +20257,249 @@ it has a `diary' type." (org-format-timestamp timestamp fmt t)) (org-format-timestamp timestamp fmt (eq boundary 'end))))))) +;;; Yank media handler and DND +(defun org-setup-yank-dnd-handlers () + "Setup the `yank-media' and DND handlers for buffer." + (setq-local dnd-protocol-alist + (cons (cons "^file:///" + (if (>= emacs-major-version 30) + #'org--dnd-multi-local-file-handler + #'org--dnd-local-file-handler)) + dnd-protocol-alist)) + (when (fboundp 'yank-media-handler) + (yank-media-handler "image/.*" #'org--image-yank-media-handler) + ;; Looks like different DEs go for different handler names, + ;; https://larsee.com/blog/2019/05/clipboard-files/. + (yank-media-handler "x/special-\\(?:gnome\|KDE\|mate\\)-files" + #'org--copied-files-yank-media-handler)) + (when (boundp 'x-dnd-direct-save-function) + (setq-local x-dnd-direct-save-function #'org--dnd-xds-function))) + +(defcustom org-yank-image-save-method 'attach + "Method to save images yanked from clipboard and dropped to Emacs. +It can be the symbol `attach' to add it as an attachment, or a +directory name to copy/cut the image to that directory." + :group 'org + :package-version '(Org . "9.7") + :type '(choice (const :tag "Add it as attachment" attach) + (directory :tag "Save it in directory")) + :safe (lambda (x) (eq x 'attach))) + +(defcustom org-yank-image-file-name-function #'org-yank-image-autogen-filename + "Function to generate filename for image yanked from clipboard. +By default, this autogenerates a filename based on the current +time. +It is called with no arguments and should return a string without +any extension which is used as the filename." + :group 'org + :package-version '(Org . "9.7") + :type '(radio (function-item :doc "Autogenerate filename" + org-yank-image-autogen-filename) + (function-item :doc "Ask for filename" + org-yank-image-read-filename) + function)) + +(defun org-yank-image-autogen-filename () + "Autogenerate filename for image in clipboard." + (format-time-string "clipboard-%Y%m%dT%H%M%S.%6N")) + +(defun org-yank-image-read-filename () + "Read filename for image in clipboard." + (read-string "Basename for image file without extension: ")) + +(declare-function org-attach-attach "org-attach" (file &optional visit-dir method)) + +(defun org--image-yank-media-handler (mimetype data) + "Save image DATA of mime-type MIMETYPE and insert link at point. +It is saved as per `org-yank-image-save-method'. The name for the +image is prompted and the extension is automatically added to the +end." + (let* ((ext (symbol-name (mailcap-mime-type-to-extension mimetype))) + (iname (funcall org-yank-image-file-name-function)) + (filename (file-name-with-extension iname ext)) + (absname (expand-file-name + filename + (if (eq org-yank-image-save-method 'attach) + temporary-file-directory + org-yank-image-save-method))) + link) + (when (and (not (eq org-yank-image-save-method 'attach)) + (not (file-directory-p org-yank-image-save-method))) + (make-directory org-yank-image-save-method t)) + (with-temp-file absname + (insert data)) + (if (null (eq org-yank-image-save-method 'attach)) + (setq link (org-link-make-string (concat "file:" (file-relative-name absname)))) + (require 'org-attach) + (org-attach-attach absname nil 'mv) + (setq link (org-link-make-string (concat "attachment:" filename)))) + (insert link))) + +;; I cannot find a spec for this but +;; https://indigo.re/posts/2021-12-21-clipboard-data.html and pcmanfm +;; suggests that this is the format. +(defun org--copied-files-yank-media-handler (_mimetype data) + "Handle copied or cut files from file manager. +They are handled as per `org-yank-dnd-method'. +DATA is a string where the first line is the operation to +perform: copy or cut. Rest of the lines are file: links to the +concerned files." + ;; pcmanfm adds a null byte at the end for some reason. + (let* ((data (split-string data "[\0\n\r]" t)) + (files (cdr data)) + (action (if (equal (car data) "cut") + 'copy + 'move)) + (sep (if (= (length files) 1) "" " "))) + (dolist (f files) + (if (file-readable-p f) + (org--dnd-local-file-handler f action sep) + (message "File `%s' is not readable, skipping" f))))) + +(defcustom org-yank-dnd-method 'ask + "Action to perform on the dropped and the pasted files. +When the value is the symbol, + . `attach' -- attach dropped/pasted file + . `open' -- visit/open dropped/pasted file in Emacs + . `file-link' -- insert file: link to dropped/pasted file + . `ask' -- ask what to do out of the above." + :group 'org + :package-version '(Org . "9.7") + :type '(choice (const :tag "Attach" attach) + (const :tag "Open/Visit file" open) + (const :tag "Insert file: link" file-link) + (const :tag "Ask what to do" ask))) + +(defcustom org-yank-dnd-default-attach-method nil + "Default attach method to use when DND action is unspecified. +This attach method is used when the DND action is `private'. +This is also used when `org-yank-image-save-method' is nil. +When nil, use `org-attach-method'." + :group 'org + :package-version '(Org . "9.7") + :type '(choice (const :tag "Default attach method" nil) + (const :tag "Copy" cp) + (const :tag "Move" mv) + (const :tag "Hard link" ln) + (const :tag "Symbolic link" lns))) + +(declare-function mailcap-file-name-to-mime-type "mailcap" (file-name)) +(defvar org-attach-method) + +(defun org--dnd-rmc (prompt choices) + (if (null (use-dialog-box-p)) + (caddr (read-multiple-choice prompt choices)) + (setq choices + (mapcar + (pcase-lambda (`(_key ,message ,val)) + (cons (capitalize message) val)) + choices)) + (x-popup-menu t (list prompt (cons "" choices))))) + +(defun org--dnd-multi-local-file-handler (urls action) + "Handle file URLS as per ACTION. +URLS is a list of file URL." + (let ((sep (if (= (length urls) 1) "" " "))) + (dolist (u urls) + (org--dnd-local-file-handler u action sep)))) + +(put 'org--dnd-multi-local-file-handler 'dnd-multiple-handler t) + +(defun org--dnd-local-file-handler (url action &optional separator) + "Handle file URL as per ACTION. +SEPARATOR is the string to insert after each link. It may be nil +in which case, space is inserted." + (unless separator + (setq separator " ")) + (let ((method (if (eq org-yank-dnd-method 'ask) + (org--dnd-rmc + "What to do with file?" + '((?a "attach" attach) + (?o "open" open) + (?f "insert file: link" file-link))) + org-yank-dnd-method))) + (pcase method + (`attach (org--dnd-attach-file url action separator)) + (`open (dnd-open-local-file url action)) + (`file-link + (let ((filename (dnd-get-local-file-name url))) + (insert (org-link-make-string (concat "file:" filename)) separator)))))) + +(defun org--dnd-attach-file (url action separator) + "Attach filename given by URL using method pertaining to ACTION. +If ACTION is `move', use `mv' attach method. +If `copy', use `cp' attach method. +If `ask', ask the user. +If `private', use the method denoted in `org-yank-dnd-default-attach-method'. +The action `private' is always returned. + +SEPARATOR is the string to insert after each link." + (require 'mailcap) + (let* ((filename (dnd-get-local-file-name url)) + (mimetype (mailcap-file-name-to-mime-type filename)) + (separatep (and (string-prefix-p "image/" mimetype) + (not (eq 'attach org-yank-image-save-method)))) + (method (pcase action + ('copy 'cp) + ('move 'mv) + ('ask (org--dnd-rmc + "Attach using method" + '((?c "copy" cp) + (?m "move" mv) + (?l "hard link" ln) + (?s "symbolic link" lns)))) + ('private (or org-yank-dnd-default-attach-method + org-attach-method))))) + (if separatep + (funcall + (pcase method + ('cp #'copy-file) + ('mv #'rename-file) + ('ln #'add-name-to-file) + ('lns #'make-symbolic-link)) + filename + (expand-file-name (file-name-nondirectory filename) + org-yank-image-save-method)) + (org-attach-attach filename nil method)) + (insert + (org-link-make-string + (concat (if separatep + "file:" + "attachment:") + (if separatep + (expand-file-name (file-name-nondirectory filename) + org-yank-image-save-method) + (file-name-nondirectory filename)))) + separator) + 'private)) + +(defvar-local org--dnd-xds-method nil + "The method to use for dropped file.") +(defun org--dnd-xds-function (need-name filename) + "Handle file with FILENAME dropped via XDS protocol. +When NEED-NAME is t, FILNAME is the base name of the file to be +saved. +When NEED-NAME is nil, the drop is complete." + (if need-name + (let ((method (if (eq org-yank-dnd-method 'ask) + (org--dnd-rmc + "What to do with dropped file?" + '((?a "attach" attach) + (?o "open" open) + (?f "insert file: link" file-link))) + org-yank-dnd-method))) + (setq-local org--dnd-xds-method method) + (pcase method + (`attach (expand-file-name filename (org-attach-dir 'create))) + (`open (expand-file-name (make-temp-name "emacs.") temporary-file-directory)) + (`file-link (read-file-name "Write file to: " nil nil nil filename)))) + (pcase org--dnd-xds-method + (`attach (insert (org-link-make-string + (concat "attachment:" (file-name-nondirectory filename))))) + (`file-link (insert (org-link-make-string (concat "file:" filename)))) + (`open (find-file filename))) + (setq-local org--dnd-xds-method nil))) + ;;; Other stuff (defvar reftex-docstruct-symbol) -- 2.42.0 --=-=-=--