-
-
Save ferenczy/040cd74c22f44a46e093575b5e1e2862 to your computer and use it in GitHub Desktop.
/** | |
* Get lost unsaved buffers in Atom editor | |
* | |
* Load text content of all unsaved buffers stored by Atom for any project in IndexedDB and print it to Developers tools console | |
* | |
* Author: David Ferenczy Rogožan (https://ferenczy.cz) | |
* | |
* Instructions: | |
* | |
* 1. Start Atom | |
* 2. Open Developer tools (Ctrl + Shift + I) | |
* 3. Open the tab _Sources_ and in the left panel, open the tab _Snippets_ | |
* 4. Click _New snippet_ | |
* 5. Give it whatever name and paste this file into the snippet | |
* 6. Press Ctrl + Enter to run it | |
* 7. The console should contain all stored unsaved buffer content, you can copy&paste it directly from there or open the context menu of the console content and use _Save as..._ to store it in a file | |
* | |
* Tested with Atom 1.40.1 x64 on Windows 7 | |
* | |
* Resources: | |
* - https://developers.google.com/web/tools/chrome-devtools/storage/indexeddb#edit | |
* - https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB#Using_a_cursor | |
* | |
**/ | |
// false to log only stored buffer content | |
var DEBUG_OUTPUT = false; | |
var OBJECT_STORE_NAME = 'states'; | |
var CONTENT_STYLE = 'border: 1px solid red; background-color: #FEE; padding: 1em'; | |
var connection = indexedDB.open('AtomEnvironments', 1); | |
connection.onerror = function(e) { | |
console.log('Error opening IndexedDB: ' + e.target.errorCode); | |
console.log(e); | |
}; | |
connection.onsuccess = (e) => { | |
debugLog('Connected to the IndexedDB'); | |
// get handle to the Atom's obbject store `states` | |
var db = e.target.result; | |
var objectStore = db.transaction([OBJECT_STORE_NAME]).objectStore(OBJECT_STORE_NAME); | |
// get cursor to iterate over all items in the `states` object | |
objectStore.openCursor().onsuccess = (e) => { | |
var cursor = e.target.result; | |
if (cursor) { | |
debugLog('Key: ' + cursor.key); | |
// get actuall value of the item | |
var value = cursor.value; | |
debugLog('Strored at: ' + value.storedAt, 1); | |
// we're looking for `buffers` which are stored under the field `value.project` | |
var project = | |
value.value && | |
value.value.project || false; | |
if (project) { | |
var paths = project.paths || []; | |
var buffers = project.buffers || []; | |
debugLog('Paths: ' + paths.join(', '), 1); | |
debugLog(buffers.length ? 'Buffers: ' + buffers.length : '[No buffers]', 1); | |
// iterate through `project`'s buffers | |
buffers.forEach((entry, i) => { | |
debugLog('Buffer #' + (i + 1), 1); | |
// unsaved buffers obviously don't have any `filePath` set | |
// saved buffers have `filePath` filled but don't have any buffer content since it's stored in the actual file | |
// files with unsaved changes will probably have both `filePath` and buffer content filled | |
var filePath = entry.filePath || '[unsaved]'; | |
debugLog('File path: ' + filePath, 2); | |
var text = entry.text || false; | |
if (text) { | |
debugLog('Content:', 2); | |
// log stored buffer text content | |
if (DEBUG_OUTPUT) { | |
// log buffer content synchronized with other logging | |
console.log('%c' + text, CONTENT_STYLE); | |
} | |
else { | |
// use timer so filename and current line is not logged to console | |
setTimeout(console.log.bind(console, '\n%c' + text, CONTENT_STYLE)); | |
} | |
} | |
else { | |
debugLog('[no content stored]', 2); | |
} | |
}); | |
} | |
// iterate to the next item | |
cursor.continue(); | |
} | |
} | |
}; | |
function debugLog(text, indent = 0) { | |
if (DEBUG_OUTPUT) { | |
text = ' '.repeat(indent * 4) + text; | |
console.log(text); | |
} | |
} | |
debugLog('Done.'); |
Thank you! Simple and effective.
I'm glad it helped you guys! It took me quite long time to investigate where and how it's being stored, so I didn't want to keep it for myself. :) Then, it was quite easy to write a simple script.
First off thank you for this, definitely wouldn't have gotten my data back without it.
Not sure if this is something that changed after you wrote this, or just got missed because the focus here was on totally unsaved buffers, but previously saved files with unsaved changes don't use the "text" field, they use "outstandingChanges", which is an array of ascii codes for the changes.
I didn't come up with the cleanest method for getting these, but I replaced lines 78-95 with:
if (filePath.includes("part of file name you are looking for")) {
output="";
entry.outstandingChanges.forEach((e,ii) => {
if (e == "0") {
output = output + " ";
} else {
output = output + String.fromCharCode(e);
}
});
console.log(output);
}
Replacing "part of file name you are looking for" with part of the path to the file with unsaved changes. It won't show deletions well, and some of the changes to my file seemed listed out of order, but it got me the bulk of what I was missing, so hopefully this helps someone else.
thanks bro, you saved me 💯