diff --git a/apm/package.json b/apm/package.json index 6623876f9..4ddb4dabe 100644 --- a/apm/package.json +++ b/apm/package.json @@ -6,6 +6,6 @@ "url": "https://github.com/atom/atom.git" }, "dependencies": { - "atom-package-manager": "1.9.2" + "atom-package-manager": "1.9.3" } } diff --git a/package.json b/package.json index f8213b354..bff11c2f2 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "marked": "^0.3.4", "normalize-package-data": "^2.0.0", "nslog": "^3", - "ohnogit": "0.0.9", + "ohnogit": "0.0.11", "oniguruma": "^5", "pathwatcher": "~6.2", "property-accessors": "^1.1.3", @@ -107,7 +107,7 @@ "settings-view": "0.235.1", "snippets": "1.0.2", "spell-check": "0.67.1", - "status-bar": "1.2.4", + "status-bar": "1.2.6", "styleguide": "0.45.2", "symbols-view": "0.112.0", "tabs": "0.93.1", @@ -141,7 +141,7 @@ "language-ruby": "0.68.5", "language-ruby-on-rails": "0.25.0", "language-sass": "0.47.0", - "language-shellscript": "0.21.1", + "language-shellscript": "0.22.0", "language-source": "0.9.0", "language-sql": "0.21.0", "language-text": "0.7.1", diff --git a/spec/fixtures/git/repo-with-submodules/git.git/config b/spec/fixtures/git/repo-with-submodules/git.git/config index ab57cc5f1..323ba7d9b 100644 --- a/spec/fixtures/git/repo-with-submodules/git.git/config +++ b/spec/fixtures/git/repo-with-submodules/git.git/config @@ -5,6 +5,12 @@ logallrefupdates = true ignorecase = true precomposeunicode = true +[branch "master"] + remote = origin + merge = refs/heads/master +[remote "origin"] + url = git@github.com:atom/some-repo-i-guess.git + fetch = +refs/heads/*:refs/remotes/origin/* [submodule "jstips"] url = https://github.com/loverajoel/jstips [submodule "You-Dont-Need-jQuery"] diff --git a/spec/fixtures/git/repo-with-submodules/git.git/refs/remotes/origin/master b/spec/fixtures/git/repo-with-submodules/git.git/refs/remotes/origin/master new file mode 100644 index 000000000..3507a23dc --- /dev/null +++ b/spec/fixtures/git/repo-with-submodules/git.git/refs/remotes/origin/master @@ -0,0 +1 @@ +d2b0ad9cbc6f6c4372e8956e5cc5af771b2342e5 diff --git a/spec/git-repository-async-spec.js b/spec/git-repository-async-spec.js index d36b9fd58..1fbe537d5 100644 --- a/spec/git-repository-async-spec.js +++ b/spec/git-repository-async-spec.js @@ -877,4 +877,34 @@ describe('GitRepositoryAsync', () => { }) }) }) + + describe('.getOriginURL()', () => { + beforeEach(() => { + const workingDirectory = copyRepository('repo-with-submodules') + repo = GitRepositoryAsync.open(workingDirectory) + }) + + it('returns the origin URL', async () => { + const url = await repo.getOriginURL() + expect(url).toBe('git@github.com:atom/some-repo-i-guess.git') + }) + }) + + describe('.getUpstreamBranch()', () => { + it('returns null when there is no upstream branch', async () => { + const workingDirectory = copyRepository() + repo = GitRepositoryAsync.open(workingDirectory) + + const upstream = await repo.getUpstreamBranch() + expect(upstream).toBe(null) + }) + + it('returns the upstream branch', async () => { + const workingDirectory = copyRepository('repo-with-submodules') + repo = GitRepositoryAsync.open(workingDirectory) + + const upstream = await repo.getUpstreamBranch() + expect(upstream).toBe('refs/remotes/origin/master') + }) + }) }) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 565f92430..1298727a9 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5738,28 +5738,6 @@ describe "TextEditor", -> expect(handler).toHaveBeenCalledWith 'OK' expect(editor.getPlaceholderText()).toBe 'OK' - describe ".checkoutHeadRevision()", -> - it "reverts to the version of its file checked into the project repository", -> - atom.config.set("editor.confirmCheckoutHeadRevision", false) - - editor.setCursorBufferPosition([0, 0]) - editor.insertText("---\n") - expect(editor.lineTextForBufferRow(0)).toBe "---" - - waitsForPromise -> - editor.checkoutHeadRevision() - - runs -> - expect(editor.lineTextForBufferRow(0)).toBe "var quicksort = function () {" - - describe "when there's no repository for the editor's file", -> - it "doesn't do anything", -> - editor = atom.workspace.buildTextEditor() - editor.setText("stuff") - editor.checkoutHeadRevision() - - waitsForPromise -> editor.checkoutHeadRevision() - describe 'gutters', -> describe 'the TextEditor constructor', -> it 'creates a line-number gutter', -> diff --git a/spec/workspace-spec.coffee b/spec/workspace-spec.coffee index 6d53fb645..f08e85558 100644 --- a/spec/workspace-spec.coffee +++ b/spec/workspace-spec.coffee @@ -1617,5 +1617,47 @@ describe "Workspace", -> runs -> expect(pane.getPendingItem()).toBeFalsy() + describe "grammar activation", -> + beforeEach -> + waitsForPromise -> + atom.packages.activatePackage('language-javascript') + + it "notifies the workspace of which grammar is used", -> + editor = null + + grammarUsed = jasmine.createSpy() + atom.workspace.handleGrammarUsed = grammarUsed + + waitsForPromise -> atom.workspace.open('sample-with-comments.js').then (o) -> editor = o + waitsFor -> grammarUsed.callCount is 1 + runs -> + expect(grammarUsed.argsForCall[0][0].name).toBe 'JavaScript' + + describe ".checkoutHeadRevision()", -> + editor = null + beforeEach -> + atom.config.set("editor.confirmCheckoutHeadRevision", false) + + waitsForPromise -> atom.workspace.open('sample-with-comments.js').then (o) -> editor = o + + it "reverts to the version of its file checked into the project repository", -> + editor.setCursorBufferPosition([0, 0]) + editor.insertText("---\n") + expect(editor.lineTextForBufferRow(0)).toBe "---" + + waitsForPromise -> + atom.workspace.checkoutHeadRevision(editor) + + runs -> + expect(editor.lineTextForBufferRow(0)).toBe "" + + describe "when there's no repository for the editor's file", -> + it "doesn't do anything", -> + editor = atom.workspace.buildTextEditor() + editor.setText("stuff") + atom.workspace.checkoutHeadRevision(editor) + + waitsForPromise -> atom.workspace.checkoutHeadRevision(editor) + escapeStringRegex = (str) -> str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&') diff --git a/src/git-repository-async.js b/src/git-repository-async.js index 37131dd24..b691994bc 100644 --- a/src/git-repository-async.js +++ b/src/git-repository-async.js @@ -234,7 +234,7 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to the {String} origin url of the // repository. getOriginURL (_path) { - return this.repo.getOriginalURL(_path) + return this.repo.getOriginURL(_path) } // Public: Returns the upstream branch for the current HEAD, or null if there @@ -246,7 +246,7 @@ export default class GitRepositoryAsync { // Returns a {Promise} which resolves to a {String} branch name such as // `refs/remotes/origin/master`. getUpstreamBranch (_path) { - return this.getUpstreamBranch(_path) + return this.repo.getUpstreamBranch(_path) } // Public: Gets all the local and remote references. diff --git a/src/project.coffee b/src/project.coffee index 93a3ed496..bf64753cf 100644 --- a/src/project.coffee +++ b/src/project.coffee @@ -391,6 +391,9 @@ class Project extends Model subscribeToBuffer: (buffer) -> buffer.onDidDestroy => @removeBuffer(buffer) + buffer.onDidChangePath => + unless @getPaths().length > 0 + @setPaths([path.dirname(buffer.getPath())]) buffer.onWillThrowWatchError ({error, handle}) => handle() @notificationManager.addWarning """ diff --git a/src/register-default-commands.coffee b/src/register-default-commands.coffee index 4f329e943..035750363 100644 --- a/src/register-default-commands.coffee +++ b/src/register-default-commands.coffee @@ -204,7 +204,7 @@ module.exports = ({commandRegistry, commandInstaller, config, notificationManage 'editor:newline-below': -> @insertNewlineBelow() 'editor:newline-above': -> @insertNewlineAbove() 'editor:toggle-line-comments': -> @toggleLineCommentsInSelection() - 'editor:checkout-head-revision': -> @checkoutHeadRevision() + 'editor:checkout-head-revision': -> atom.workspace.checkoutHeadRevision(this) 'editor:move-line-up': -> @moveLineUp() 'editor:move-line-down': -> @moveLineDown() 'editor:move-selection-left': -> @moveSelectionLeft() diff --git a/src/text-editor.coffee b/src/text-editor.coffee index ce53cc3ed..2997a87e8 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -10,7 +10,6 @@ Cursor = require './cursor' Model = require './model' Selection = require './selection' TextMateScopeSelector = require('first-mate').ScopeSelector -{Directory} = require "pathwatcher" GutterContainer = require './gutter-container' TextEditorElement = require './text-editor-element' {isDoubleWidthCharacter, isHalfWidthCharacter, isKoreanCharacter, isWrapBoundary} = require './text-utils' @@ -108,13 +107,9 @@ class TextEditor extends Model state.displayLayer = state.buffer.getDisplayLayer(state.displayLayerId) ? state.buffer.addDisplayLayer() state.selectionsMarkerLayer = state.displayLayer.getMarkerLayer(state.selectionsMarkerLayerId) state.config = atomEnvironment.config - state.packageManager = atomEnvironment.packages state.clipboard = atomEnvironment.clipboard - state.viewRegistry = atomEnvironment.views state.grammarRegistry = atomEnvironment.grammars - state.project = atomEnvironment.project state.assert = atomEnvironment.assert.bind(atomEnvironment) - state.applicationDelegate = atomEnvironment.applicationDelegate editor = new this(state) if state.registered disposable = atomEnvironment.textEditors.add(editor) @@ -127,18 +122,14 @@ class TextEditor extends Model { @softTabs, @firstVisibleScreenRow, @firstVisibleScreenColumn, initialLine, initialColumn, @tabLength, @softWrapped, @decorationManager, @selectionsMarkerLayer, @buffer, suppressCursorCreation, - @mini, @placeholderText, lineNumberGutterVisible, @largeFileMode, @config, - @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate, grammar, @showInvisibles, @autoHeight, @scrollPastEnd, - @editorWidthInChars, @tokenizedBuffer, @ignoreInvisibles, @displayLayer + @mini, @placeholderText, lineNumberGutterVisible, @largeFileMode, @config, @clipboard, @grammarRegistry, + @assert, @applicationDelegate, grammar, @showInvisibles, @autoHeight, @scrollPastEnd, @editorWidthInChars, + @tokenizedBuffer, @ignoreInvisibles, @displayLayer } = params throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? - throw new Error("Must pass a packageManager parameter when constructing TextEditors") unless @packageManager? throw new Error("Must pass a clipboard parameter when constructing TextEditors") unless @clipboard? - throw new Error("Must pass a viewRegistry parameter when constructing TextEditors") unless @viewRegistry? throw new Error("Must pass a grammarRegistry parameter when constructing TextEditors") unless @grammarRegistry? - throw new Error("Must pass a project parameter when constructing TextEditors") unless @project? throw new Error("Must pass an assert parameter when constructing TextEditors") unless @assert? @firstVisibleScreenRow ?= 0 @@ -156,8 +147,7 @@ class TextEditor extends Model @buffer ?= new TextBuffer @tokenizedBuffer ?= new TokenizedBuffer({ - @tabLength, @buffer, @largeFileMode, @config, - @grammarRegistry, @packageManager, @assert + @tabLength, @buffer, @largeFileMode, @config, @grammarRegistry, @assert }) @displayLayer ?= @buffer.addDisplayLayer() @displayLayer.setTextDecorationLayer(@tokenizedBuffer) @@ -217,8 +207,6 @@ class TextEditor extends Model subscribeToBuffer: -> @buffer.retain() @disposables.add @buffer.onDidChangePath => - unless @project.getPaths().length > 0 - @project.setPaths([path.dirname(@getPath())]) @emitter.emit 'did-change-title', @getTitle() @emitter.emit 'did-change-path', @getPath() @disposables.add @buffer.onDidChangeEncoding => @@ -559,12 +547,12 @@ class TextEditor extends Model onDidChangeScrollTop: (callback) -> Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollTop instead.") - @viewRegistry.getView(this).onDidChangeScrollTop(callback) + @getElement().onDidChangeScrollTop(callback) onDidChangeScrollLeft: (callback) -> Grim.deprecate("This is now a view method. Call TextEditorElement::onDidChangeScrollLeft instead.") - @viewRegistry.getView(this).onDidChangeScrollLeft(callback) + @getElement().onDidChangeScrollLeft(callback) onDidRequestAutoscroll: (callback) -> @emitter.on 'did-request-autoscroll', callback @@ -589,10 +577,9 @@ class TextEditor extends Model softTabs = @getSoftTabs() newEditor = new TextEditor({ @buffer, selectionsMarkerLayer, @tabLength, softTabs, - suppressCursorCreation: true, @config, @packageManager, + suppressCursorCreation: true, @config, @firstVisibleScreenRow, @firstVisibleScreenColumn, - @clipboard, @viewRegistry, @grammarRegistry, @project, @assert, @applicationDelegate, - displayLayer + @clipboard, @grammarRegistry, @assert, displayLayer }) newEditor @@ -792,25 +779,6 @@ class TextEditor extends Model # via {Pane::saveItemAs}. getSaveDialogOptions: -> {} - checkoutHeadRevision: -> - if @getPath() - checkoutHead = => - @project.repositoryForDirectory(new Directory(@getDirectoryPath())) - .then (repository) => - repository?.async.checkoutHeadForEditor(this) - - if @config.get('editor.confirmCheckoutHeadRevision') - @applicationDelegate.confirm - message: 'Confirm Checkout HEAD Revision' - detailedMessage: "Are you sure you want to discard all changes to \"#{@getFileName()}\" since the last Git commit?" - buttons: - OK: checkoutHead - Cancel: null - else - checkoutHead() - else - Promise.resolve(false) - ### Section: Reading Text ### @@ -3304,12 +3272,12 @@ class TextEditor extends Model scrollToTop: -> Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.") - @viewRegistry.getView(this).scrollToTop() + @getElement().scrollToTop() scrollToBottom: -> Grim.deprecate("This is now a view method. Call TextEditorElement::scrollToTop instead.") - @viewRegistry.getView(this).scrollToBottom() + @getElement().scrollToBottom() scrollToScreenRange: (screenRange, options = {}) -> scrollEvent = {screenRange, options} @@ -3318,12 +3286,12 @@ class TextEditor extends Model getHorizontalScrollbarHeight: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getHorizontalScrollbarHeight instead.") - @viewRegistry.getView(this).getHorizontalScrollbarHeight() + @getElement().getHorizontalScrollbarHeight() getVerticalScrollbarWidth: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getVerticalScrollbarWidth instead.") - @viewRegistry.getView(this).getVerticalScrollbarWidth() + @getElement().getVerticalScrollbarWidth() pageUp: -> @moveUp(@getRowsPerPage()) @@ -3390,11 +3358,11 @@ class TextEditor extends Model pixelPositionForBufferPosition: (bufferPosition) -> Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForBufferPosition` instead") - @viewRegistry.getView(this).pixelPositionForBufferPosition(bufferPosition) + @getElement().pixelPositionForBufferPosition(bufferPosition) pixelPositionForScreenPosition: (screenPosition) -> Grim.deprecate("This method is deprecated on the model layer. Use `TextEditorElement::pixelPositionForScreenPosition` instead") - @viewRegistry.getView(this).pixelPositionForScreenPosition(screenPosition) + @getElement().pixelPositionForScreenPosition(screenPosition) getVerticalScrollMargin: -> maxScrollMargin = Math.floor(((@height / @getLineHeightInPixels()) - 1) / 2) @@ -3440,7 +3408,7 @@ class TextEditor extends Model @height = height else Grim.deprecate("This is now a view method. Call TextEditorElement::setHeight instead.") - @viewRegistry.getView(this).setHeight(height) + @getElement().setHeight(height) getHeight: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getHeight instead.") @@ -3454,7 +3422,7 @@ class TextEditor extends Model @width else Grim.deprecate("This is now a view method. Call TextEditorElement::setWidth instead.") - @viewRegistry.getView(this).setWidth(width) + @getElement().setWidth(width) getWidth: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getWidth instead.") @@ -3494,77 +3462,77 @@ class TextEditor extends Model getScrollTop: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollTop instead.") - @viewRegistry.getView(this).getScrollTop() + @getElement().getScrollTop() setScrollTop: (scrollTop) -> Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollTop instead.") - @viewRegistry.getView(this).setScrollTop(scrollTop) + @getElement().setScrollTop(scrollTop) getScrollBottom: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollBottom instead.") - @viewRegistry.getView(this).getScrollBottom() + @getElement().getScrollBottom() setScrollBottom: (scrollBottom) -> Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollBottom instead.") - @viewRegistry.getView(this).setScrollBottom(scrollBottom) + @getElement().setScrollBottom(scrollBottom) getScrollLeft: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollLeft instead.") - @viewRegistry.getView(this).getScrollLeft() + @getElement().getScrollLeft() setScrollLeft: (scrollLeft) -> Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollLeft instead.") - @viewRegistry.getView(this).setScrollLeft(scrollLeft) + @getElement().setScrollLeft(scrollLeft) getScrollRight: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollRight instead.") - @viewRegistry.getView(this).getScrollRight() + @getElement().getScrollRight() setScrollRight: (scrollRight) -> Grim.deprecate("This is now a view method. Call TextEditorElement::setScrollRight instead.") - @viewRegistry.getView(this).setScrollRight(scrollRight) + @getElement().setScrollRight(scrollRight) getScrollHeight: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollHeight instead.") - @viewRegistry.getView(this).getScrollHeight() + @getElement().getScrollHeight() getScrollWidth: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getScrollWidth instead.") - @viewRegistry.getView(this).getScrollWidth() + @getElement().getScrollWidth() getMaxScrollTop: -> Grim.deprecate("This is now a view method. Call TextEditorElement::getMaxScrollTop instead.") - @viewRegistry.getView(this).getMaxScrollTop() + @getElement().getMaxScrollTop() intersectsVisibleRowRange: (startRow, endRow) -> Grim.deprecate("This is now a view method. Call TextEditorElement::intersectsVisibleRowRange instead.") - @viewRegistry.getView(this).intersectsVisibleRowRange(startRow, endRow) + @getElement().intersectsVisibleRowRange(startRow, endRow) selectionIntersectsVisibleRowRange: (selection) -> Grim.deprecate("This is now a view method. Call TextEditorElement::selectionIntersectsVisibleRowRange instead.") - @viewRegistry.getView(this).selectionIntersectsVisibleRowRange(selection) + @getElement().selectionIntersectsVisibleRowRange(selection) screenPositionForPixelPosition: (pixelPosition) -> Grim.deprecate("This is now a view method. Call TextEditorElement::screenPositionForPixelPosition instead.") - @viewRegistry.getView(this).screenPositionForPixelPosition(pixelPosition) + @getElement().screenPositionForPixelPosition(pixelPosition) pixelRectForScreenRange: (screenRange) -> Grim.deprecate("This is now a view method. Call TextEditorElement::pixelRectForScreenRange instead.") - @viewRegistry.getView(this).pixelRectForScreenRange(screenRange) + @getElement().pixelRectForScreenRange(screenRange) ### Section: Utility diff --git a/src/tokenized-buffer.coffee b/src/tokenized-buffer.coffee index 4636ceddc..ea7082a6d 100644 --- a/src/tokenized-buffer.coffee +++ b/src/tokenized-buffer.coffee @@ -30,14 +30,13 @@ class TokenizedBuffer extends Model state.buffer = atomEnvironment.project.bufferForPathSync(state.bufferPath) state.config = atomEnvironment.config state.grammarRegistry = atomEnvironment.grammars - state.packageManager = atomEnvironment.packages state.assert = atomEnvironment.assert new this(state) constructor: (params) -> { @buffer, @tabLength, @largeFileMode, @config, - @grammarRegistry, @packageManager, @assert, grammarScopeName + @grammarRegistry, @assert, grammarScopeName } = params @emitter = new Emitter @@ -128,7 +127,7 @@ class TokenizedBuffer extends Model @disposables.add(@configSubscriptions) @retokenizeLines() - @packageManager.triggerActivationHook("#{grammar.packageName}:grammar-used") + @emitter.emit 'did-change-grammar', grammar getGrammarSelectionContent: -> diff --git a/src/workspace.coffee b/src/workspace.coffee index 838a1dcec..f75f00bc6 100644 --- a/src/workspace.coffee +++ b/src/workspace.coffee @@ -4,6 +4,7 @@ path = require 'path' {join} = path {Emitter, Disposable, CompositeDisposable} = require 'event-kit' fs = require 'fs-plus' +{Directory} = require 'pathwatcher' DefaultDirectorySearcher = require './default-directory-searcher' Model = require './model' TextEditor = require './text-editor' @@ -550,9 +551,17 @@ class Workspace extends Model @project.bufferForPath(filePath, options).then (buffer) => editor = @buildTextEditor(_.extend({buffer, largeFileMode}, options)) disposable = atom.textEditors.add(editor) - editor.onDidDestroy -> disposable.dispose() + grammarSubscription = editor.observeGrammar(@handleGrammarUsed.bind(this)) + editor.onDidDestroy -> + grammarSubscription.dispose() + disposable.dispose() editor + handleGrammarUsed: (grammar) -> + return unless grammar? + + @packageManager.triggerActivationHook("#{grammar.packageName}:grammar-used") + # Public: Returns a {Boolean} that is `true` if `object` is a `TextEditor`. # # * `object` An {Object} you want to perform the check against. @@ -564,8 +573,7 @@ class Workspace extends Model # Returns a {TextEditor}. buildTextEditor: (params) -> params = _.extend({ - @config, @packageManager, @clipboard, @viewRegistry, - @grammarRegistry, @project, @assert, @applicationDelegate + @config, @clipboard, @grammarRegistry, @assert }, params) new TextEditor(params) @@ -1079,3 +1087,22 @@ class Workspace extends Model inProcessFinished = true checkFinished() + + checkoutHeadRevision: (editor) -> + if editor.getPath() + checkoutHead = => + @project.repositoryForDirectory(new Directory(editor.getDirectoryPath())) + .then (repository) => + repository?.async.checkoutHeadForEditor(editor) + + if @config.get('editor.confirmCheckoutHeadRevision') + @applicationDelegate.confirm + message: 'Confirm Checkout HEAD Revision' + detailedMessage: "Are you sure you want to discard all changes to \"#{editor.getFileName()}\" since the last Git commit?" + buttons: + OK: checkoutHead + Cancel: null + else + checkoutHead() + else + Promise.resolve(false)