diff --git a/CHANGELOG.md b/CHANGELOG.md index 396d90567..96b6201dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +* Improved: Faster and better looking find and replace +* Improved: Double-click selection behavior between word/non-word * Added: Solarized theme now bundled by default * Added: Base16 Tomorrow Dark theme now bundled by default diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4e56232bc..f71699b60 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,8 +16,6 @@ styleguides * Include thoughtfully worded [Jasmine](http://pivotal.github.com/jasmine/) specs - * Style new elements in both the light and dark default themes when - appropriate * Add 3rd-party packages as a `package.json` dependency * Commit messages are in the present tense * Commit messages that improve the format of the code start with :lipstick: diff --git a/dot-atom/themes/README.md b/dot-atom/themes/README.md deleted file mode 100644 index dbedd5e13..000000000 --- a/dot-atom/themes/README.md +++ /dev/null @@ -1 +0,0 @@ -All themes in this directory will be automatically loaded diff --git a/package.json b/package.json index a75decff8..847d9209f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "bugs": { "url": "https://github.com/atom/atom/issues" }, - "atomShellVersion": "0.5.1", + "atomShellVersion": "0.5.3", "dependencies": { "async": "0.2.6", "bootstrap": "git://github.com/twbs/bootstrap.git#v3.0.0", diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 7e8129746..7e60ba0d3 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -181,7 +181,6 @@ describe "Config", -> expect(fs.exists(config.configDirPath)).toBeTruthy() expect(fs.exists(path.join(config.configDirPath, 'packages'))).toBeTruthy() expect(fs.exists(path.join(config.configDirPath, 'snippets'))).toBeTruthy() - expect(fs.exists(path.join(config.configDirPath, 'themes'))).toBeTruthy() expect(fs.isFileSync(path.join(config.configDirPath, 'config.cson'))).toBeTruthy() describe ".loadUserConfig()", -> diff --git a/spec/editor-spec.coffee b/spec/editor-spec.coffee index 3890f1448..afb7bf8c8 100644 --- a/spec/editor-spec.coffee +++ b/spec/editor-spec.coffee @@ -440,6 +440,29 @@ describe "Editor", -> editor.renderedLines.trigger mousedownEvent(editor: editor, point: [3, 12], originalEvent: {detail: 1}, shiftKey: true) expect(editor.getSelectedBufferRange()).toEqual [[3, 10], [3, 12]] + describe "when clicking between a word and a non-word", -> + it "selects the word", -> + expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0) + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [1, 21], originalEvent: {detail: 1}) + editor.renderedLines.trigger 'mouseup' + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [1, 21], originalEvent: {detail: 2}) + editor.renderedLines.trigger 'mouseup' + expect(editor.getSelectedText()).toBe "function" + + editor.setCursorBufferPosition([0, 0]) + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [1, 22], originalEvent: {detail: 1}) + editor.renderedLines.trigger 'mouseup' + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [1, 22], originalEvent: {detail: 2}) + editor.renderedLines.trigger 'mouseup' + expect(editor.getSelectedText()).toBe "items" + + editor.setCursorBufferPosition([0, 0]) + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [0, 28], originalEvent: {detail: 1}) + editor.renderedLines.trigger 'mouseup' + editor.renderedLines.trigger mousedownEvent(editor: editor, point: [0, 28], originalEvent: {detail: 2}) + editor.renderedLines.trigger 'mouseup' + expect(editor.getSelectedText()).toBe "{" + describe "triple/quardruple/etc-click", -> it "selects the line under the cursor", -> expect(editor.getCursorScreenPosition()).toEqual(row: 0, column: 0) diff --git a/src/atom.coffee b/src/atom.coffee index 5c68888bc..723f9a7f4 100644 --- a/src/atom.coffee +++ b/src/atom.coffee @@ -4,6 +4,7 @@ _ = require './underscore-extensions' Package = require './package' ipc = require 'ipc' remote = require 'remote' +shell = require 'shell' crypto = require 'crypto' path = require 'path' dialog = remote.require 'dialog' @@ -284,6 +285,9 @@ window.atom = crashRenderProcess: -> process.crash() + beep: -> + shell.beep() + requireUserInitScript: -> userInitScriptPath = path.join(config.configDirPath, "user.coffee") try diff --git a/src/cursor.coffee b/src/cursor.coffee index 01a0b0b61..0b3941f22 100644 --- a/src/cursor.coffee +++ b/src/cursor.coffee @@ -102,10 +102,21 @@ class Cursor # Public: Returns the visibility of the cursor. isVisible: -> @visible - # Public: Returns a RegExp of what the cursor considers a "word" - wordRegExp: -> - nonWordCharacters = config.get("editor.nonWordCharacters") - new RegExp("^[\t ]*$|[^\\s#{_.escapeRegExp(nonWordCharacters)}]+|[#{_.escapeRegExp(nonWordCharacters)}]+", "g") + # Public: Get the RegExp used by the cursor to determine what a "word" is. + # + # * options: + # + includeNonWordCharacters: + # A Boolean indicating whether to include non-word characters in the regex. + # + # Returns a RegExp. + wordRegExp: ({includeNonWordCharacters}={})-> + includeNonWordCharacters ?= true + nonWordCharacters = config.get('editor.nonWordCharacters') + segments = ["^[\t ]*$"] + segments.push("[^\\s#{_.escapeRegExp(nonWordCharacters)}]+") + if includeNonWordCharacters + segments.push("[#{_.escapeRegExp(nonWordCharacters)}]+") + new RegExp(segments.join("|"), "g") # Public: Identifies if this cursor is the last in the {EditSession}. # @@ -126,6 +137,25 @@ class Cursor range = [[row, Math.min(0, column - 1)], [row, Math.max(0, column + 1)]] /^\s+$/.test @editSession.getTextInBufferRange(range) + # Public: Returns whether the cursor is currently between a word and non-word + # character. The non-word characters are defined by the + # `editor.nonWordCharacters` config value. + # + # This method returns false if the character before or after the cursor is + # whitespace. + # + # Returns a Boolean. + isBetweenWordAndNonWord: -> + return false if @isAtBeginningOfLine() or @isAtEndOfLine() + + {row, column} = @getBufferPosition() + range = [[row, column - 1], [row, column + 1]] + [before, after] = @editSession.getTextInBufferRange(range) + return false if /\s/.test(before) or /\s/.test(after) + + nonWordCharacters = config.get('editor.nonWordCharacters').split('') + _.contains(nonWordCharacters, before) isnt _.contains(nonWordCharacters, after) + # Public: Returns whether this cursor is between a word's start and end. isInsideWord: -> {row, column} = @getBufferPosition() @@ -280,6 +310,9 @@ class Cursor # * options: # + wordRegex: # A RegExp indicating what constitutes a "word" (default: {.wordRegExp}) + # + includeNonWordCharacters: + # A Boolean indicating whether to include non-word characters in the + # default word regex. Has no effect if wordRegex is set. # # Returns a {Range}. getBeginningOfCurrentWordBufferPosition: (options = {}) -> @@ -289,7 +322,7 @@ class Cursor scanRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = null - @editSession.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) => + @editSession.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) => if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious beginningOfWordPosition = range.start if not beginningOfWordPosition?.isEqual(currentBufferPosition) @@ -297,7 +330,7 @@ class Cursor beginningOfWordPosition or currentBufferPosition - # Public: Retrieves buffer position of previous word boundry. It might be on + # Public: Retrieves buffer position of previous word boundary. It might be on # the current word, or the previous word. getPreviousWordBoundaryBufferPosition: (options = {}) -> currentBufferPosition = @getBufferPosition() @@ -319,7 +352,7 @@ class Cursor beginningOfWordPosition or currentBufferPosition - # Public: Retrieves buffer position of the next word boundry. It might be on + # Public: Retrieves buffer position of the next word boundary. It might be on # the current word, or the previous word. getMoveNextWordBoundaryBufferPosition: (options = {}) -> currentBufferPosition = @getBufferPosition() @@ -345,6 +378,9 @@ class Cursor # * options: # + wordRegex: # A RegExp indicating what constitutes a "word" (default: {.wordRegExp}) + # + includeNonWordCharacters: + # A Boolean indicating whether to include non-word characters in the + # default word regex. Has no effect if wordRegex is set. # # Returns a {Range}. getEndOfCurrentWordBufferPosition: (options = {}) -> @@ -353,7 +389,7 @@ class Cursor scanRange = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) => + @editSession.scanInBufferRange (options.wordRegex ? @wordRegExp(options)), scanRange, ({range, stop}) => if range.start.isLessThanOrEqual(currentBufferPosition) or allowNext endOfWordPosition = range.end if not endOfWordPosition?.isEqual(currentBufferPosition) diff --git a/src/selection.coffee b/src/selection.coffee index c48d05cf9..7b184a64c 100644 --- a/src/selection.coffee +++ b/src/selection.coffee @@ -115,6 +115,8 @@ class Selection selectWord: -> options = {} options.wordRegex = /[\t ]*/ if @cursor.isSurroundedByWhitespace() + if @cursor.isBetweenWordAndNonWord() + options.includeNonWordCharacters = false @setBufferRange(@cursor.getCurrentWordBufferRange(options)) @wordwise = true