diff --git a/Atom/src/Atom.mm b/Atom/src/Atom.mm index 20b2eceae..84acbaad8 100755 --- a/Atom/src/Atom.mm +++ b/Atom/src/Atom.mm @@ -24,7 +24,7 @@ - (void)dealloc { [_hiddenWindow release]; - [self dealloc]; + [super dealloc]; } - (BOOL)isHandlingSendEvent { @@ -40,7 +40,8 @@ if ([[self mainMenu] performKeyEquivalent:event]) return; - if (_clientHandler && ![self keyWindow] && [event type] == NSKeyDown) { + bool windowHandlesKeyEvents = [[[self keyWindow] windowController] handlesKeyEvents]; + if (_clientHandler && !windowHandlesKeyEvents && [event type] == NSKeyDown) { [_hiddenWindow makeKeyAndOrderFront:self]; [_hiddenWindow sendEvent:event]; } diff --git a/Atom/src/AtomController.h b/Atom/src/AtomController.h index fd630dc11..a9853c827 100644 --- a/Atom/src/AtomController.h +++ b/Atom/src/AtomController.h @@ -9,6 +9,8 @@ class ClientHandler; NSView *_webView; NSString *_bootstrapScript; NSString *_pathToOpen; + + bool _handlesKeyEvents; CefRefPtr _atomContext; CefRefPtr _clientHandler; @@ -17,6 +19,7 @@ class ClientHandler; - (id)initWithBootstrapScript:(NSString *)bootstrapScript atomContext:(CefRefPtr) context; - (id)initWithPath:(NSString *)path atomContext:(CefRefPtr)atomContext; - (id)initSpecsWithAtomContext:(CefRefPtr)atomContext; +- (bool)handlesKeyEvents; - (void)createBrowser; diff --git a/Atom/src/AtomController.mm b/Atom/src/AtomController.mm index f07edbd2a..7d3ea1450 100644 --- a/Atom/src/AtomController.mm +++ b/Atom/src/AtomController.mm @@ -29,10 +29,12 @@ - (id)initWithPath:(NSString *)path atomContext:(CefRefPtr)atomContext { _pathToOpen = [path retain]; + _handlesKeyEvents = YES; return [self initWithBootstrapScript:@"window-bootstrap" atomContext:atomContext]; } - (id)initSpecsWithAtomContext:(CefRefPtr)atomContext { + _handlesKeyEvents = NO; return [self initWithBootstrapScript:@"spec-bootstrap" atomContext:atomContext]; } @@ -56,6 +58,10 @@ CefBrowser::CreateBrowser(window_info, _clientHandler.get(), [indexURLString UTF8String], settings); } +- (bool)handlesKeyEvents { + return _handlesKeyEvents; +} + #pragma mark BrowserDelegate - (void)loadStart { diff --git a/spec/atom/editor-spec.coffee b/spec/atom/editor-spec.coffee index 57273e0b1..8a5ad0fbb 100644 --- a/spec/atom/editor-spec.coffee +++ b/spec/atom/editor-spec.coffee @@ -12,6 +12,7 @@ describe "Editor", -> beforeEach -> buffer = new Buffer(require.resolve('fixtures/sample.js')) editor = new Editor + editor.autoIndent = false editor.enableKeymap() editor.setBuffer(buffer) @@ -458,6 +459,30 @@ describe "Editor", -> editor.lines.trigger 'mouseup' expect(editor.getSelectedText()).toBe " if (items.length <= 1) return items;" + describe "auto indent/outdent", -> + beforeEach -> + editor.autoIndent = true + + describe "when newline is inserted", -> + it "indents cursor based on the indentation of previous line", -> + editor.setCursorBufferPosition([4, 29]) + editor.insertText("\n") + expect(editor.buffer.lineForRow(5)).toEqual(" ") + + it "indents cursor based on the indentation of previous line", -> + editor.setCursorBufferPosition([4, 29]) + editor.insertText("\nvar thisIsCool") + expect(editor.buffer.lineForRow(5)).toEqual(" var thisIsCool") + + describe "when text that closes a scope entered", -> + it "outdents the text", -> + editor.setCursorBufferPosition([1, 30]) + editor.insertText("\n") + expect(editor.buffer.lineForRow(2)).toEqual(" ") + editor.insertText("}") + expect(editor.buffer.lineForRow(2)).toEqual(" }") + expect(editor.getCursorBufferPosition().column).toBe 3 + describe "selection", -> selection = null diff --git a/src/atom/ace-outdent-adaptor.coffee b/src/atom/ace-outdent-adaptor.coffee new file mode 100644 index 000000000..5e54d9fa4 --- /dev/null +++ b/src/atom/ace-outdent-adaptor.coffee @@ -0,0 +1,21 @@ +Range = require 'range' + +module.exports = +class AceOutdentAdaptor + constructor: (@buffer, @editor) -> + + getLine: (row) -> + @buffer.lineForRow(row) + + # We don't care where the bracket is; we always outdent one level + findMatchingBracket: ({row, column}) -> + {row: 0, column: 0} + + # Does not actually replace text, just line at range.start outdents one level + replace: (range, text) -> + {row, column} = @editor.getCursorBufferPosition() + start = range.start + end = {row: range.start.row, column: range.start.column + atom.tabText.length} + @buffer.change(new Range(start, end), "") + @editor.setCursorBufferPosition({row, column: column - atom.tabText.length}) + diff --git a/src/atom/app.coffee b/src/atom/app.coffee index f5e79057b..37bd69570 100644 --- a/src/atom/app.coffee +++ b/src/atom/app.coffee @@ -6,15 +6,17 @@ module.exports = class App keymap: null windows: null + tabText: null constructor: (@loadPath, nativeMethods)-> @windows = [] @setupKeymap() + @tabText = " " setupKeymap: -> @keymap = new GlobalKeymap() - $(document).on 'keydown', (e) => @keymap.handleKeyEvent(e) + @keymap.bindDefaultKeys() open: (url) -> $native.open url diff --git a/src/atom/buffer.coffee b/src/atom/buffer.coffee index 1567498a8..bdd4f9f10 100644 --- a/src/atom/buffer.coffee +++ b/src/atom/buffer.coffee @@ -95,9 +95,10 @@ class Buffer if not @path then throw new Error("Tried to save buffer with no url") fs.write @path, @getText() - modeName: -> + getMode: -> + return @mode if @mode extension = if @path then @path.split('/').pop().split('.').pop() else null - switch extension + modeName = switch extension when 'js' then 'javascript' when 'coffee' then 'coffee' when 'rb', 'ru' then 'ruby' @@ -106,4 +107,6 @@ class Buffer when 'css' then 'css' else 'text' + @mode = new (require("ace/mode/#{modeName}").Mode) + _.extend(Buffer.prototype, EventEmitter) diff --git a/src/atom/editor.coffee b/src/atom/editor.coffee index f1e5e2194..8b0cbdfb0 100644 --- a/src/atom/editor.coffee +++ b/src/atom/editor.coffee @@ -1,4 +1,5 @@ {View, $$} = require 'space-pen' +AceOutdentAdaptor = require 'ace-outdent-adaptor' Buffer = require 'buffer' Cursor = require 'cursor' Gutter = require 'gutter' @@ -32,6 +33,7 @@ class Editor extends View highlighter: null renderer: null undoManager: null + autoIndent: null initialize: () -> requireStylesheet 'editor.css' @@ -40,6 +42,7 @@ class Editor extends View @buildCursorAndSelection() @handleEvents() @setBuffer(new Buffer) + @autoIndent = true bindKeys: -> window.keymap.bindKeys '*:not(.editor *)', @@ -70,7 +73,7 @@ class Editor extends View @on 'select-left', => @selectLeft() @on 'select-up', => @selectUp() @on 'select-down', => @selectDown() - @on 'newline', => @insertNewline() + @on 'newline', => @insertText("\n") @on 'backspace', => @backspace() @on 'delete', => @delete() @on 'cut', => @cutSelection() @@ -297,12 +300,34 @@ class Editor extends View selectToBufferPosition: (position) -> @selection.selectToBufferPosition(position) - insertText: (text) -> @selection.insertText(text) - insertNewline: -> @selection.insertNewline() + insertText: (text) -> + { text, shouldOutdent } = @autoIndentText(text) + + @selection.insertText(text) + + @autoOutdentText() if shouldOutdent + + autoIndentText: (text) -> + if @autoIndent + state = @renderer.lineForRow(@getCursorRow()).state + + if text[0] == "\n" + indent = @buffer.mode.getNextLineIndent(state, @getCurrentLine(), atom.tabText) + text = text[0] + indent + text[1..] + else if @buffer.mode.checkOutdent(state, @getCurrentLine(), text) + shouldOutdent = true + + console.log text + + {text, shouldOutdent} + + autoOutdentText: -> + state = @renderer.lineForRow(@getCursorRow()).state + @buffer.mode.autoOutdent(state, new AceOutdentAdaptor(@buffer, this), @getCursorRow()) cutSelection: -> @selection.cut() copySelection: -> @selection.copy() - paste: -> @selection.insertText($native.readFromPasteboard()) + paste: -> @insertText($native.readFromPasteboard()) foldSelection: -> @selection.fold() diff --git a/src/atom/global-keymap.coffee b/src/atom/global-keymap.coffee index 1fe11643c..ec1eaf14e 100644 --- a/src/atom/global-keymap.coffee +++ b/src/atom/global-keymap.coffee @@ -9,15 +9,15 @@ class GlobalKeymap constructor: -> @bindingSets = [] + bindDefaultKeys: -> @bindKeys "*", 'meta-n': 'newWindow' 'meta-o': 'open' $(document).on 'newWindow', => $native.newWindow() - $(document).on 'open', => + $(document).on 'open', => url = $native.openDialog() atom.open(url) if url - bindKeys: (selector, bindings) -> @bindingSets.unshift(new BindingSet(selector, bindings)) @@ -29,7 +29,7 @@ class GlobalKeymap handleKeyEvent: (event) -> event.keystroke = @keystrokeStringForEvent(event) - currentNode = $(event.target) + currentNode = $(event.target) while currentNode.length candidateBindingSets = @bindingSets.filter (set) -> currentNode.is(set.selector) candidateBindingSets.sort (a, b) -> b.specificity - a.specificity diff --git a/src/atom/highlighter.coffee b/src/atom/highlighter.coffee index 67dd3b8f1..061228ff5 100644 --- a/src/atom/highlighter.coffee +++ b/src/atom/highlighter.coffee @@ -5,18 +5,12 @@ EventEmitter = require 'event-emitter' module.exports = class Highlighter buffer: null - tokenizer: null screenLines: [] constructor: (@buffer) -> - @buildTokenizer() @screenLines = @buildLinesForScreenRows('start', 0, @buffer.lastRow()) @buffer.on 'change', (e) => @handleBufferChange(e) - buildTokenizer: -> - Mode = require("ace/mode/#{@buffer.modeName()}").Mode - @tokenizer = (new Mode).getTokenizer() - handleBufferChange: (e) -> oldRange = e.oldRange.copy() newRange = e.newRange.copy() @@ -56,8 +50,9 @@ class Highlighter screenLine buildLineForScreenRow: (state, row) -> + tokenizer = @buffer.getMode().getTokenizer() line = @buffer.lineForRow(row) - {tokens, state} = @tokenizer.getLineTokens(line, state) + {tokens, state} = tokenizer.getLineTokens(line, state) new ScreenLineFragment(tokens, line, [1, 0], [1, 0], { state }) lineForScreenRow: (row) -> diff --git a/src/atom/selection.coffee b/src/atom/selection.coffee index 8fe9b8a67..b292143b6 100644 --- a/src/atom/selection.coffee +++ b/src/atom/selection.coffee @@ -81,9 +81,6 @@ class Selection extends View insertText: (text) -> @editor.buffer.change(@getBufferRange(), text) - insertNewline: -> - @insertText('\n') - delete: -> range = @getBufferRange() @editor.buffer.change(range, '') unless range.isEmpty() diff --git a/src/atom/window.coffee b/src/atom/window.coffee index 70e7f9798..7b732da7f 100644 --- a/src/atom/window.coffee +++ b/src/atom/window.coffee @@ -17,11 +17,11 @@ windowAdditions = startup: (url) -> @setupKeymap() @attachRootView(url) - - $(window).on 'close', => + + $(window).on 'close', => @shutdown() @close() - + $(window).focus() atom.windowOpened this @@ -33,7 +33,7 @@ windowAdditions = setupKeymap: -> @keymap = new GlobalKeymap() - + @keymap.bindDefaultKeys() $(document).on 'keydown', (e) => @keymap.handleKeyEvent(e) attachRootView: (url) ->