Forging org-attach features into Tinderbox
Every note-taking app handles file attachments differently. Most of them do it poorly. What I've found surprising is that I actually like what Org mode does with attachments. I might be the only one who does.
The way I have Emacs configured, dragging a file into an open buffer window will prompt me with a few options, the one I use being "Attach file". This then copies the file into a subfolder of whatever directory is configured as the org-attach-directory
. This subfolder is named based on any ID property set in the Org file. This means I end up with a directory tree that looks like this:
5f
6d
├── ace650-30fb-4157-9e6e-a259f6b4b75e
│ └── 20230820-Luigi-Ghirri .jpg
├── bffb46-e988-4e4e-864f-4ff0b9171068
│ ├── Datavue Snap 1+1 Portable Computer-closed.jpg
│ ├── Datavue Snap 1+1 Portable Computer-floppy.jpg
│ ├── Datavue Snap 1+1 Portable Computer-front.jpg
│ ├── Datavue Snap 1+1 Portable Computer.MOV
│ └── Datavue Snap 1+1 Portable Computer.jpg
└── ca2ca7-f6a8-415f-8b53-d607081fdda2
└── Community Darkroom Project.tbx
6c
6e
You can see why someone might avoid doing this. Without the source .org file, all bets are off. I don't lose the source .org file, is all. Also, I try to name my files in a reasonable way, so using Spotlight as a fallback is feasible.
Tinderbox, on the other hand, isn't much help out of the box with files. It has lots of file-based tooling, but the idea of managing attachments isn't one of them. So, I'm trying to finagle Tinderbox into working the way Emacs does.
In Tinderbox, if you have a "File" attribute showing, you can drag a file from the finder into that attribute and it will set its value to the Path (e.g. "~/Desktop/funny-meme.jpg"). What I've done is create a Stamp that copies that file to my version of Org mode's "org-attach" tree (see above).
It's hard to describe, but here's a quick rundown of how it works.
Instead of a uuid, I use a date string derived from the current time (e.g. "20241125T143431"). This is stored as a string in an "Identifier" attribute as soon as I create a new note in my LifeBook.tbx file. Here's the parts that do it...
// Set some basic attributes in the new note, including the $Identifier
$Date|=date("today");$Prototype="pJournalEntry";
$Identifier|=fNoteIdentifier($Date);
function fNoteIdentifier(vDate:date){
var:string id = vDate.format("yM0DThmms");
return id;
};
Here's what that part of the note looks like after dragging a file onto the File attribute.
Once the File attribute has a value, I run a Stamp named "Attach".
if($File){
if($Identifier==""){$Identifier=fNoteIdentifier($Date)};
var:string vSourceFilePath=$File.substr(1); // remove tilde
var:string vSourceFileName=vSourceFilePath.split("/").at(-1);
var:string vAttachmentDir=$Text("/Config/AttachmentDir");
var:string vDestDir=fNoteAttachDir();
var:string vCmd="mkdir -p " + vDestDir;
vCmd+=' && cp "$HOME' + vSourceFilePath+'" "'+vDestDir+'/"';
$HasAttachments=true;
$Text(/Debug)=vCmd;
$Text(/Debug)+=runCommand(vCmd);
$File=vDestDir;}
function fNoteAttachDir() {
var:string vAttachmentDir=$Text("/Config/AttachmentDir");
var:string vDestDir=vAttachmentDir+"/"+$Date.format(y)+"/"+$Identifier;
return vDestDir;
}
Without going too far into the weeds, this stamp runs a shell command that creates the appropriate target directory and copies the $File into it. It then sets $HasAttachments to true and finally, sets the original $File attribute to the attachment directory. This last bit means I can click on that little folder icon and it will open the folder in Finder.
I'm using a simpler file tree using subfolders based on the year in the Identifier:
.
└── 2024
├── 20241125T121015
│ └── USPS-OM-2n.pdf
└── 20241125T143431
└── Donation Receipt — Thank you from the Internet Archive.eml
It probably seems more complicated than it is. The whole process is
- Drag file onto the document
- Select "Attach file" from the Stamps menu.
If this all seems terribly overwrought, that's because it is. I just wanted to see if I could do it. It's not exactly the same as Org mode, but it's close enough for who it's for.
Member discussion