├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── lib ├── config.coffee ├── files.coffee ├── save-prompt.coffee └── save-session.coffee ├── package.json ├── preview.gif └── spec ├── config-spec.coffee ├── files-spec.coffee └── save-prompt-spec.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules 4 | projects/ 5 | .npmignore 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | notifications: 4 | email: 5 | on_success: never 6 | on_failure: change 7 | 8 | script: 'curl -s https://raw.githubusercontent.com/atom/ci/master/build-package.sh | sh' 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 0.16.0 2 | * Deprecated Save Session for 1.4.0 3 | 4 | ## 0.15.7 5 | * phord fixed some cache issues. 6 | 7 | ## 0.15.6 8 | * Updated the readme to reference a more up-to-date issue. 9 | 10 | ## 0.15.5 11 | * Made the specs run... Poorly. 12 | 13 | ## 0.15.4 14 | * Fixed some issues an undefined function. 15 | 16 | ## 0.15.3 17 | * May have fixed the `getPath` issue. 18 | 19 | ## 0.15.2 20 | * Removed the "what is saved" section of the readme. 21 | 22 | ## 0.15.1 23 | * Fixed a deprecation issue. 24 | * Updated readme since so much functionality has been removed. 25 | 26 | ## 0.15.0 27 | * WARNING: This may not be compatible with older versions. Save your files 28 | before updating 29 | * Undeprecated the package. 30 | * Removed a lot of code for managing the state of Atom. 31 | * Now this package only saves unsaved buffers. 32 | 33 | ## 0.14.0 34 | * Deprecated the package since the functionality has been added to Atom core. 35 | 36 | ## 0.13.5 37 | * Added another check to project paths to help prevent an error. 38 | 39 | ## 0.13.4 40 | * Fixed an issue where the package wouldn't activate. 41 | 42 | ## 0.13.3 43 | * Forgot to move to master on my last push. 44 | * This has 0.13.2's changes. 45 | 46 | ## 0.13.2 47 | * Should more reliably deactivate thanks to JohnMurga. 48 | 49 | ## 0.13.1 50 | * Removed an alert that was left from debugging (sorry), again, thanks to 51 | anthonyraymond for catching this. 52 | 53 | ## 0.13.0 54 | * Big changes here. Mostly thanks to anthonyraymond 55 | * Files are saved far more efficiently. 56 | * Deprecations have been taken care of. 57 | * Some issues have shown up when saving while closing editors, so that is 58 | disabled for now. 59 | * Multiple projects will now be restored on the project tree. 60 | * Probably some other changes as well... 61 | 62 | 63 | ## 0.12.5 64 | * Added some of JohnMurga's changes. 65 | * New windows work better now, but still aren't perfect. 66 | 67 | ## 0.12.4 68 | * Removed some debugging messages. 69 | 70 | ## 0.12.3 71 | * Really fixed the issue from 0.12.2. 72 | * Removed the backwards compatibility for now. 73 | 74 | ## 0.12.2 75 | * Fixed an issue with checking for the path incorrectly. 76 | 77 | ## 0.12.1 78 | * Fixed an issue with saving/opening projects with Atom's new project setup 79 | thanks to smiffy6969. 80 | 81 | ## 0.12.0 82 | * Now saves fullscreen thanks to quarterto. 83 | 84 | ## 0.11.5 85 | * Fixed a deprecation issue. 86 | 87 | ## 0.11.4 88 | * Something went wrong so this version was skipped. 89 | 90 | ## 0.11.3 91 | * Fixed an thrown error in Atom 0.166.0 92 | 93 | ## 0.11.2 94 | * Fixed an `Undefined is not a function` issue with closing the first undefined 95 | buffer. 96 | 97 | ## 0.11.1 98 | * Fixed an issue with opening files without a cursor position 99 | 100 | ## 0.11.0 Added a delay option 101 | * An option was added for an additional delay for saving files after typing. 102 | 103 | ## 0.10.0 Added lot's of tests 104 | * Some refactoring 105 | * Added tests for everything except files 106 | 107 | ## 0.9.0 First steps to saving scroll position 108 | * It will save scrolls when files are normally saved 109 | * It's a little weird because of how Atom restores scrolling. Unfortunately, I 110 | don't have much control over it at the moment. 111 | 112 | ## 0.8.10 Fix for users without an open project 113 | 114 | ## 0.8.9 Another syntax fix... 115 | 116 | ## 0.8.8 Another syntax fix 117 | 118 | ## 0.8.7 Missed an @ symbol... 119 | * Should fix issue #20 now 120 | 121 | ## 0.8.6 Fixed an issue with Windows and saving per project 122 | * Fixes issue #20 123 | 124 | ## 0.8.5 No changes... 125 | 126 | ## 0.8.4 Command for reloading project, Better handing of json errors 127 | * A command called `Reopen Project` will reopen the currently active project. 128 | This was mainly done for development/testing. 129 | * Json errors are handled better, instead of just crashing, it will just delete 130 | the project file and continue restoring. 131 | * Updated readme 132 | 133 | ## 0.8.3 Added descriptions to settings 134 | 135 | ## 0.8.2 Fixed an issue with opening new windows 136 | * Opening a new window (cmd+N) will no longer open the project you were just 137 | working on. It will open up the undefined project. 138 | 139 | ## 0.8.1 Fixed a config issue 140 | 141 | ## 0.8.0 Files open asynchronously, removed `Disable New File On Open Always` 142 | * Files are now opened asynchronously, which should help the initial load time 143 | * The `Disable New File On Open Always` setting has been removed, and is now the 144 | way `Disable New File On Open` works. 145 | 146 | ## 0.7.4 Big refactor and save on exit fix 147 | * Moved code to separate files to clean up the main file. 148 | * Fixed an issue where having save on exit enabled and canceling the exit after 149 | being prompted to save would still exit Atom. 150 | 151 | ## 0.7.3 Refactor and new preview gif 152 | * Refactored the code by moving config stuff to its own file 153 | * Updated the preview gif to show some newer features 154 | 155 | ## 0.7.2 Fixed Windows Bug 156 | * Fixed an issue with Windows using `\` for file separators over `/` 157 | 158 | ## 0.7.1 - Updated readme 159 | 160 | ## 0.7.0 - Restoring files per project 161 | * Added a setting that allows files to be restored per project instead of 162 | globally. 163 | 164 | ## 0.6.0 - Always open without default file 165 | * Added the option to never open the file that Atom opens automatically on 166 | startup. Default is false. 167 | 168 | ## 0.5.5 - Small fixes 169 | * Removed option when opening files since it didn't do what I expected :(. 170 | * Enabled save on close prompt for closing a single file at a time. 171 | 172 | ## 0.5.4 - Bug fix 173 | * Fixed an error thrown when splitting panes. 174 | 175 | ## 0.5.3 - Bug fix 176 | * Disabling the disable new file on open setting should work now. 177 | 178 | ## 0.5.2 - Bug fix 179 | * Should no longer have issues with restoring unsaved files with disabling the 180 | new file on open. 181 | 182 | ## 0.5.1 - Safer closing of the new file buffer 183 | * There are now checks to be sure that the file is empty and has no path before 184 | it is closed. 185 | 186 | ## 0.5.0 - Changed saving the project 187 | * The project is now saved when the window gets focus instead of with file edits. 188 | 189 | ## 0.4.0 - Removing the new file buffer 190 | * The new file is automatically closed when Atom starts if there were previous 191 | files open. 192 | 193 | ## 0.3.2 - Bug fixes 194 | * Fixed a bug where closing a buffer was not saved. 195 | 196 | ## 0.3.1 - Bug fixes 197 | * Fixed a bug where you had to reopen an Atom window for the Skip Save Prompt setting 198 | to actually save. 199 | 200 | ## 0.3.0 - Disabled save on exit 201 | * Skip Save Prompt will disable the save on exit prompt 202 | * Fixed some bugs 203 | 204 | ## 0.2.4 - Minor edits 205 | * Just readme edits and deleting some unused stuff. 206 | 207 | ## 0.2.3 - Cursor Position 208 | * The cursor position is now saved on edits 209 | 210 | ## 0.2.2 - More settings 211 | * Users can specify what they want to save now. 212 | 213 | ## 0.2.1 - Settings 214 | * Users can specify their buffer save file. 215 | 216 | ## 0.2.0 - Buffers are saved a file. 217 | * Buffers are saved to a file instead of settings so users can open their config 218 | files without breaking everything. 219 | 220 | ## 0.1.2 - Fixed Readme 221 | 222 | ## 0.1.1 - Published Package 223 | 224 | ## 0.1.0 - First Release 225 | * The project is reopened if there is no project already open. 226 | * Dimensions are reloaded 227 | * Open files are reloaded if the project is reloaded. 228 | * Files will be opened with the contents they had when they were closed 229 | * This includes unsaved files 230 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Michael Peterson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Save Session (Atom Package) [![Build Status](https://travis-ci.org/mpeterson2/save-session.svg?branch=master)](https://travis-ci.org/mpeterson2/save-session) 2 | 3 | ## Project Status: Deprecated 4 | 5 | All of Save Session's functionality is now included in Atom core. 6 | 7 | Check out [this pull request](https://github.com/atom/atom/pull/9968) for more 8 | info. 9 | 10 | ## What is Save Session 11 | 12 | Save Session is designed to reopen your last session in [Atom](https://atom.io/). 13 | It automatically saves all file's contents in the background so you don't have 14 | to worry as much about losing an important file. I liked how 15 | [Sublime Text](http://www.sublimetext.com/) does this, so I wanted to recreate 16 | it for Atom. 17 | 18 | ![preview](https://raw.githubusercontent.com/mpeterson2/save-session/master/preview.gif) 19 | 20 | ## Settings 21 | 22 | - `Data Save Folder` - The root folder to save the session data in. 23 | - `Restore Open File Contents` - Whether or not file contents will be 24 | automatically restored on load. 25 | - `Skip Save Prompt` - This will disable the save on exit prompt. 26 | - `Extra Delay` - Adds an extra delay for saving files when typing. 27 | 28 | ## How it works 29 | 30 | File info is stored in a folder at 31 | `/save-session//projects.json` by default and 32 | gets reloaded at when you reopen the same project again. 33 | 34 | ## Contributing 35 | 36 | Feel free to submit issues if you see anything misbehaving. The more information 37 | you can give me about your issue the better. Things like operating system, Atom 38 | version, Save Session version, your Save Session config, other installed 39 | packages, and any error messages in the console that mention Save Session are 40 | helpful. 41 | 42 | Pull requests are also welcome if you want to improve or change something. 43 | -------------------------------------------------------------------------------- /lib/config.coffee: -------------------------------------------------------------------------------- 1 | Os = require 'os' 2 | Crypto = require('crypto') 3 | 4 | module.exports = 5 | 6 | # User configs 7 | disableNewBufferOnOpen: (val, force) -> 8 | @config 'disableNewFileOnOpen', val, force 9 | 10 | disableNewBufferOnOpenAlways: (val, force) -> 11 | @config 'disableNewFileOnOpenAlways', val, force 12 | 13 | restoreOpenFilesPerProject: (val, force) -> 14 | @config 'restoreOpenFilesPerProject', val, force 15 | 16 | saveFolder: (val, force) -> 17 | saveFolderPath = @config 'dataSaveFolder', val, force 18 | if not saveFolderPath? 19 | @setSaveFolderDefault() 20 | saveFolderPath = @saveFolder() 21 | return saveFolderPath 22 | 23 | restoreOpenFileContents: (val, force) -> 24 | @config 'restoreOpenFileContents', val, force 25 | 26 | skipSavePrompt: (val, force) -> 27 | @config 'skipSavePrompt', val, force 28 | 29 | extraDelay: (val, force) -> 30 | @config 'extraDelay', val, force 31 | 32 | #Helpers 33 | setSaveFolderDefault: -> 34 | @saveFolder(atom.packages.getPackageDirPaths() + @pathSeparator() + 'save-session' + @pathSeparator() + 'projects') 35 | 36 | pathSeparator: -> 37 | if @isWindows() 38 | return '\\' 39 | return '/' 40 | 41 | isWindows: -> 42 | return Os.platform() is 'win32' 43 | 44 | isArray: (value) -> 45 | value and 46 | typeof value is 'object' and 47 | value instanceof Array and 48 | typeof value.length is 'number' and 49 | typeof value.splice is 'function' and 50 | not (value.propertyIsEnumerable 'length') 51 | 52 | saveFile: -> 53 | saveFolderPath = @saveFolder() 54 | 55 | if atom.project.getPaths().length > 0 56 | projects = atom.project.getPaths() 57 | projectPath = projects[0] if (projects? and projects.length > 0) 58 | 59 | if projectPath? 60 | path = @transformProjectPath(projectPath) 61 | return saveFolderPath + @pathSeparator() + path + @pathSeparator() + 'project.json' 62 | 63 | return saveFolderPath + @pathSeparator() + 'project.json' 64 | 65 | transformProjectPath: (path) -> 66 | if @isWindows 67 | colon = path.indexOf(':') 68 | if colon isnt -1 69 | return path.substring(0, colon) + path.substring(colon + 1, path.length) 70 | 71 | return path 72 | 73 | hashMyStr: (str) -> 74 | hash = "" #return empty hash for empy string 75 | if str? and str isnt "" 76 | hash = Crypto.createHash('md5').update(str).digest("hex") 77 | 78 | return hash 79 | 80 | config: (key, val, force) -> 81 | if val? or (force? and force) 82 | atom.config.set 'save-session.' + key, val 83 | else 84 | atom.config.get 'save-session.' + key 85 | 86 | observe: (key, callback) -> 87 | atom.config.observe('save-session.' + key, callback) 88 | -------------------------------------------------------------------------------- /lib/files.coffee: -------------------------------------------------------------------------------- 1 | {$} = require 'atom-space-pen-views' 2 | Fs = require 'fs' 3 | Mkdirp = require 'mkdirp' 4 | Config = require './config' 5 | 6 | module.exports = 7 | 8 | activate: (buffers) -> 9 | saveFilePath = Config.saveFile() 10 | 11 | Fs.exists saveFilePath, (exists) => 12 | if exists 13 | Fs.readFile saveFilePath, encoding: 'utf8', (err, str) => 14 | buffers = JSON.parse(str) 15 | if Config.restoreOpenFileContents() 16 | @restore buffers 17 | 18 | @addListeners() 19 | 20 | save: -> 21 | buffers = [] 22 | 23 | atom.workspace.getTextEditors().map (editor) => 24 | buffer = {} 25 | if editor.getBuffer().isModified() 26 | buffer.text = editor.getBuffer().cachedText 27 | buffer.diskText = Config.hashMyStr(editor.getBuffer().cachedDiskContents) 28 | buffer.path = editor.getPath() 29 | 30 | buffers.push buffer 31 | 32 | file = Config.saveFile() 33 | folder = file.substring(0, file.lastIndexOf(Config.pathSeparator())) 34 | Mkdirp folder, (err) => 35 | Fs.writeFile(file, JSON.stringify(buffers)) 36 | 37 | 38 | restore: (buffers) -> 39 | for buffer in buffers 40 | @restoreText(buffer) 41 | 42 | 43 | restoreText: (buffer) -> 44 | if buffer.path == undefined 45 | editors = atom.workspace.getTextEditors().filter (editor) => 46 | editor.buffer.file == null and editor.buffer.cachedText == '' 47 | 48 | if editors.length > 0 49 | buf = editors[0].getBuffer() 50 | 51 | else 52 | editors = atom.workspace.getTextEditors().filter (editor) => 53 | editor.buffer.file?.path == buffer.path 54 | 55 | if editors.length > 0 56 | buf = editors[0].getBuffer() 57 | 58 | # Replace the text if needed 59 | if Config.restoreOpenFileContents() and buffer.text? and buf? and 60 | buf.getText() isnt buffer.text and Config.hashMyStr(buf.cachedDiskContents) is buffer.diskText 61 | buf.setText(buffer.text) 62 | 63 | addListeners: -> 64 | # When files are edited 65 | atom.workspace.observeTextEditors (editor) => 66 | editor.onDidStopChanging => 67 | setTimeout (=>@save()), Config.extraDelay() 68 | editor.onDidSave => 69 | @save() 70 | 71 | window.onbeforeunload = () => 72 | @save() 73 | -------------------------------------------------------------------------------- /lib/save-prompt.coffee: -------------------------------------------------------------------------------- 1 | Config = require './config' 2 | 3 | module.exports = 4 | 5 | activate: -> 6 | @addListeners() 7 | 8 | enableTemp: (pane) -> 9 | pane.promptToSaveItem = (item) -> 10 | save = pane.promptToSaveItem2 item 11 | pane.promptToSaveItem = (item) -> 12 | true 13 | save 14 | 15 | addListeners: -> 16 | 17 | Config.observe 'skipSavePrompt', (val) -> 18 | atom.workspace.getPanes().map (pane) -> 19 | if val 20 | pane.promptToSaveItem = (item) -> 21 | true 22 | else if pane.promptToSaveItem2 23 | pane.promptToSaveItem = (item) -> 24 | pane.promptToSaveItem2 item 25 | 26 | 27 | atom.workspace.observePanes (pane) => 28 | pane.promptToSaveItem2 = pane.promptToSaveItem 29 | 30 | if Config.skipSavePrompt() 31 | pane.promptToSaveItem = (item) -> 32 | true 33 | 34 | pane.onWillDestroyItem (event) => 35 | if Config.skipSavePrompt() 36 | @enableTemp pane 37 | else 38 | pane.promptToSaveItem = (item) -> 39 | pane.promptToSaveItem2 item 40 | -------------------------------------------------------------------------------- /lib/save-session.coffee: -------------------------------------------------------------------------------- 1 | {$} = require 'atom-space-pen-views' 2 | Fs = require 'fs' 3 | Config = require './config' 4 | Files = require './files' 5 | SavePrompt = require './save-prompt' 6 | 7 | module.exports = 8 | 9 | config: 10 | restoreOpenFileContents: 11 | type: 'boolean' 12 | default: true 13 | description: 'Restore the contents of files that were unsaved in the last session' 14 | skipSavePrompt: 15 | type: 'boolean' 16 | default: true 17 | description: 'Disable the save on exit prompt' 18 | extraDelay: 19 | type: 'integer' 20 | default: 500 21 | description: "Add an extra delay time in ms for auto saving files after typing." 22 | dataSaveFolder: 23 | type: 'string' 24 | description: 'The folder in which to save project states' 25 | 26 | activate: (state) -> 27 | # Default settings that couldn't be set up top. 28 | if not Config.saveFolder()? 29 | Config.saveFolderDefault() 30 | 31 | # Activate everything 32 | SavePrompt.activate() 33 | Files.activate() 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "save-session", 3 | "main": "./lib/save-session", 4 | "version": "0.16.0", 5 | "description": "An Atom package to restore your session.", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/mpeterson2/save-session" 9 | }, 10 | "license": "MIT", 11 | "engines": { 12 | "atom": ">0.193.0 <1.4.0" 13 | }, 14 | "dependencies": { 15 | "mkdirp": ">=0.5.0", 16 | "atom-space-pen-views": "^2.0.3" 17 | }, 18 | "devDependencies": { 19 | "q": "^1.0.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mpeterson2/save-session/b7192b5462544f0d49d2013c5a7f70c9e7c77ebb/preview.gif -------------------------------------------------------------------------------- /spec/config-spec.coffee: -------------------------------------------------------------------------------- 1 | Config = require '../lib/config' 2 | Os = require 'os' 3 | 4 | describe 'pathSeparator tests', -> 5 | beforeEach: -> 6 | 7 | it 'Not Windows', -> 8 | spyOn(Os, 'platform').andReturn(Math.random()) 9 | expect(Config.pathSeparator()).toBe('/') 10 | expect(Os.platform).toHaveBeenCalled() 11 | 12 | it 'Windows', -> 13 | spyOn(Os, 'platform').andReturn('win32') 14 | expect(Config.pathSeparator()).toBe('\\') 15 | expect(Os.platform).toHaveBeenCalled() 16 | 17 | 18 | describe 'saveFile tests', -> 19 | beforeEach -> 20 | spyOn(Config, 'saveFolder').andReturn('folder') 21 | spyOn(Config, 'pathSeparator').andReturn('/') 22 | 23 | describe 'projects restoring', -> 24 | it 'is a project to be restored', -> 25 | atom.project.path || atom.project.rootDirectories[0].path = 'path' 26 | 27 | expect(Config.saveFile()).toBe('folder/path/project.json') 28 | expect(Config.saveFolder).toHaveBeenCalled() 29 | expect(Config.pathSeparator).toHaveBeenCalled() 30 | 31 | 32 | describe 'transformProjectPath tests', -> 33 | it 'is Windows with :', -> 34 | spyOn(Config, 'isWindows').andReturn(true) 35 | path = Config.transformProjectPath('c:\\path') 36 | expect(path).toBe('c\\path') 37 | 38 | it 'is Windows without :', -> 39 | spyOn(Config, 'isWindows').andReturn(true) 40 | path = Config.transformProjectPath('path\\more') 41 | expect(path).toBe('path\\more') 42 | 43 | it 'is not windows', -> 44 | spyOn(Config, 'isWindows').andReturn(false) 45 | path = Config.transformProjectPath('path/more') 46 | expect(path).toBe('path/more') 47 | 48 | 49 | describe 'config tests', -> 50 | beforeEach -> 51 | spyOn(atom.config, 'set') 52 | spyOn(atom.config, 'get') 53 | 54 | it 'Contains key and value', -> 55 | Config.config 'key', 'val' 56 | expect(atom.config.set).toHaveBeenCalled() 57 | expect(atom.config.get).not.toHaveBeenCalled() 58 | 59 | it 'Contains key and forced', -> 60 | Config.config 'key', undefined, true 61 | expect(atom.config.set).toHaveBeenCalled() 62 | expect(atom.config.get).not.toHaveBeenCalled() 63 | 64 | it 'Contains key only', -> 65 | Config.config 'key' 66 | expect(atom.config.set).not.toHaveBeenCalled() 67 | expect(atom.config.get).toHaveBeenCalled() 68 | -------------------------------------------------------------------------------- /spec/files-spec.coffee: -------------------------------------------------------------------------------- 1 | # I have no idea how to test this... 2 | -------------------------------------------------------------------------------- /spec/save-prompt-spec.coffee: -------------------------------------------------------------------------------- 1 | # Not really sure how to test this one anymore... 2 | --------------------------------------------------------------------------------