Add specific Draft syntax triggered additon of tags

Hello Greg,

Evernote has an interesting feature: if you email a note to your evernote account, you can automatically have evernote file it in the proper notebook simply by putting @notebookname in the subject line.

I know that I cannot email notes into Drafts but the idea of automatic syntax generated tags is interesting.
I would certainly never use @ as a marker for a tag, but let’s say that a text contains //greg;, drafts would scan the note and automatically add the tag greg.

With Bear, it’s possible to automatically add a ‘greg’ tag, simply by typing #greg anywhere in the text. The idea is extremely interesting and useful. In practise, it’s a disaster with Bear because any text containing hashtags creates tags. It’s just a question of using the right syntax which is complicated enough and not commonly found in texts.

This would accelerate workflow because there are many situations where I create a draft, and then have to enter the tags manually instead of just saving automatically and let Drafts do the tagging.

There are other situations for example I use Popclip a lot with Drafts Mac.

If I select text in any application → popclip → create Draft (something I do 10 times a day), I then have to go to Drafts and start fishing for the newly created Draft to add tags which involves exiting the workspace I was working it, or clicking on recent drafts etc.

In general, I think that the whole process of tag creation slows down workflow and is a small weakness of Drafts.

thank you.

Back in 2010 I was in a Twitter chat with Phil Libin (former Evernote CEO) where I was posting with my old handle of @rebootit and suggested mail-in processing/routing options, so I like to think I had a hand in bringing that feature to Evernote :slight_smile:

In terms of quick entry, pretty much everything you have noted would be possible with actions I think. You could have an action that scans a draft for syntax and adds each it finds as a tag to the draft. You could have a pop-up dialog that pre-populates with selected text to allow quick addition of new tags. There are lots of ways to tie this to your own preferred workflow.

The issue with processing the text as you type is that, as you pointed out, the risk of false positives. Being able to trigger things only when you are ready to I think for this sort of situation actually gives you the more powerful and reliable approach.

1 Like

Evernote: congratulations. It was a great idea. I was impressed by his enthusiastic reply.

Action: a very nice idea, unfortunately way beyond my scripting abilities.

thank you for your interesting reply.

I will take baby steps.

glossary:
tags means tags
pre-tags means those words in the draft text which I want to convert to tags

1- what in your opinion is a good - less likely to lead to false positives albeit easy to read and write - syntax for tags ?

2- scans a draft for syntax and adds each it finds as a tag to the draft
would you start by listing all pre-tags in an array, and then create all the tags at once or search → pre-tag → tag each time a pre-tag is found ? I imagine that there is no problem adding the same tag multiple times?

3- the add tag part would look like
draft.addTag(“pre-tag”);
draft.update();

so it would be
a- javascript : search for pre-tag by syntax
when find a pre-tag
draft.addTag(“pre-tag”);
draft.update();
if end of draft stop, otherwise loop back to a

thank you

That could be anything really.

Some examples might be:

  1. Using unique but related delimiters like you might with many SGML-based formats (HTML, XML, etc.)
<tag>foo</tag>
  1. Identical delimiters
:::bar:::
  1. A prefix that assumes any whitespace, line or content ending implicitly marks the end.
+++quz
  1. A suffix that assumes any whitespace, line or content start implicitly marks the beginning.
qux%%

The precise choice is simply a matter of taste and how it might be interpreted by the syntax you are using (remember custom syntax highlighting is on the roadmap), and actions. There may not be something perfect for all circumstances. In terms of creating an action, I would certainly make things easily configurable so that if in the future I found I needed to change my syntax a little, I could perhaps amend just one or perhaps a handful (if I wanted to allow for all four approaches above for example) of constants at the start of the script to do so.

If a tag has already been added then adding it a second time has no effect. It would be more efficient to deduplicate any pre-tag array compiled, but honestly, given the number of tags and the speed of i*OS and Drafts, I doubt a human could measure the difference in efficiency without the script logging the processing times.

I would certainly parse the content, split out tags and push them into a pre-tag array, then process that array to add the tags to the draft, and finally, consider offering an option to remove all pre-tag instances in the content. I’m assuming that once the tags are applied, having them in the body would no longer be required in most, if not all, circumstances.

The parsing process has a number of ways it could be done. Regular expression matches, splitting the content string (tokenising) and taking alternating entries from the resulting array, searching for positions and moving on, or removing and processing the string again (recursive approach) until nothing remains.

2 Likes

I made a basic implementation of what i guess you might Need:


// choose a good prefix for tags which will work in all your draft contents - e.g. if you script a lot in Drafts, it won't be good to choose "//" as a prefix...
const tagPrefix = "+++"

let cont = draft.content;

// execute as long as the prefix exists in the drafts content.
while (cont.indexOf(tagPrefix) != -1) {
  let posOfPrefix = cont.indexOf(tagPrefix)
  let tagStartPos = posOfPrefix + tagPrefix.length;
  let tagEndPos = 0;
  let devider = ' ';
  if (cont.indexOf(' ', posOfPrefix + tagPrefix.length) == -1) {
    tagEndPos = cont.indexOf('\n', posOfPrefix + tagPrefix.length);
    devider = '\n';
  } else {
    tagEndPos = cont.indexOf(' ', posOfPrefix + tagPrefix.length);
  }
  tagStr = cont.slice(tagStartPos,tagEndPos);

  draft.addTag(tagStr);

  draft.update();
  cont = cont.replace(tagPrefix+tagStr,devider);
  
}

draft.content = cont;
draft.update();

Choose a prefix in the beginning, ist will just work if the character After the tag you choose is a Space or a newline.
The tags will be removed from the text

1 Like

thanks very much for your detailed response.
If Bear bungled in a major way assigning # to tags, and probably lost many members in the process, I thought it best to consult you.

I am going to try out your script. I would like to tell you that your help and contribution are greatly greatly appreciated. Thanks very much !

Just a couple of general comments from my programmer brain about mixing meta-data with content…

It’s best to segregate it in some way. Like using front matter separated by a delimiter (like Jekyll uses YAML, or by using a marker to dedicate lines as meta-data, like only lines starting with a certain special character are looked at for meta data.

This makes is easy to both scan the document for lines with meta data, and easy to strip the meta data out of the content…so, the action that looks for tags, could read them, assign them to the draft, and remove the markup that assigned the tags. Still lots of ways to do this, but you might do something like only look for lines that start with and exclamation point and parse those as tags.

assuming that my tags are script java tag
something like
+++ script java tag
with no special syntax for the tags ?

You have done a lot already !

I tested the script and it works fine.

1- I wanted to keep the tags in the text instead of deleting them. I tried commenting out the following line but it just made the action crash
// cont = cont.replace(tagPrefix+tagStr,devider);

2- if it is not a lot of work, how complicated would it be to use Greg‘s method with a line delimiter, for example the tag line starting with +++.
Example : 3 tags script java action, is it possible for the script to read the line
+++ script java action (with a newline)
conclude that script java and action are 3 tags and add them to the draft ?

thanks again very muc

Should be possible - a bit of work but in the and simpler.
The problem with just removing the replace line is, that you will end up in a endless loop… this is something which can be worked around:)
It simply belongs on what you want.
A line with multiple tag (no spaces in a tag) prefixed with e.g. +++
Or do you simply want to add each tag with +++ somewhere in the draft.

The best thing would be to provide a sample text with your most preferred way to place the tags in the draft.
Then I can sit down tomorrow and work this out;)

1 Like

Thank you very much for your offer !.

1- I do not want to remove the tags in the draft text itself

2- line with multiple tag (no spaces in a tag) prefixed with e.g. +++ I don’t know if defining a line which would apply to both iphone and mac screen real-estate is a problem ?

3- Drafts allows for free spaces in tags. If your method does not, no problem, or should I simply write ‘time machine’ with quotes instead of time-machine ?

thanks again

example:

About Time Machine local snapshots

+++ mac, time-machine (or 'time machine?), backup,free-space, snapshots, terminal

Time Machine lets you restore files from local snapshots of the files on your Mac, even when your Time Machine backup disk isn’t available.

Your Time Machine backup disk might not always be available, so Time Machine also stores some of its backups on your Mac. These backups are called local snapshots.

How to use local snapshots
If you enter Time Machine when your backup disk isn’t available, Time Machine automatically uses local snapshots to help you restore files. Reconnect your backup disk to make even more backups available.

You can view your local snapshots in Terminal mode like so: $tmutil listlocalsnapshots /
`check free space before, after
example
com.apple.TimeMachine.2017-12-14-173102
com.apple.TimeMachine.2017-12-14-212356
com.apple.TimeMachine.2017-12-15-052254
com.apple.TimeMachine.2017-12-15-084940
com.apple.TimeMachine.2017-12-15-094508
com.apple.TimeMachine.2017-12-15-121635

So here is another Try,
Everything in the line with the prefix will be a tag, dont use „“ to Mark your tags, just separate them with a Comma! If there is a leading or trailing Space at the tag, it will not be removed from the tag, a space in a tag, e.g. „my tag“ will work.

Try it out and Tell me if this is what you are searching for:

// add tasks from prefix in draft content
// choose a good prefix for tags which will work in all your draft contents - e.g. if you script a lot in Drafts, it won't be good to choose "//" as a prefix...
const tagPrefix = "+++"

let cont = draft.content;

// assuming the draft contains the tags to be added in one or multiple lines starting with the defined prefix. If more tags should be added, they are separated by a comma ','!

let lines = cont.split('\n');

for (line of lines) {
	if (line.startsWith(tagPrefix)) {
		//this is a line with tags.
		var tags ="";
			if (line.startsWith(tagPrefix + ' ')){
				tags = line.replace(tagPrefix + ' ','');
			} else {
				tags = line.replace(tagPrefix,'');
			}
		for (tag of tags.split(',')){
			if (tag.charAt(0) == ' ') {
				tag = tag.substr(1);
			}
			
			if (tag.charAt(tag.length - 1) == ' ') {
				tag = tag.substr(0);
			}
			draft.addTag(tag);
			draft.update();
		}		
	}
}

1 Like

absolutely perfect and thank you very very much for everything including being allowed to have spaces in tag, which means that I won’t have to redo my tag list.
I am very grateful for your efforts.
It makes a big difference in my workflow

1 Like

What is this sorcery speak off?

I wish I had Enough knowledge to understand what you’re talking about. It’s like listening to a foreign language. I can understand what I’m hearing I can’t speak it or spell it.

Can you recommend a beginners guide or somewhere I can go to start to learn this in more detail?

What is it you are wanting to learn more about?

If it is just terminology, then a search engine should suffice.

If it is “everything”/“stuff”, that comes down to decades of experience (self study, schooling, day job).

If it is something specific like JavaScript or regular expressions, then I’m pretty sure I could point you to a useful guide.

If you have a specific query on something I’ve posted, I’m always happy to try and clarify it and explain in another way.

1 Like

yeah – you’ve got me, it’s more of a everything/staff approach and I think that the self-study route in the long term it’s going to be the way forward.

I guess what I’m interested in is being able to understand scripts. How to make them what the languages and how to execute the magic I see you wall doing. I think it’s empowering to know how to do this kind of thing and honestly… i’d love my kids to have more command over this type of thing by the time they’re old enough to understand it then I do right now.

I guess I’m looking for a head start for their sake as well as my own.