diff --git a/.pairs b/.pairs index 726f863bc..c939edd3c 100644 --- a/.pairs +++ b/.pairs @@ -4,6 +4,7 @@ pairs: dg: David Graham; dgraham ks: Kevin Sawicki; kevin jc: Jerry Cheung; jerry + bl: Brian Lopez; brian email: domain: github.com #global: true diff --git a/native/atom_cef_client.cpp b/native/atom_cef_client.cpp index e36215144..41a0c2383 100644 --- a/native/atom_cef_client.cpp +++ b/native/atom_cef_client.cpp @@ -76,6 +76,9 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr browser, else if (name == "endTracing") { EndTracing(); } + else if (name == "show") { + Show(browser); + } else { return false; } @@ -235,4 +238,4 @@ bool AtomCefClient::Save(const std::string& path, const std::string& data) { fwrite(data.c_str(), data.size(), 1, f); fclose(f); return true; -} \ No newline at end of file +} diff --git a/native/atom_cef_client.h b/native/atom_cef_client.h index 92c3784bb..75b787138 100644 --- a/native/atom_cef_client.h +++ b/native/atom_cef_client.h @@ -122,6 +122,7 @@ class AtomCefClient : public CefClient, CefRefPtr CreateReplyDescriptor(int replyId, int callbackIndex); void Exit(int status); void Log(const char *message); + void Show(CefRefPtr browser); IMPLEMENT_REFCOUNTING(AtomCefClient); IMPLEMENT_LOCKING(AtomCefClient); diff --git a/native/atom_cef_client_mac.mm b/native/atom_cef_client_mac.mm index 628017009..c20bd5fbe 100644 --- a/native/atom_cef_client_mac.mm +++ b/native/atom_cef_client_mac.mm @@ -95,6 +95,11 @@ void AtomCefClient::ShowDevTools(CefRefPtr browser) { [windowController showDevTools]; } +void AtomCefClient::Show(CefRefPtr browser) { + AtomWindowController *windowController = [[browser->GetHost()->GetWindowHandle() window] windowController]; + [windowController.webView setHidden:NO]; +} + void AtomCefClient::ShowSaveDialog(int replyId, CefRefPtr browser) { CefRefPtr replyMessage = CefProcessMessage::Create("reply"); CefRefPtr replyArguments = replyMessage->GetArgumentList(); @@ -127,4 +132,4 @@ void AtomCefClient::Exit(int status) { void AtomCefClient::Log(const char *message) { std::cout << message << "\n"; -} \ No newline at end of file +} diff --git a/native/atom_window_controller.mm b/native/atom_window_controller.mm index 3c22c82e6..785d85071 100644 --- a/native/atom_window_controller.mm +++ b/native/atom_window_controller.mm @@ -41,6 +41,8 @@ if (!background) { [self setShouldCascadeWindows:NO]; [self setWindowFrameAutosaveName:@"AtomWindow"]; + NSColor *background = [NSColor colorWithCalibratedRed:(51.0/255.0) green:(51.0/255.0f) blue:(51.0/255.0f) alpha:1.0]; + [self.window setBackgroundColor:background]; [self showWindow:self]; } @@ -116,6 +118,7 @@ [urlString appendFormat:@"&pathToOpen=%@", [self encodeUrlParam:_pathToOpen]]; _cefClient = new AtomCefClient(); + [self.webView setHidden:YES]; [self addBrowserToView:self.webView url:[urlString UTF8String] cefHandler:_cefClient]; } @@ -180,9 +183,9 @@ if (_cefClient && _cefClient->GetBrowser()) { _cefClient->GetBrowser()->SendProcessMessage(PID_RENDERER, CefProcessMessage::Create("shutdown")); } - + if (_pidToKillOnClose) kill([_pidToKillOnClose intValue], SIGQUIT); - + [self autorelease]; return YES; } diff --git a/package.json b/package.json index 6e9696a82..1d8e2a164 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version" : "0.0.0", "dependencies": { - "coffee-script": "1.x" + "coffee-script": "1.x", + "cson": "1.x" }, "scripts": { diff --git a/script/copy-files-to-bundle b/script/copy-files-to-bundle index 659c87e04..c8ab8dd4f 100755 --- a/script/copy-files-to-bundle +++ b/script/copy-files-to-bundle @@ -15,7 +15,7 @@ cp "$PROJECT_DIR/native/v8_extensions/"*.js "$RESOUCES_PATH/v8_extensions/" DIRS="src static vendor" -# Compile and .coffee files into bundle +# Compile .coffee files into bundle COFFEE_FILES=$(find $DIRS -type file -name '*.coffee') for COFFEE_FILE in $COFFEE_FILES; do echo $COFFEE_FILE @@ -28,5 +28,18 @@ for COFFEE_FILE in $COFFEE_FILES; do fi done; +# Compile .cson files into bundle +CSON_FILES=$(find $DIRS -type file -name '*.cson') +for CSON_FILE in $CSON_FILES; do + echo $CSON_FILE + JSON_FILE=$(echo "$RESOUCES_PATH/$CSON_FILE" | sed 's/.cson/.json/' ) + OUTPUT_PATH="$RESOUCES_PATH/$(dirname "$CSON_FILE")" + + if [ $CSON_FILE -nt "$JSON_FILE" ]; then + mkdir -p "$OUTPUT_PATH" + node_modules/.bin/cson2json "$CSON_FILE" > "$JSON_FILE" + fi +done; + # Copy non-coffee files into bundle -rsync --archive --recursive --exclude="src/**/*.coffee" src static vendor spec benchmark "$RESOUCES_PATH" +rsync --archive --recursive --exclude="src/**/*.coffee" --exclude="src/**/*.cson" src static vendor spec benchmark themes "$RESOUCES_PATH" diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 2adf7feb4..c74a6605e 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -1973,6 +1973,17 @@ describe "EditSession", -> editSession.indent() expect(editSession.lineForBufferRow(2)).toBe " " + it "auto-indents selection when autoIndent is called", -> + editSession.setCursorBufferPosition([2, 0]) + editSession.insertText(" 0\n 2\n4\n") + + editSession.setSelectedBufferRange([[2, 0], [4, 0]]) + editSession.autoIndentSelectedRows() + + expect(editSession.lineForBufferRow(2)).toBe " 0" + expect(editSession.lineForBufferRow(3)).toBe " 2" + expect(editSession.lineForBufferRow(4)).toBe "4" + describe "editor.autoIndentOnPaste", -> it "does not auto-indent pasted text by default", -> editSession.setCursorBufferPosition([2, 0]) diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index ae616f814..777e7b7b3 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -199,6 +199,15 @@ describe "Editor", -> expect(editor.remove).not.toHaveBeenCalled() expect(atom.confirm).toHaveBeenCalled() + it "doesn't trigger an alert if the buffer is opened in multiple sessions", -> + spyOn(editor, 'remove').andCallThrough() + spyOn(atom, 'confirm') + editor.insertText("I AM CHANGED!") + editor.splitLeft() + editor.trigger "core:close" + expect(editor.remove).toHaveBeenCalled() + expect(atom.confirm).not.toHaveBeenCalled() + describe ".edit(editSession)", -> otherEditSession = null diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index e5abf32a0..20b5bca36 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -18,7 +18,7 @@ describe "RootView", -> afterEach -> rootView.deactivate() - describe "initialize(pathToOpen)", -> + describe ".initialize(pathToOpen)", -> describe "when called with a pathToOpen", -> describe "when pathToOpen references a file", -> it "creates a project for the file's parent directory, then sets the title and opens the file in an editor", -> @@ -42,95 +42,6 @@ describe "RootView", -> expect(rootView.getEditors().length).toBe 0 expect(rootView.getTitle()).toBe rootView.project.getPath() - describe "when called with view state data returned from a previous call to RootView.prototype.serialize", -> - viewState = null - - describe "when the serialized RootView has an unsaved buffer", -> - buffer = null - - beforeEach -> - rootView.remove() - rootView = new RootView - rootView.open() - editor1 = rootView.getActiveEditor() - buffer = editor1.getBuffer() - editor1.splitRight() - viewState = rootView.serialize() - - it "constructs the view with the same panes", -> - rootView = RootView.deserialize(viewState) - expect(rootView.project.getPath()?).toBeFalsy() - expect(rootView.getEditors().length).toBe 2 - expect(rootView.getActiveEditor().getText()).toBe buffer.getText() - expect(rootView.getTitle()).toBe 'untitled' - - describe "when the serialized RootView has a project", -> - beforeEach -> - path = require.resolve 'fixtures' - rootView.remove() - rootView = new RootView(path) - - describe "when there are open editors", -> - beforeEach -> - rootView.open('dir/a') - editor1 = rootView.getActiveEditor() - editor2 = editor1.splitRight() - editor3 = editor2.splitRight() - editor4 = editor2.splitDown() - editor2.edit(rootView.project.buildEditSessionForPath('dir/b')) - editor3.edit(rootView.project.buildEditSessionForPath('sample.js')) - editor3.setCursorScreenPosition([2, 4]) - editor4.edit(rootView.project.buildEditSessionForPath('sample.txt')) - editor4.setCursorScreenPosition([0, 2]) - rootView.attachToDom() - editor2.focus() - viewState = rootView.serialize() - rootView.remove() - - it "constructs the view with the same project and panes", -> - rootView = RootView.deserialize(viewState) - rootView.attachToDom() - - expect(rootView.getEditors().length).toBe 4 - editor1 = rootView.panes.find('.row > .pane .editor:eq(0)').view() - editor3 = rootView.panes.find('.row > .pane .editor:eq(1)').view() - editor2 = rootView.panes.find('.row > .column > .pane .editor:eq(0)').view() - editor4 = rootView.panes.find('.row > .column > .pane .editor:eq(1)').view() - - expect(editor1.getPath()).toBe require.resolve('fixtures/dir/a') - expect(editor2.getPath()).toBe require.resolve('fixtures/dir/b') - expect(editor3.getPath()).toBe require.resolve('fixtures/sample.js') - expect(editor3.getCursorScreenPosition()).toEqual [2, 4] - expect(editor4.getPath()).toBe require.resolve('fixtures/sample.txt') - expect(editor4.getCursorScreenPosition()).toEqual [0, 2] - - # ensure adjust pane dimensions is called - expect(editor1.width()).toBeGreaterThan 0 - expect(editor2.width()).toBeGreaterThan 0 - expect(editor3.width()).toBeGreaterThan 0 - expect(editor4.width()).toBeGreaterThan 0 - - # ensure correct editor is focused again - expect(editor2.isFocused).toBeTruthy() - expect(editor1.isFocused).toBeFalsy() - expect(editor3.isFocused).toBeFalsy() - expect(editor4.isFocused).toBeFalsy() - - expect(rootView.getTitle()).toBe "#{fs.base(editor2.getPath())} – #{rootView.project.getPath()}" - - describe "where there are no open editors", -> - beforeEach -> - rootView.attachToDom() - viewState = rootView.serialize() - rootView.remove() - - it "constructs the view with no open editors", -> - rootView = RootView.deserialize(viewState) - rootView.attachToDom() - - expect(rootView.getEditors().length).toBe 0 - - describe "when called with no pathToOpen", -> it "opens an empty buffer", -> rootView.remove() @@ -139,6 +50,107 @@ describe "RootView", -> expect(rootView.getEditors()[0].getText()).toEqual "" expect(rootView.getTitle()).toBe 'untitled' + describe "@deserialize()", -> + viewState = null + + describe "when the serialized RootView has an unsaved buffer", -> + buffer = null + + beforeEach -> + rootView.remove() + rootView = new RootView + rootView.open() + editor1 = rootView.getActiveEditor() + buffer = editor1.getBuffer() + editor1.splitRight() + viewState = rootView.serialize() + + it "constructs the view with the same panes", -> + rootView = RootView.deserialize(viewState) + expect(rootView.project.getPath()?).toBeFalsy() + expect(rootView.getEditors().length).toBe 2 + expect(rootView.getActiveEditor().getText()).toBe buffer.getText() + expect(rootView.getTitle()).toBe 'untitled' + + describe "when the serialized RootView has a project", -> + beforeEach -> + path = require.resolve 'fixtures' + rootView.remove() + rootView = new RootView(path) + + describe "when there are open editors", -> + beforeEach -> + rootView.open('dir/a') + editor1 = rootView.getActiveEditor() + editor2 = editor1.splitRight() + editor3 = editor2.splitRight() + editor4 = editor2.splitDown() + editor2.edit(rootView.project.buildEditSessionForPath('dir/b')) + editor3.edit(rootView.project.buildEditSessionForPath('sample.js')) + editor3.setCursorScreenPosition([2, 4]) + editor4.edit(rootView.project.buildEditSessionForPath('sample.txt')) + editor4.setCursorScreenPosition([0, 2]) + rootView.attachToDom() + editor2.focus() + viewState = rootView.serialize() + rootView.remove() + + it "constructs the view with the same project and panes", -> + rootView = RootView.deserialize(viewState) + rootView.attachToDom() + + expect(rootView.getEditors().length).toBe 4 + editor1 = rootView.panes.find('.row > .pane .editor:eq(0)').view() + editor3 = rootView.panes.find('.row > .pane .editor:eq(1)').view() + editor2 = rootView.panes.find('.row > .column > .pane .editor:eq(0)').view() + editor4 = rootView.panes.find('.row > .column > .pane .editor:eq(1)').view() + + expect(editor1.getPath()).toBe require.resolve('fixtures/dir/a') + expect(editor2.getPath()).toBe require.resolve('fixtures/dir/b') + expect(editor3.getPath()).toBe require.resolve('fixtures/sample.js') + expect(editor3.getCursorScreenPosition()).toEqual [2, 4] + expect(editor4.getPath()).toBe require.resolve('fixtures/sample.txt') + expect(editor4.getCursorScreenPosition()).toEqual [0, 2] + + # ensure adjust pane dimensions is called + expect(editor1.width()).toBeGreaterThan 0 + expect(editor2.width()).toBeGreaterThan 0 + expect(editor3.width()).toBeGreaterThan 0 + expect(editor4.width()).toBeGreaterThan 0 + + # ensure correct editor is focused again + expect(editor2.isFocused).toBeTruthy() + expect(editor1.isFocused).toBeFalsy() + expect(editor3.isFocused).toBeFalsy() + expect(editor4.isFocused).toBeFalsy() + + expect(rootView.getTitle()).toBe "#{fs.base(editor2.getPath())} – #{rootView.project.getPath()}" + + describe "where there are no open editors", -> + beforeEach -> + rootView.attachToDom() + viewState = rootView.serialize() + rootView.remove() + + it "constructs the view with no open editors", -> + rootView = RootView.deserialize(viewState) + rootView.attachToDom() + + expect(rootView.getEditors().length).toBe 0 + + describe "when a pane's wrapped view cannot be deserialized", -> + it "renders an empty pane", -> + viewState = + panesViewState: + viewClass: "Pane", + wrappedView: + viewClass: "BogusView" + + rootView.remove() + rootView = RootView.deserialize(viewState) + expect(rootView.find('.pane').length).toBe 1 + expect(rootView.find('.pane').children().length).toBe 0 + describe ".serialize()", -> it "absorbs exceptions that are thrown by the package module's serialize methods", -> spyOn(console, 'error') diff --git a/spec/spec-bootstrap.coffee b/spec/spec-bootstrap.coffee index c3a680ba7..dbffbeece 100644 --- a/spec/spec-bootstrap.coffee +++ b/spec/spec-bootstrap.coffee @@ -1,4 +1,5 @@ require 'atom' +atom.show() {runSpecSuite} = require 'jasmine-helper' document.title = "Spec Suite" diff --git a/src/app/atom-package.coffee b/src/app/atom-package.coffee index 7d66ab6a7..e86678a37 100644 --- a/src/app/atom-package.coffee +++ b/src/app/atom-package.coffee @@ -35,10 +35,7 @@ class AtomPackage extends Package keymaps.map (relativePath) => fs.resolve(@keymapsDirPath, relativePath, ['cson', 'json', '']) else - if fs.exists(@keymapsDirPath) - fs.list(@keymapsDirPath) - else - [] + fs.list(@keymapsDirPath) loadStylesheets: -> for stylesheetPath in @getStylesheetPaths() @@ -46,7 +43,4 @@ class AtomPackage extends Package getStylesheetPaths: -> stylesheetDirPath = fs.join(@path, 'stylesheets') - if fs.exists stylesheetDirPath - fs.list stylesheetDirPath - else - [] + fs.list(stylesheetDirPath) diff --git a/src/app/atom.coffee b/src/app/atom.coffee index 8f02a3db0..ee5c8a442 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -75,6 +75,9 @@ _.extend atom, focus: -> @sendMessageToBrowserProcess('focus') + show: -> + @sendMessageToBrowserProcess('show') + exit: (status) -> @sendMessageToBrowserProcess('exit', [status]) diff --git a/src/app/binding-set.coffee b/src/app/binding-set.coffee index d3a40a8b1..168de6bbe 100644 --- a/src/app/binding-set.coffee +++ b/src/app/binding-set.coffee @@ -7,13 +7,16 @@ PEG = require 'pegjs' module.exports = class BindingSet + + @parser: null + selector: null commandsByKeystrokes: null commandForEvent: null parser: null constructor: (@selector, commandsByKeystrokes, @index) -> - @parser = PEG.buildParser(fs.read(require.resolve 'keystroke-pattern.pegjs')) + BindingSet.parser ?= PEG.buildParser(fs.read(require.resolve 'keystroke-pattern.pegjs')) @specificity = Specificity(@selector) @commandsByKeystrokes = @normalizeCommandsByKeystrokes(commandsByKeystrokes) @@ -42,7 +45,7 @@ class BindingSet normalizedKeystrokes.join(' ') normalizeKeystroke: (keystroke) -> - keys = @parser.parse(keystroke) + keys = BindingSet.parser.parse(keystroke) modifiers = keys[0...-1] modifiers.sort() [modifiers..., _.last(keys)].join('-') diff --git a/src/app/buffer.coffee b/src/app/buffer.coffee index 59c6bdd21..d5f9bd34c 100644 --- a/src/app/buffer.coffee +++ b/src/app/buffer.coffee @@ -54,6 +54,8 @@ class Buffer @destroy() if @refcount <= 0 this + hasEditors: -> @refcount > 1 + subscribeToFile: -> @file.on "contents-changed", => if @isModified() diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 24bcb6bf1..7e7791963 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -142,6 +142,8 @@ class EditSession lineLengthForBufferRow: (row) -> @buffer.lineLengthForRow(row) scanInRange: (args...) -> @buffer.scanInRange(args...) backwardsScanInRange: (args...) -> @buffer.backwardsScanInRange(args...) + isModified: -> @buffer.isModified() + hasEditors: -> @buffer.hasEditors() screenPositionForBufferPosition: (bufferPosition, options) -> @displayBuffer.screenPositionForBufferPosition(bufferPosition, options) bufferPositionForScreenPosition: (screenPosition, options) -> @displayBuffer.bufferPositionForScreenPosition(screenPosition, options) @@ -206,6 +208,9 @@ class EditSession toggleLineCommentsInSelection: -> @mutateSelectedText (selection) -> selection.toggleLineComments() + autoIndentSelectedRows: -> + @mutateSelectedText (selection) -> selection.autoIndentSelectedRows() + cutToEndOfLine: -> maintainPasteboard = false @mutateSelectedText (selection) -> diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 720afce55..649d8afbd 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -117,6 +117,7 @@ class Editor extends View 'editor:select-word': @selectWord 'editor:newline': @insertNewline 'editor:indent': @indent + 'editor:auto-indent': @autoIndent 'editor:indent-selected-rows': @indentSelectedRows 'editor:outdent-selected-rows': @outdentSelectedRows 'editor:backspace-to-beginning-of-word': @backspaceToBeginningOfWord @@ -151,6 +152,7 @@ class Editor extends View 'core:select-to-bottom': @selectToBottom 'core:close': @destroyActiveEditSession 'editor:save': @save + 'editor:save-as': @saveAs 'editor:newline-below': @insertNewlineBelow 'editor:toggle-soft-tabs': @toggleSoftTabs 'editor:toggle-soft-wrap': @toggleSoftWrap @@ -247,6 +249,7 @@ class Editor extends View insertNewline: -> @activeEditSession.insertNewline() insertNewlineBelow: -> @activeEditSession.insertNewlineBelow() indent: (options) -> @activeEditSession.indent(options) + autoIndent: (options) -> @activeEditSession.autoIndentSelectedRows(options) indentSelectedRows: -> @activeEditSession.indentSelectedRows() outdentSelectedRows: -> @activeEditSession.outdentSelectedRows() cutSelection: -> @activeEditSession.cutSelectedText() @@ -463,7 +466,7 @@ class Editor extends View @remove() if @editSessions.length is 0 callback(index) if callback - if editSession.buffer.isModified() + if editSession.isModified() and not editSession.hasEditors() @promptToSaveDirtySession(editSession, destroySession) else destroySession(editSession) @@ -653,6 +656,9 @@ class Editor extends View session.save() onSuccess?() else + @saveAs(session, onSuccess) + + saveAs: (session=@activeEditSession, onSuccess) -> atom.showSaveDialog (path) => if path session.saveAs(path) diff --git a/src/app/keymaps/atom.cson b/src/app/keymaps/atom.cson index 0780ad30e..a4f64a990 100644 --- a/src/app/keymaps/atom.cson +++ b/src/app/keymaps/atom.cson @@ -22,7 +22,7 @@ 'pageup': 'core:page-up' 'pagedown': 'core:page-down' - 'meta-S': 'window:save-all' + 'meta-alt-s': 'window:save-all' 'meta-W': 'window:close' 'meta-+': 'window:increase-font-size' 'meta--': 'window:decrease-font-size' @@ -33,4 +33,4 @@ '.tool-panel': 'meta-escape': 'tool-panel:unfocus' 'escape': 'core:close' - 'meta-w': 'noop' \ No newline at end of file + 'meta-w': 'noop' diff --git a/src/app/keymaps/editor.cson b/src/app/keymaps/editor.cson index 376f822a2..2f48d27bb 100644 --- a/src/app/keymaps/editor.cson +++ b/src/app/keymaps/editor.cson @@ -1,8 +1,10 @@ '.editor': 'meta-s': 'editor:save' + 'meta-S': 'editor:save-as' 'enter': 'editor:newline' 'meta-enter': 'editor:newline-below' 'tab': 'editor:indent' + 'meta-=': 'editor:auto-indent' 'meta-d': 'editor:delete-line' 'ctrl-[': 'editor:fold-current-row' 'ctrl-]': 'editor:unfold-current-row' diff --git a/src/app/pane.coffee b/src/app/pane.coffee index fb5317b8a..81881e74a 100644 --- a/src/app/pane.coffee +++ b/src/app/pane.coffee @@ -6,14 +6,14 @@ module.exports = class Pane extends View @content: (wrappedView) -> @div class: 'pane', => - @subview 'wrappedView', wrappedView + @subview 'wrappedView', wrappedView if wrappedView @deserialize: ({wrappedView}, rootView) -> new Pane(rootView.deserializeView(wrappedView)) serialize: -> viewClass: "Pane" - wrappedView: @wrappedView.serialize() + wrappedView: @wrappedView?.serialize() adjustDimensions: -> # do nothing diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index f4f6c271c..3a187d6a7 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -42,6 +42,12 @@ class RootView extends View window.rootView = this @packageStates ?= {} @packageModules = {} + @viewClasses = { + "Pane": Pane, + "PaneRow": PaneRow, + "PaneColumn": PaneColumn, + "Editor": Editor + } @handleEvents() if not projectOrPathToOpen or _.isString(projectOrPathToOpen) @@ -121,12 +127,11 @@ class RootView extends View console?.error("Exception serializing '#{name}' package's module\n", e.stack) packageStates + registerViewClass: (viewClass) -> + @viewClasses[viewClass.name] = viewClass + deserializeView: (viewState) -> - switch viewState.viewClass - when 'Pane' then Pane.deserialize(viewState, this) - when 'PaneRow' then PaneRow.deserialize(viewState, this) - when 'PaneColumn' then PaneColumn.deserialize(viewState, this) - when 'Editor' then Editor.deserialize(viewState, this) + @viewClasses[viewState.viewClass]?.deserialize(viewState, this) activatePackage: (name, packageModule) -> config.setDefaults(name, packageModule.configDefaults) if packageModule.configDefaults? diff --git a/src/app/selection.coffee b/src/app/selection.coffee index dce6f1b3e..f30eea09a 100644 --- a/src/app/selection.coffee +++ b/src/app/selection.coffee @@ -307,6 +307,10 @@ class Selection if matchLength = buffer.lineForRow(row).match(leadingTabRegex)?[0].length buffer.delete [[row, 0], [row, matchLength]] + autoIndentSelectedRows: -> + [start, end] = @getBufferRowRange() + @editSession.autoIndentBufferRows(start, end) + toggleLineComments: -> @modifySelection => @editSession.toggleLineCommentsForBufferRows(@getBufferRowRange()...) diff --git a/src/app/window.coffee b/src/app/window.coffee index b7988eba8..9e53ed5b6 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -99,9 +99,10 @@ windowAdditions = measure: (description, fn) -> start = new Date().getTime() - fn() + value = fn() result = new Date().getTime() - start console.log description, result + value window[key] = value for key, value of windowAdditions window.startup() diff --git a/src/packages/command-logger/src/command-logger.coffee b/src/packages/command-logger/src/command-logger.coffee index 75b66cf29..ebe1e7164 100644 --- a/src/packages/command-logger/src/command-logger.coffee +++ b/src/packages/command-logger/src/command-logger.coffee @@ -2,7 +2,6 @@ ScrollView = require 'scroll-view' $ = require 'jquery' _ = require 'underscore' -d3 = require 'd3.v3' module.exports = class CommandLogger extends ScrollView @@ -121,6 +120,8 @@ class CommandLogger extends ScrollView w = @treeMap.width() h = @treeMap.height() + d3 = require 'd3.v3' + x = d3.scale.linear().range([0, w]) y = d3.scale.linear().range([0, h]) color = d3.scale.category20() diff --git a/src/packages/command-panel/src/command-interpreter.coffee b/src/packages/command-panel/src/command-interpreter.coffee index eb328c9b6..0c8a08d8a 100644 --- a/src/packages/command-panel/src/command-interpreter.coffee +++ b/src/packages/command-panel/src/command-interpreter.coffee @@ -4,9 +4,9 @@ PEG = require 'pegjs' module.exports = class CommandInterpreter constructor: (@project) -> - @parser = PEG.buildParser(fs.read(require.resolve 'command-panel/commands.pegjs')) eval: (string, activeEditSession) -> + @parser ?= PEG.buildParser(fs.read(require.resolve 'command-panel/commands.pegjs')) compositeCommand = @parser.parse(string) @lastRelativeAddress = compositeCommand if compositeCommand.isRelativeAddress() compositeCommand.execute(@project, activeEditSession) diff --git a/src/stdlib/require.coffee b/src/stdlib/require.coffee index 5504ee78b..1076bcc49 100644 --- a/src/stdlib/require.coffee +++ b/src/stdlib/require.coffee @@ -28,7 +28,7 @@ require = (path, cb) -> parts = file.split '.' ext = parts[parts.length-1] - if __modules[file]? + if __moduleExists file if not __modules.loaded[file.toLowerCase()]? console.warn "Circular require: #{__filename} required #{file}" return __modules[file] @@ -73,16 +73,26 @@ resolve = (name, {verifyExistence}={}) -> file = file.replace '../', "#{prefix}/" if file[0] isnt '/' - paths.some (path) -> - fileExists = /\.(.+)$/.test(file) and __exists "#{path}/#{file}" - jsFileExists = not /\.(.+)$/.test(file) and __exists "#{path}/#{file}.js" - - if jsFileExists - file = "#{path}/#{file}.js" - else if fileExists + moduleAlreadyLoaded = paths.some (path) -> + if __moduleExists "#{path}/#{file}" file = "#{path}/#{file}" - else if expanded = __expand "#{path}/#{file}" + else if __moduleExists "#{path}/#{file}.js" + file = "#{path}/#{file}.js" + else if expanded = __moduleExpand "#{path}/#{file}" file = expanded + + if not moduleAlreadyLoaded + hasExtension = /\.(.+)$/.test(file) + paths.some (path) -> + fileExists = hasExtension and __exists "#{path}/#{file}" + jsFileExists = not hasExtension and __exists "#{path}/#{file}.js" + + if jsFileExists + file = "#{path}/#{file}.js" + else if fileExists + file = "#{path}/#{file}" + else if expanded = __expand "#{path}/#{file}" + file = expanded else file = __expand(file) or file @@ -92,16 +102,27 @@ resolve = (name, {verifyExistence}={}) -> console.warn("Failed to resolve '#{name}'") if verifyExistence null +__moduleExists = (path) -> + __modules[path]? + +__moduleExpand = (path) -> + return path if __moduleExists path + for ext, handler of exts + return "#{path}.#{ext}" if __moduleExists "#{path}.#{ext}" + return "#{path}/index.#{ext}" if __moduleExists "#{path}/index.#{ext}" + null + __expand = (path) -> + modulePath = __moduleExpand path + return modulePath if modulePath + return path if __isFile path for ext, handler of exts - if __exists "#{path}.#{ext}" - return "#{path}.#{ext}" - else if __exists "#{path}/index.#{ext}" - return "#{path}/index.#{ext}" + return "#{path}.#{ext}" if __exists "#{path}.#{ext}" + return "#{path}/index.#{ext}" if __exists "#{path}/index.#{ext}" return path if __exists path - return null + null __exists = (path) -> $native.exists path diff --git a/src/window-bootstrap.coffee b/src/window-bootstrap.coffee index 5720d9af9..fa815e832 100644 --- a/src/window-bootstrap.coffee +++ b/src/window-bootstrap.coffee @@ -4,3 +4,4 @@ require 'window' pathToOpen = atom.getWindowState('pathToOpen') ? window.location.params.pathToOpen window.attachRootView(pathToOpen) +atom.show() diff --git a/static/index.html b/static/index.html index e65255bd2..582a8c87b 100644 --- a/static/index.html +++ b/static/index.html @@ -1,5 +1,5 @@ - + diff --git a/static/jasmine.css b/static/jasmine.css index 72301db23..6bf9eef9c 100644 --- a/static/jasmine.css +++ b/static/jasmine.css @@ -3,6 +3,9 @@ font-size: 16px; } +body { + background: #eee; +} .jasmine_reporter a:visited, .jasmine_reporter a { color: #303; diff --git a/static/reset.css b/static/reset.css index 2daea0c94..44497b27d 100755 --- a/static/reset.css +++ b/static/reset.css @@ -40,7 +40,6 @@ footer, header, hgroup, menu, nav, section { /* Line-height should always be unitless! */ body { line-height: 1.5; - background: white; } /* Tables still need 'cellspacing="0"' in the markup. */