├── .gitignore ├── img ├── 1.png ├── 2.png ├── 3.png └── 4.png ├── 3_Restore_Directly_to_v0.md ├── README.md ├── 1_Save_Snapshot.md └── 2_Compare_or_Restore_Snapshot.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | 4 | *.plist 5 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism/master/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism/master/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism/master/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism/master/img/4.png -------------------------------------------------------------------------------- /3_Restore_Directly_to_v0.md: -------------------------------------------------------------------------------- 1 | # A third little script - Restore Directly to v0 2 | 3 | ```applescript 4 | 5 | -- Restore Directly to v0 6 | 7 | -- bcdavasconcelos 2020-06-09-12-12-27 8 | -- https://github.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism 9 | 10 | -- **Do not use this as a backup mechanism.** 11 | -- These snapshots should be considered *a convenience* for editing plain text. 12 | -- It was not intended to protect from loss of data. 13 | 14 | tell application id "DNtp" 15 | 16 | set theRecord to (content record of think window 1) 17 | set thePath to the path of theRecord -- Get the file path 18 | 19 | set theText to the plain text of theRecord 20 | 21 | set theText to get custom meta data for "v0" from theRecord default value "" 22 | 23 | set the plain text of theRecord to theText 24 | 25 | log message "Version restored" info "Restored to template version " & ((current date) as string) -- 26 | 27 | end tell 28 | 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | GitHub Last Commit GitHub Issues 2 | 3 | 4 | # A Snapshots Mechanism for DEVONthink 3 5 | 6 | ## Warning 7 | 1. **Do not use this as a backup mechanism.** These snapshots should be considered *a convenience*. It was not intended to protect from loss of data. There is no safety net here. 8 | 2. These are **potentially destructive** scripts. **You cannot ⌘Z your way out of changes made by scripts.** 9 | 3. Finally, this is intended for markdown and/or plain text **only**. 10 | 11 | *** 12 | 13 | # The first script: Save Snapshot 14 | 15 | The idea is very simple. I created custom metadata fields to store snapshots of the text (**v1**-**v9**) and the modification time (**d1**-**d9**). The [first script](1_Save_Snapshot.md) is for *storing the text*. It will store the current text in v1 and throw what was in v1 to v2, what was in v2 to v3 and so on. What was in v9 says goodbye. 16 | 17 | ![][image-1] 18 | 19 | *I keep it at the bottom, so I don't see it if I don't want to.* 20 | 21 | 22 | *** 23 | 24 | # The second script: Compare/Restore Snapshot 25 | 26 | The [second script](2_Compare_or_Restore_Snapshot.md) is for *restoring a snapshot*. When it is activated, it will ask whether you want to compare snapshots using BBEdit (could have used filemerge or something else, but I like BBEdit and you can install it for free) or simply restore to one of the previous snapshots. 27 | 28 | ![][image-2] 29 | 30 | The next dialog will prompt for the desired snapshot to be compared or restored. 31 | 32 | 33 | ![][image-3] 34 | 35 | If you chose to **restore**, that's it. The script will do so by replacing the text of the record by the stored snapshot and it will log the change in DEVONthink (I like how discrete the log is and prefer it over the notification function). If you chose to **compare** instead, you *can* make the changes you want and then *save*. 36 | 37 | *Here is the compare window open in BBEdit.* 38 | 39 | ![][image-4] 40 | 41 | *** 42 | 43 | # A third little script - Restore Directly to v0 44 | 45 | Side-note: I am also keeping a v0, which is sort of a template for the note and which won't be touched by the first script. I also set up a special shortcut to restore directly to this snapshot without any prompts. This will be the [third script](3_Restore_Directly_to_v0.md). 46 | 47 | 48 | [image-1]: img/1.png 49 | [image-2]: img/2.png 50 | [image-3]: img/3.png 51 | [image-4]: img/4.png 52 | 53 | #Applescript #DEVONthink 54 | -------------------------------------------------------------------------------- /1_Save_Snapshot.md: -------------------------------------------------------------------------------- 1 | # Save Snapshot 2 | 3 | ```applescript 4 | 5 | -- Save Snapshot 6 | 7 | -- bcdavasconcelos 2020-06-09-12-10-14 8 | -- https://github.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism 9 | 10 | -- **Do not use this as a backup mechanism.** 11 | -- These snapshots should be considered *a convenience* for editing plain text. 12 | -- It was not intended to protect from loss of data. 13 | 14 | tell application id "DNtp" 15 | -- set theRecords to the selection 16 | -- repeat with theRecord in theRecords 17 | set theRecord to (content record of think window 1) 18 | 19 | set theText to the plain text of theRecord 20 | set theNewMod to the modification date of theRecord 21 | 22 | set theOldBackup to get custom meta data for "v9" from theRecord default value "" 23 | add custom meta data theOldBackup for "v10" to theRecord 24 | 25 | set theOldBackup to get custom meta data for "v8" from theRecord default value "" 26 | add custom meta data theOldBackup for "v9" to theRecord 27 | 28 | set theOldBackup to get custom meta data for "v7" from theRecord default value "" 29 | add custom meta data theOldBackup for "v8" to theRecord 30 | 31 | set theOldBackup to get custom meta data for "v6" from theRecord default value "" 32 | add custom meta data theOldBackup for "v7" to theRecord 33 | 34 | set theOldBackup to get custom meta data for "v5" from theRecord default value "" 35 | add custom meta data theOldBackup for "v6" to theRecord 36 | 37 | set theOldBackup to get custom meta data for "v4" from theRecord default value "" 38 | add custom meta data theOldBackup for "v5" to theRecord 39 | 40 | set theOldBackup to get custom meta data for "v3" from theRecord default value "" 41 | add custom meta data theOldBackup for "v4" to theRecord 42 | 43 | set theOldBackup to get custom meta data for "v2" from theRecord default value "" 44 | add custom meta data theOldBackup for "v3" to theRecord 45 | 46 | set theOldBackup to get custom meta data for "v1" from theRecord default value "" 47 | add custom meta data theOldBackup for "v2" to theRecord 48 | 49 | set theMod to get custom meta data for "v9" from theRecord default value "" 50 | add custom meta data theMod for "v10" to theRecord 51 | 52 | set theMod to get custom meta data for "d8" from theRecord default value "" 53 | add custom meta data theMod for "d9" to theRecord 54 | 55 | set theMod to get custom meta data for "d7" from theRecord default value "" 56 | add custom meta data theMod for "d8" to theRecord 57 | 58 | set theMod to get custom meta data for "d6" from theRecord default value "" 59 | add custom meta data theMod for "d7" to theRecord 60 | 61 | set theMod to get custom meta data for "d5" from theRecord default value "" 62 | add custom meta data theMod for "d6" to theRecord 63 | 64 | set theMod to get custom meta data for "d4" from theRecord default value "" 65 | add custom meta data theMod for "d5" to theRecord 66 | 67 | set theMod to get custom meta data for "d3" from theRecord default value "" 68 | add custom meta data theMod for "d4" to theRecord 69 | 70 | set theMod to get custom meta data for "d2" from theRecord default value "" 71 | add custom meta data theMod for "d3" to theRecord 72 | 73 | set theMod to get custom meta data for "d1" from theRecord default value "" 74 | add custom meta data theMod for "d2" to theRecord 75 | 76 | add custom meta data theNewMod for "d1" to theRecord 77 | add custom meta data theText for "v1" to theRecord 78 | 79 | log message "New version saved" info "Saved at " & ((current date) as string) 80 | 81 | end tell 82 | 83 | ``` 84 | -------------------------------------------------------------------------------- /2_Compare_or_Restore_Snapshot.md: -------------------------------------------------------------------------------- 1 | # The second script: Compare/Restore Snapshot 2 | 3 | ```applescript 4 | 5 | -- Compare/Restore Snapshot 6 | 7 | -- bcdavasconcelos 2020-06-09-12-12-02 8 | -- https://github.com/bcdavasconcelos/DEVONthink-3-Snapshot-Mechanism 9 | 10 | -- **Do not use this as a backup mechanism.** 11 | -- These snapshots should be considered *a convenience* for editing plain text. 12 | -- It was not intended to protect from loss of data. 13 | 14 | 15 | tell application id "DNtp" 16 | set theRecord to the (content record of think window 1) 17 | 18 | 19 | set theOpts to {"Compare", "Restore", "Cancel"} 20 | set theAnswer1 to the button returned of (display dialog "Hi, I am Hal. What can I do for you?" buttons theOpts default button 1) 21 | 22 | set d0 to get custom meta data for "d0" from theRecord default value "" as string 23 | set myDateString0 to "v0 Template" 24 | 25 | try 26 | set d1 to get custom meta data for "d1" from theRecord default value "" as string 27 | set myDateString1 to ("v1" & " " & (month of d1) & " " & (day of d1) & ", " & (year of d1) & " - " & (time string of d1)) as string 28 | on error 29 | set myDateString1 to "" 30 | end try 31 | 32 | try 33 | set d2 to get custom meta data for "d2" from theRecord default value "" as string 34 | set myDateString2 to ("v2" & " " & (month of d2) & " " & (day of d2) & ", " & (year of d2) & " - " & (time string of d2)) as string 35 | on error 36 | set myDateString2 to "" 37 | end try 38 | 39 | try 40 | set d3 to get custom meta data for "d3" from theRecord default value "" as string 41 | set myDateString3 to ("v3" & " " & (month of d3) & " " & (day of d3) & ", " & (year of d3) & " - " & (time string of d3)) as string 42 | on error 43 | set myDateString3 to "" 44 | end try 45 | 46 | try 47 | set d4 to get custom meta data for "d4" from theRecord default value "" as string 48 | set myDateString4 to ("v4" & " " & (month of d4) & " " & (day of d4) & ", " & (year of d4) & " - " & (time string of d4)) as string 49 | on error 50 | set myDateString4 to "" 51 | end try 52 | 53 | try 54 | set d5 to get custom meta data for "d5" from theRecord default value "" as string 55 | set myDateString5 to ("v5" & " " & (month of d5) & " " & (day of d5) & ", " & (year of d5) & " - " & (time string of d5)) as string 56 | on error 57 | set myDateString5 to "" 58 | end try 59 | 60 | try 61 | set d6 to get custom meta data for "d6" from theRecord default value "" as string 62 | set myDateString6 to ("v6" & " " & (month of d6) & " " & (day of d6) & ", " & (year of d6) & " - " & (time string of d6)) as string 63 | on error 64 | set myDateString6 to "" 65 | end try 66 | 67 | try 68 | set d7 to get custom meta data for "d7" from theRecord default value "" as string 69 | set myDateString7 to ("v7" & " " & (month of d7) & " " & (day of d7) & ", " & (year of d7) & " - " & (time string of d7)) as string 70 | on error 71 | set myDateString7 to "" 72 | end try 73 | 74 | try 75 | set d8 to get custom meta data for "d8" from theRecord default value "" as string 76 | set myDateString8 to ("v8" & " " & (month of d8) & " " & (day of d8) & ", " & (year of d8) & " - " & (time string of d8)) as string 77 | on error 78 | set myDateString8 to "" 79 | end try 80 | 81 | try 82 | set d9 to get custom meta data for "d9" from theRecord default value "" as string 83 | set myDateString9 to ("v9" & " " & (month of d9) & " " & (day of d9) & ", " & (year of d9) & " - " & (time string of d9)) as string 84 | on error 85 | set myDateString9 to "" 86 | end try 87 | 88 | 89 | set l to {myDateString0, myDateString1, myDateString2, myDateString3, myDateString4, myDateString5, myDateString6, myDateString7, myDateString8, myDateString9} as list 90 | set theAnswer to (choose from list l with prompt {"Wise decision. 91 | Now, choose your destiny..."} default items "") 92 | 93 | set theAnswer to item 1 of theAnswer 94 | if theAnswer contains "v0" then set theAnswer to "v0" 95 | if theAnswer contains "v0" then set theTime to "Template" 96 | 97 | if theAnswer contains "v1" then set theAnswer to "v1" 98 | if theAnswer contains "v1" then set theTime to "d1" 99 | 100 | if theAnswer contains "v2" then set theAnswer to "v2" 101 | if theAnswer contains "v2" then set theTime to "d2" 102 | 103 | if theAnswer contains "v3" then set theAnswer to "v3" 104 | if theAnswer contains "v3" then set theTime to "d3" 105 | 106 | if theAnswer contains "v4" then set theAnswer to "v4" 107 | if theAnswer contains "v4" then set theTime to "d4" 108 | 109 | if theAnswer contains "v5" then set theAnswer to "v5" 110 | if theAnswer contains "v5" then set theTime to "d5" 111 | 112 | if theAnswer contains "v6" then set theAnswer to "v6" 113 | if theAnswer contains "v6" then set theTime to "d6" 114 | 115 | if theAnswer contains "v7" then set theAnswer to "v7" 116 | if theAnswer contains "v7" then set theTime to "d7" 117 | 118 | if theAnswer contains "v8" then set theAnswer to "v8" 119 | if theAnswer contains "v8" then set theTime to "d8" 120 | 121 | if theAnswer contains "v9" then set theAnswer to "v9" 122 | if theAnswer contains "v9" then set theTime to "d9" 123 | 124 | set theName to the name of theRecord 125 | set thePath to the path of theRecord -- Get the file path 126 | 127 | set theText to the plain text of theRecord 128 | 129 | set theText to get custom meta data for (theAnswer as text) from theRecord default value "" 130 | try 131 | set theTime to get custom meta data for (theTime as text) from theRecord default value "" 132 | set theTime to ((year of theTime) & "-" & (month of theTime) & "-" & (day of theTime) & "-" & (time string of theTime)) as string 133 | set theTime to my replaceText(theTime, ":", "-") 134 | on error 135 | set theTime to "Template" 136 | end try 137 | -- set docName to theName & " " & theTime as text 138 | 139 | if theAnswer1 is "Restore" then 140 | set the plain text of theRecord to theText 141 | log message "Version restored" info (theAnswer as text) & " " & theTime as text 142 | end if 143 | 144 | if theAnswer1 is "Compare" then 145 | set docName to theTime as text 146 | set _text to theText 147 | tell application "BBEdit" 148 | 149 | set tempFilePath to (path to temporary items as text) & docName 150 | set newDoc to make new document with properties {text:_text} initial save location tempFilePath 151 | save newDoc 152 | close newDoc 153 | -- open newDoc 154 | set theResult to compare file (thePath as POSIX file) against file (tempFilePath as alias) 155 | activate 156 | end tell 157 | end if 158 | end tell 159 | 160 | 161 | on replaceText(theString, old, new) 162 | set {TID, text item delimiters} to {text item delimiters, old} 163 | set theStringItems to text items of theString 164 | set text item delimiters to new 165 | set theString to theStringItems as text 166 | set text item delimiters to TID 167 | return theString 168 | end replaceText 169 | ``` 170 | --------------------------------------------------------------------------------