sublime-evernote icon indicating copy to clipboard operation
sublime-evernote copied to clipboard

Support note guid metadata

Open bordaigorl opened this issue 11 years ago • 10 comments

It could be nice to support a metadata field for the note's guid so that one could maintain a local markdown version of some of his/her notes with full two-way synch facilities.

This needs a "Synch" command that downloads new versions of the note and updates the current view, plus support for user supplied guids in new notes metadata.

bordaigorl avatar Feb 17 '14 08:02 bordaigorl

+1 -- this would be excellent!

Give me a shout if you want help with implementing/testing any of these.

mwcraig avatar Feb 28 '14 22:02 mwcraig

It is not very clear to me what the best behaviour would be. Consider the following: you create a note on Evernote and you want it to be tied to a markdown file in your computer. This would be achieved by having a note-guid metadata field set to the guid of the note. Now, what should happen when you edit the note locally? Probably you want to update the remote note on save. Suppose the remote copy has been changed by other clients. What should happen? Or, suppose you changed the note from a different client, now the local copy is out of synch. Would you need to re-download the new version from the remote every time you open the note? How can you reliably detect the markdown file is in fact an Evernote note and so it should be synchronised with the remote on open? Wouldn't it be a bit inefficient? Once we settle on a viable and well-behaved solution we can start implementing something...

bordaigorl avatar Feb 28 '14 22:02 bordaigorl

I would be inclined to keep things as simple as possible, and make this syncing something that users need to opt-in to use by changing a setting.

For me I see the primary use case as wanting to update an existing evernote note from a local file rather than needing a full two-way sync. That said, some ideas:

  • On first sending a note to evernote from a local file the note-guid is added to the meta data.
  • If a local note is created by "Open Evernote Noteitsnote-guid`` is set in the metadata.
  • On save of a local note a check is done of whether the evernote note has changed (not positive this is possible, but assume it is). If there is a conflict of any kind, i.e. if the note on Evernote has been modified at all since the last save to/open from evernote of this note, the user is presented with a dialog offering to:
    • Overwrite the remote note with the local.
    • Overwrite the local note with the remote.
    • Make a new remote note from this local note.
    • Break this note's link with evernote by removing its note-guid
  • On open of a local note, assuming this behavior can be restricted to markdown files only...
    • Check whether there is metadata with a note-guid entry. If no, nothing further needs to be done.
    • If there is a note-guid ~~compare the last modifcation time of the local note and the evernote note~~ Never mind, comparison based on times won't work well because times are always going to be different.
    • If there is a note-guid, generate the HTML content of the local file and compare it to the HTML content of the Evernote note. If they differ, offer the same options as above, under saving.

I know this isn't really a sync at all because it doesn't try to merge the contents of a local and remote note that differ. I'd be inclined to not attempt a real sync solution.

One alternative that would capture the use case I'm most interested in is to check, when Send to Evernote is run, whether there are any existing notes with the same metadata (i.e. title, notebook, tags( and if there is ask whether a new evernote note should be created or whether the existing note should be overwritten.

That would remove the need for any checking on open because there is nothing to check until the user sends the note to evernote. It also avoids giving the impression that the plugin can do syncing, it is just a little more helpful about deciding what the destination on evernote should be.

Note also that the same issues, of a note being modified on evernote while also being modified locally, already exists in the current implementation. Once I've done a Send to Evernote I can edit the note in ST or in Evernote...but when I save in ST any remote changes are discarded.

I'm actually fine with that behavior.

mwcraig avatar Mar 01 '14 03:03 mwcraig

I think checking for notes with the same title and in the same notebook, offering a choice for action, is the best option. The only downside is efficiency: every time you send/update a note you have to run a search. Maybe a setting/argument turning this on/off could be just fine.

bordaigorl avatar Mar 01 '14 16:03 bordaigorl

I think the search only needs to be done once per sessions, either when you open (which might be pretty inefficient doing it for every note) or the first time after a buffer is opened that send to evernote is invoked.

After that the current mechanism of storing the note guid in the view metadata works fine.

mwcraig avatar Mar 01 '14 18:03 mwcraig

It is still a bit unclear to me how to make this both robust and fast.

A couple of observations.

Detecting an Evernote Note file

I think trying to parse metadata on open is not a great idea, especially if you are thinking of doing this upon opening any file.

A more direct and extendible approach could be to introduce an Evernote Note syntax definition (which will include the markdown one) and link that to a file extension such as .enmd (for Evernote Note MarkDown).

Then we can define EventListeners for these files only.

Difference between Save and Send?

If we modify the send-to-en command to check whether a note with the same title in the same notebook already exists then we may try to unify the send and save commands.

Detecting changes

There are three problems related to detecting changes in the notes:

  1. how to understand if the current version is newer than the one online. This can be partially supported by using the updateSequenceNum field of a note, which is much more robust than time-stamps.
  2. This however implies we store this number in the metadata and that we update it when saving. Which can be a bit fragile, especially since the user can (accidentally?) modify it.
  3. If we do not have a reliable update checking mechanism, then we might need to nag the user with warnings about possible data-loss when updating which is not great.

There is an alternative much weaker option. One could detect whether the note has been edited by another client by checking whether the hidden comment the plugin injects is present or not. If it is present, the contents could be checked for equality with the current contents of the local note.

Current status

Other Evernote clients are already struggling with conflicting versions of notes, I would like this plugin to be very explicit in what's the effect of the commands. No magic should be happening. If you send to evernote, that should mean that you are writing to the servers what you see. If you open a note from the server than you are looking at the note at the time of the download. The update mechanism breaks this intuition because you now have two versions (the local and the online) that can diverge arbitrarily (plus the local metadata can be modified at will). This can cause a lot of confusion.

I propose the following:

  1. Evernote syntax to make clear we are reading a note
  2. Save to Evernote command with search for existing notes with same notebook&title with prompt for overwrite. Option to switch off the prompt until the end of the session. Optional EventListener for update-on-save.
  3. No note-guid metadata
  4. Add a Re-Open command that finds the note online (according to metadata) and rewrites the contents of the view with the online version. Maybe implement the weaker form of update-check as detailed before, to prompt the user.

bordaigorl avatar Mar 04 '14 16:03 bordaigorl

This is why it is good you are taking the lead on this -- I tend to code first and ask questions later, which is definitely not the right approach here. :)

I think your proposal is the way to go, just a couple questions about specifics:

  1. Evernote syntax to make clear we are reading a note

Not sure what you mean here--clarification of the docs? or of status messages? Something else? Don't have strong feelings about what happens here, just not following what you mean.

In general I agree that there should be no magic and the plugin should be clear about what it is doing.

  1. Save to Evernote command with search for existing notes with same notebook&title with prompt for overwrite.

I assume the options will be to overwrite, add new note or cancel? If so, sounds good. I imagine there will be people who want to have two notes with the same name in the same notebook. Both the optional pieces sound perfect.

4...Maybe implement the weaker form of update-check as detailed before, to prompt the user.

I'm not sure this is necessary...by clarifying that a Save to evernote is always a one-way push to evernote and that a Re-Open or Open is always a one-way pull from evernote the user is put in the position of needing to decide which is desirable.

Re-Open from could maybe require user confirmation, though personally I'd get tired of that pretty fast...perhaps an initial warning that the local note view will be overwritten with an option to disable the warning for the rest of the session, like in Save to Evernote?

mwcraig avatar Mar 04 '14 19:03 mwcraig

I am glad we are converging to something feasible.

Evernote syntax to make clear we are reading a note

Not sure what you mean here--clarification of the docs? or of status messages? Something else? Don't have strong feelings about what happens here, just not following what you mean.

I mean the following: suppose you have a bunch of markdown files containing some of your notes. Now you open one of them. You would like ST to understand it is not just a md file but it is actually an evernote note. How can you do that? The way this is usually dealt with in ST is by having a custom extension for those files, associated with a Syntax file that sets some outer scope like text.html.markdown.evernote. This way you can make keymaps and commands fire only when you are in that scope. Plus you can add highlighting for custom elements (such as the metadata block).

To get some early feedback I put together a simple implementation of the idea in commit d3cd4d74c89eda35d42dc915998cfcc1e85b4418. To test it simply set "md_syntax": "Packages/Evernote/Evernote.tmLanguage" in your Evernote.sublime-settings and open a note (either from Evernote or from a .enmd file). The commands are still not dependent on the scope but you should get the idea. One shortcoming of this is that your Markdown.sublime-settings would not apply anymore to these files so you may need to copy them over to Evernote.sublime-settings which could lead to undesirable duplication. What do you think?

Notes with same notebook/title can be a pain indeed. I am thinking of a pallette showing options for each matching note; it could be cumbersome to display them so they are distinguishable for the user! On the other hand, storing the note-guid has the same problems as storing the USN (how to update its value, accidental modifications). Any ideas?

I agree the weaker update detection is not very useful. The re-open feature could easily support a "don't nag me again for this session" option.

bordaigorl avatar Mar 05 '14 12:03 bordaigorl

One shortcoming of this is that your Markdown.sublime-settings would not apply anymore to these files so you may need to copy them over to Evernote.sublime-settings which could lead to undesirable duplication.

I've been using MarkdownExtended for highlighting my markdown files; it looks like what you have implemented does everything that that does--i.e. highlighting metadata, fenced code blocks, so I don't think there is an issue.

Didn't encounter any issues in the short try I gave the latest version.

I assume one could always manually invoke the commands even if one didn't use the .enmd extension?

Notes with same notebook/title can be a pain indeed. I am thinking of a pallette showing options for each matching note...Any ideas?

I'd lean towards simply generating a list of all matching notes with the user prompted to select either the one they want to overwrite or creating a new note with the same title. That list will become cluttered/confusing only if the user is in the habit of creating many noes in the same notebook with the same title...and there are probably limits to what can be done to accommodate those users.

Maybe including the first part of the first sentence in generating the list of matching would help? Or the date of creation or last modification (pulled from the metadata of the note(s) on evernote)?

In terms of UI I was thinking something like the dropdown list that comes up if a notebook isn't specified in the metadata when you do the Send to Evernote. The list would look something like this:

Select existing note below to overwrite that note or New Note
note_with_same_name -- creation_date_here
note_with_same_name -- creation_date_here
note_with_same_name -- creation_date_here
New Note

This would provide some way for a user with a bunch of duplicate names to disnguish between the notes and shouldn't require any local record-keeping if note creation/modification dates can be pulled from the metadata of notes downloaded from evernote.

I don't think there needs to be a palette of options next to each matching note--basically the only bit of information needed from the user is whether to match a local to a remote note and if so, which remote note.

mwcraig avatar Mar 05 '14 20:03 mwcraig

+1 for this feature. It would even be really useful if it only associated Markdown files with Evernote notes by guid and then synced local updates to read-only notes in Evernote. This would avoid the problem of needing to merge in remote updates.

csu avatar Aug 28 '15 06:08 csu