From 80529c2f2509fea6f700722ba0d819d2158a23dc Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 8 Nov 2012 09:51:12 -0800 Subject: [PATCH 1/9] Uncommented needed lines in update-cef script --- script/update-cef | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/script/update-cef b/script/update-cef index cd828418b..d58b03a0b 100755 --- a/script/update-cef +++ b/script/update-cef @@ -19,11 +19,11 @@ CEF_RELEASE_BRANCH=${2:-1271} CEF_BINARY_PATH=$(echo "$CEF_DIR"/binary_distrib/cef_binary_*_macosx/) # Expand the path # Update and compile CEF -#CEF_AUTOMATE_SCRIPT_PATH=/tmp/cef-update -#rm -rf $CEF_AUTOMATE_SCRIPT_PATH -#svn checkout http://chromiumembedded.googlecode.com/svn/trunk/cef1/tools/automate $CEF_AUTOMATE_SCRIPT_PATH -#cd $CEF_AUTOMATE_SCRIPT_PATH -#python automate.py --download-dir="$(dirname $CHROMIUM_DIR)" --url=http://chromiumembedded.googlecode.com/svn/branches/$CEF_RELEASE_BRANCH/cef3 +CEF_AUTOMATE_SCRIPT_PATH=/tmp/cef-update +rm -rf $CEF_AUTOMATE_SCRIPT_PATH +svn checkout http://chromiumembedded.googlecode.com/svn/trunk/cef1/tools/automate $CEF_AUTOMATE_SCRIPT_PATH +cd $CEF_AUTOMATE_SCRIPT_PATH +python automate.py --download-dir="$(dirname $CHROMIUM_DIR)" --url=http://chromiumembedded.googlecode.com/svn/branches/$CEF_RELEASE_BRANCH/cef3 # Copy the CEF gypi files and update their paths to match Atom's file layout for GYPI_PATH in "$CEF_DIR/cef_paths.gypi" "$CEF_DIR/cef_paths2.gypi"; do From 207281aa1ccb547ad855f7b04c5bfed06283532b Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 8 Nov 2012 09:55:00 -0800 Subject: [PATCH 2/9] Stole clean-merged-branches from github/github --- script/clean-merged-branches | 41 ++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100755 script/clean-merged-branches diff --git a/script/clean-merged-branches b/script/clean-merged-branches new file mode 100755 index 000000000..04fbd19c8 --- /dev/null +++ b/script/clean-merged-branches @@ -0,0 +1,41 @@ +#!/bin/sh +#/ Usage: clean-merged-branches [-f] +#/ Delete merged branches from the origin remote. +#/ +#/ Options: +#/ -f Really delete the branches. Without this branches are shown +#/ but nothing is deleted. + +set -e + +# show usage maybe +[ "$1" = "--help" ] && { + grep '^#/' <"$0"| cut -c4- + exit 0 +} + +# fetch and prune remote branches +git fetch origin --prune + +# grab list of merged branches +branches=$( + git branch -a --merged origin/master | + grep remotes/origin/ | + grep -v /master | + sed 's@remotes/origin/@@' +) + +# bail out with no branches +[ -z "$branches" ] && { + echo "no merged branches detected" 1>&2 + exit 0 +} + +# delete the branches or just show what would be done without -f +if [ "$1" = -f ]; then + git push origin $(echo "$branches" | sed 's/^ */:/') +else + echo "These branches will be deleted:" 1>&2 + echo "$branches" + echo "Run \`$0 -f' if you're sure." +fi From 608b7ee9e18044cacdf87e37d6de3764361cf829 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Thu, 8 Nov 2012 12:21:20 -0800 Subject: [PATCH 3/9] Throw an exception if OnigRegExp fails to create a regex from a pattern --- native/v8_extensions/onig_reg_exp.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/native/v8_extensions/onig_reg_exp.mm b/native/v8_extensions/onig_reg_exp.mm index 71c991b14..ba1657b1f 100644 --- a/native/v8_extensions/onig_reg_exp.mm +++ b/native/v8_extensions/onig_reg_exp.mm @@ -76,9 +76,13 @@ bool OnigRegExp::Execute(const CefString& name, return true; } else if (name == "buildOnigRegExp") { - CefRefPtr userData = new OnigRegExpUserData(arguments[0]); + CefRefPtr pattern = arguments[0]; + CefRefPtr userData = new OnigRegExpUserData(pattern); + if (!userData->m_regex) { + exception = std::string("Failed to create OnigRegExp from pattern '") + pattern->GetStringValue().ToString() + "'"; + } retval = CefV8Value::CreateObject(NULL); - retval->SetUserData(userData); + retval->SetUserData((CefRefPtr)userData); return true; } From 00a26ae4dadef74537d80901fbd10fa13fc31964 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Wed, 7 Nov 2012 16:18:05 -0800 Subject: [PATCH 4/9] Fix how repositories work in TextMate grammars Previously, we treated all grammar repositories as rules, but some grammars have repositories that are a single pattern. If it is a single pattern, transform it into a rule with one pattern. Fix how repositories work in TextMate grammars Previously, we treated all grammar repositories as rules, but some grammars have repositories that are a single pattern. If it is a single pattern, transform it into a rule with one pattern. --- spec/app/text-mate-grammar-spec.coffee | 45 +++++++++++++++----------- src/app/text-mate-grammar.coffee | 2 +- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/spec/app/text-mate-grammar-spec.coffee b/spec/app/text-mate-grammar-spec.coffee index e694eb302..34e570c10 100644 --- a/spec/app/text-mate-grammar-spec.coffee +++ b/spec/app/text-mate-grammar-spec.coffee @@ -197,25 +197,27 @@ describe "TextMateGrammar", -> expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"] expect(tokens[1]).toEqual value: 'div', scopes: ["text.html.ruby","meta.tag.block.any.html","entity.name.tag.block.any.html"] - expect(tokens[2]).toEqual value: ' class=', scopes: ["text.html.ruby","meta.tag.block.any.html"] - expect(tokens[3]).toEqual value: '\'', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html","punctuation.definition.string.begin.html"] - expect(tokens[4]).toEqual value: 'name', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html"] - expect(tokens[5]).toEqual value: '\'', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html","punctuation.definition.string.end.html"] - expect(tokens[6]).toEqual value: '>', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.end.html"] - expect(tokens[7]).toEqual value: '<%=', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.embedded.ruby"] - expect(tokens[8]).toEqual value: ' ', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] - expect(tokens[9]).toEqual value: 'User', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","support.class.ruby"] - expect(tokens[10]).toEqual value: '.', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.separator.method.ruby"] - expect(tokens[11]).toEqual value: 'find', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] - expect(tokens[12]).toEqual value: '(', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.function.ruby"] - expect(tokens[13]).toEqual value: '2', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","constant.numeric.ruby"] - expect(tokens[14]).toEqual value: ')', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.function.ruby"] - expect(tokens[15]).toEqual value: '.', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.separator.method.ruby"] - expect(tokens[16]).toEqual value: 'full_name ', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] - expect(tokens[17]).toEqual value: '%>', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.embedded.ruby"] - expect(tokens[18]).toEqual value: '', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.end.html"] + expect(tokens[2]).toEqual value: ' ', scopes: ["text.html.ruby","meta.tag.block.any.html"] + expect(tokens[3]).toEqual value: 'class', scopes: ["text.html.ruby","meta.tag.block.any.html", "entity.other.attribute-name.html"] + expect(tokens[4]).toEqual value: '=', scopes: ["text.html.ruby","meta.tag.block.any.html"] + expect(tokens[5]).toEqual value: '\'', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html","punctuation.definition.string.begin.html"] + expect(tokens[6]).toEqual value: 'name', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html"] + expect(tokens[7]).toEqual value: '\'', scopes: ["text.html.ruby","meta.tag.block.any.html","string.quoted.single.html","punctuation.definition.string.end.html"] + expect(tokens[8]).toEqual value: '>', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.end.html"] + expect(tokens[9]).toEqual value: '<%=', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.embedded.ruby"] + expect(tokens[10]).toEqual value: ' ', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] + expect(tokens[11]).toEqual value: 'User', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","support.class.ruby"] + expect(tokens[12]).toEqual value: '.', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.separator.method.ruby"] + expect(tokens[13]).toEqual value: 'find', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] + expect(tokens[14]).toEqual value: '(', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.function.ruby"] + expect(tokens[15]).toEqual value: '2', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","constant.numeric.ruby"] + expect(tokens[16]).toEqual value: ')', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.function.ruby"] + expect(tokens[17]).toEqual value: '.', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.separator.method.ruby"] + expect(tokens[18]).toEqual value: 'full_name ', scopes: ["text.html.ruby","source.ruby.rails.embedded.html"] + expect(tokens[19]).toEqual value: '%>', scopes: ["text.html.ruby","source.ruby.rails.embedded.html","punctuation.section.embedded.ruby"] + expect(tokens[20]).toEqual value: '', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.end.html"] it "can parse a grammar with newline charachters in its regular expressions (regression)", -> grammar = new TextMateGrammar @@ -244,3 +246,8 @@ describe "TextMateGrammar", -> grammar = TextMateBundle.grammarForFilePath("hello.js") {tokens, ruleStack} = grammar.tokenizeLine("// line comment") {tokens, ruleStack} = grammar.tokenizeLine(" // second line comment with a single leading space", ruleStack) + + it "correctly parses content inside an c if block. (regression)", -> + grammar = TextMateBundle.grammarForFilePath("hello.c") + {tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}") + expect(tokens[5].scopes).toEqual ["source.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] diff --git a/src/app/text-mate-grammar.coffee b/src/app/text-mate-grammar.coffee index 38549d0a7..ebecfe5a3 100644 --- a/src/app/text-mate-grammar.coffee +++ b/src/app/text-mate-grammar.coffee @@ -26,6 +26,7 @@ class TextMateGrammar @firstLineRegex = new OnigRegExp(firstLineMatch) if firstLineMatch for name, data of repository + data = {patterns: [data], tempName: name} if data.begin? or data.match? @repository[name] = new Rule(this, data) tokenizeLine: (line, {ruleStack, tabLength}={}) -> @@ -111,7 +112,6 @@ class Rule # Add a `\n` to appease patterns that contain '\n' explicitly return null unless result = @getScanner().findNextMatch(line + "\n", position) { index, captureIndices } = result - # Since the `\n' (added above) is not part of the line, truncate captures to the line's actual length lineLength = line.length captureIndices = captureIndices.map (value, index) -> From f09a1045240f5ed60637be1fe55f25ab66e2a0ae Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Fri, 9 Nov 2012 15:35:40 -0800 Subject: [PATCH 5/9] Treat $base in textmate grammars as if it is $self $base works as $self worked previously. $self will need to be fixed. If inside a embedded grammar $self refers to the embedded grammar while $base refers to the overall grammar. --- spec/app/text-mate-grammar-spec.coffee | 15 +++++++++++---- src/app/text-mate-grammar.coffee | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/spec/app/text-mate-grammar-spec.coffee b/spec/app/text-mate-grammar-spec.coffee index 34e570c10..51d8b229e 100644 --- a/spec/app/text-mate-grammar-spec.coffee +++ b/spec/app/text-mate-grammar-spec.coffee @@ -247,7 +247,14 @@ describe "TextMateGrammar", -> {tokens, ruleStack} = grammar.tokenizeLine("// line comment") {tokens, ruleStack} = grammar.tokenizeLine(" // second line comment with a single leading space", ruleStack) - it "correctly parses content inside an c if block. (regression)", -> - grammar = TextMateBundle.grammarForFilePath("hello.c") - {tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}") - expect(tokens[5].scopes).toEqual ["source.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] + describe "when inside an C block", -> + it "correctly parses a method. (regression)", -> + grammar = TextMateBundle.grammarForFilePath("hello.c") + {tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}") + expect(tokens[5]).toEqual value: "m", scopes: ["source.objc++", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] + + it "correctly parses nested blocks. (regression)", -> + grammar = TextMateBundle.grammarForFilePath("hello.c") + {tokens, ruleStack} = grammar.tokenizeLine("if(1){if(1){m()}}") + expect(tokens[5]).toEqual value: "if", scopes: ["source.c", "meta.block.c", "keyword.control.c"] + expect(tokens[10]).toEqual value: "m", scopes: ["source.c", "meta.block.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] diff --git a/src/app/text-mate-grammar.coffee b/src/app/text-mate-grammar.coffee index ebecfe5a3..4c0a07cc3 100644 --- a/src/app/text-mate-grammar.coffee +++ b/src/app/text-mate-grammar.coffee @@ -75,7 +75,7 @@ class TextMateGrammar ruleForInclude: (name) -> if name[0] == "#" @repository[name[1..]] - else if name == "$self" + else if name == "$self" or name == "$base" @initialRule else TextMateBundle = require 'text-mate-bundle' From 0bb384d98b3f0bd4275386aed988ed8b42725252 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Fri, 9 Nov 2012 15:51:24 -0800 Subject: [PATCH 6/9] Atom is sent to the foreground when launched from the command line. --- native/main_mac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/native/main_mac.mm b/native/main_mac.mm index 9db015762..565c62342 100644 --- a/native/main_mac.mm +++ b/native/main_mac.mm @@ -83,6 +83,7 @@ void listenForPathToOpen(int fd, NSString *socketPath) { dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ [[AtomApplication sharedApplication] open:path]; + [NSApp activateIgnoringOtherApps:YES]; }); } } From 1f7b92495af2a6ce23c5580236477339f4e6f902 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Fri, 9 Nov 2012 16:10:53 -0800 Subject: [PATCH 7/9] fix failing spec --- spec/app/text-mate-grammar-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/app/text-mate-grammar-spec.coffee b/spec/app/text-mate-grammar-spec.coffee index 51d8b229e..351724bd6 100644 --- a/spec/app/text-mate-grammar-spec.coffee +++ b/spec/app/text-mate-grammar-spec.coffee @@ -251,7 +251,7 @@ describe "TextMateGrammar", -> it "correctly parses a method. (regression)", -> grammar = TextMateBundle.grammarForFilePath("hello.c") {tokens, ruleStack} = grammar.tokenizeLine("if(1){m()}") - expect(tokens[5]).toEqual value: "m", scopes: ["source.objc++", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] + expect(tokens[5]).toEqual value: "m", scopes: ["source.c", "meta.block.c", "meta.function-call.c", "support.function.any-method.c"] it "correctly parses nested blocks. (regression)", -> grammar = TextMateBundle.grammarForFilePath("hello.c") From 448060a6198d1331bf42231f5a16586b1247b57d Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Mon, 12 Nov 2012 08:44:16 -0800 Subject: [PATCH 8/9] `rake test` kills all existing Atom processes Existing Atom processes were causes false positive ci builds. --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index 1026bb482..b7c975da4 100644 --- a/Rakefile +++ b/Rakefile @@ -116,6 +116,7 @@ end desc "Run the specs" task :test => ["clean", "clone-default-bundles"] do + `pkill Atom` Rake::Task["run"].invoke("--test") end From bb9c2e1bcb6bf864e888288d68f6dca0246e3e37 Mon Sep 17 00:00:00 2001 From: Corey Johnson Date: Mon, 12 Nov 2012 15:59:44 -0800 Subject: [PATCH 9/9] Handle exceptions thrown during do/undo/redo --- spec/app/undo-manager-spec.coffee | 54 ++++++++++++++++++++++++++++ src/app/undo-manager.coffee | 58 ++++++++++++++++++++++--------- 2 files changed, 95 insertions(+), 17 deletions(-) diff --git a/spec/app/undo-manager-spec.coffee b/spec/app/undo-manager-spec.coffee index 307412a74..d4933f612 100644 --- a/spec/app/undo-manager-spec.coffee +++ b/spec/app/undo-manager-spec.coffee @@ -98,3 +98,57 @@ describe "UndoManager", -> undoManager.undo() expect(buffer.lineForRow(0)).not.toContain("foo") + it "records transactions that occur prior to an exception", -> + spyOn(console, 'error') + buffer.setText("jumpstreet") + undoManager.transact -> + buffer.insert([0,0], "3") + buffer.insert([0,0], "2") + throw new Error("problem") + buffer.insert([0,0], "2") + + expect(console.error).toHaveBeenCalled() + expect(buffer.lineForRow(0)).toBe "23jumpstreet" + undoManager.undo() + expect(buffer.lineForRow(0)).toBe "jumpstreet" + + describe "when a `do` operation throws an exception", -> + it "clears the stack", -> + spyOn(console, 'error') + buffer.setText("word") + class FailingOperation + do: -> throw new Error("I'm a bad do operation") + + buffer.insert([0,0], "1") + undoManager.pushOperation(new FailingOperation()) + expect(console.error).toHaveBeenCalled() + undoManager.undo() + expect(buffer.lineForRow(0)).toBe "1word" + + + describe "when an `undo` operation throws an exception", -> + it "clears the stack", -> + spyOn(console, 'error') + buffer.setText("word") + class FailingOperation + undo: -> throw new Error("I'm a bad undo operation") + + buffer.insert([0,0], "1") + undoManager.pushOperation(new FailingOperation()) + undoManager.undo() + expect(console.error).toHaveBeenCalled() + expect(buffer.lineForRow(0)).toBe "1word" + + describe "when an `redo` operation throws an exception", -> + it "clears the stack", -> + spyOn(console, 'error') + buffer.setText("word") + class FailingOperation + redo: -> throw new Error("I'm a bad undo operation") + + buffer.insert([0,0], "1") + undoManager.pushOperation(new FailingOperation()) + undoManager.undo() + undoManager.redo() + expect(console.error).toHaveBeenCalled() + expect(buffer.lineForRow(0)).toBe "1word" \ No newline at end of file diff --git a/src/app/undo-manager.coffee b/src/app/undo-manager.coffee index 21760ef62..d3e4b8273 100644 --- a/src/app/undo-manager.coffee +++ b/src/app/undo-manager.coffee @@ -8,7 +8,10 @@ class UndoManager currentTransaction: null constructor: -> - @startBatchCallCount = 0 + @clear() + + clear: -> + @currentTransaction = null @undoHistory = [] @redoHistory = [] @@ -18,29 +21,50 @@ class UndoManager else @undoHistory.push([operation]) @redoHistory = [] - operation.do?(editSession) + + try + operation.do?(editSession) + catch e + console.error e.stack + @clear() transact: (fn) -> + safeFn = -> + try + fn() + catch e + console.error e.stack + if @currentTransaction - fn() + safeFn() else @currentTransaction = [] - fn() - @undoHistory.push(@currentTransaction) if @currentTransaction.length + safeFn() + @undoHistory.push(@currentTransaction) if @currentTransaction?.length @currentTransaction = null undo: (editSession) -> - if batch = @undoHistory.pop() - opsInReverse = new Array(batch...) - opsInReverse.reverse() - op.undo?(editSession) for op in opsInReverse - @redoHistory.push batch - batch.oldSelectionRanges + try + if batch = @undoHistory.pop() + opsInReverse = new Array(batch...) + opsInReverse.reverse() + op.undo?(editSession) for op in opsInReverse + + @redoHistory.push batch + batch.oldSelectionRanges + catch e + console.error e.stack + @clear() redo: (editSession) -> - if batch = @redoHistory.pop() - for op in batch - op.do?(editSession) - op.redo?(editSession) - @undoHistory.push(batch) - batch.newSelectionRanges + try + if batch = @redoHistory.pop() + for op in batch + op.do?(editSession) + op.redo?(editSession) + + @undoHistory.push(batch) + batch.newSelectionRanges + catch e + console.error e.stack + @clear()