Merge branch 'master' into win-bootstrap-native-modules

This commit is contained in:
Kevin Sawicki 2013-10-28 17:33:39 -07:00
commit 2f62123a75
18 changed files with 177 additions and 183 deletions

View File

@ -1,101 +0,0 @@
* 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
* Fixed: Make Atom's version the same as Speakeasy's version
* Fixed: Package generator package not opening window to generated package
* Fixed: Precompile bootstrap.less for faster startup
* Fixed: Save sometimes failing from an editor that was split
* Fixed: Search results not appearing when set to exclude ignores
* Fixed: Status bar and gutter displaying incorrect Git status information
* Fixed: Packages not installing from the Settings view
* Fixed: Spec runner now works from a released build
* Fixed: Literate CoffeeScript not syntax highlighting correctly
* Added: Soft wrap and tab length can now be set in the settings view
* Fixed: Python import statements not syntax highlighting correctly
* Added: Terminal package now bundled by default, open with ctrl-`
* Fixed: Fuzzy finder not showing results for files at a certain depth
* Fixed: Atom > Preferences... menu not opening settings in focused window
* Fixed: Atom failing to launch if the theme being used was not found
* Improved: Theme changes now immediately take effect
* Fixed: Wrap in quotes/parens now works in split panes
* Improved: Autocomplete now includes CSS property names and values
* Improved: Settings GUI is now a pane item
* Added: Support package filtering in Settings GUI
* Added: Dynamically load all config options in the Settings GUI
* Added: Ability to bookmark lines and navigate bookmarks
* Fixed: Error when inserting newlines in CSS
* Fixed: Folding all will fold comments as well
* Added: Ability to fold all code at a given indentation level
* Improved: cmd-n now opens a new tab and cmd-shift-n now opens a new window.
* Added: Inspect Element context menu
* Fixed: Save As dialog now defaults to directory path of current editor
* Fixed: Using toggle comment shortcut respects indentation level
* Fixed: Search never completing in the command panel
* Fixed: cmd-n now works when no windows are open
* Fixed: Error selecting a grammar for an untitled editor
* Added: j/k now can be used to navigate the tree view and archive editor
* Fixed: Atom can now be launched when ~/.atom/config.cson doesn't exist
* Added: Initial collaboration sessions
* Fixed: Empty lines being deleted via uppercase/downcase command
* Fixed: Keybindings not working when using non-English keyboard language
* Fixed: cmd-shift-p and cmd-alt-w not doing anything when pressed
* Improved: Use grunt (instead of rake) for build system
* Fixed: Java files not syntax highlighting correctly.
* Fixed: LESS/CSS now indents properly after hitting enter.
* Added: Support for browsing .tar.gz and .zip files in the editor
* Added: TODO/FIXME/CHANGED are now highlighted in comments.
* Fixed: Full screen state of windows is now persisted across restarts.
* Added: Makefile syntax highlighting now included.
* Added: Open fuzzy finder to specific line using colon suffix (i.e ':25')
* Fixed: Issues deleting and moving over certain UTF-8 characters
* Fixed: Tree view not properly highlighting or revealing for open images.
* Added: Packages can now be installed from the configuration UI.
* Fixed: .git folder now ignored by default when searching
* Fixed: Not being able to disable packages from configuration UI.
* Fixed: Fuzzy finder showing poor results for entered text
* Improved: App icon
* Fixed: Fuzzy finder being empty sometimes
* Improved: App icon
* Fixed: End of line invisibles rendering incorrectly with the indent guide
* Fixed: Updates not installing automatically on restart
* Fixed: Wrap guide not displaying
* Fixed: Error when saving with the markdown preview focused
* Fixed: Atom always running in dev mode
* Fixed: Crash when running in dev mode without a path to the Atom source
* Fixed: Freeze when editing a RoR class
* Added: meta-N to open a new untitled editor in the current window
* Fixed: Styling in command logger
* Added: XML and Ruby syntax highlighting in Markdown files
* Fixed: Error when editing files in a HEAD-less Git repository
* Fixed: Invisible characters not being visible when enabled
* Added: Editor gutter now displays Git status for lines
* Improved: Startup time
* Added: SQL bundle now included
* Added: PEG.js bundle now included
* Added: Hyperlinks can now be opened with ctrl-O
* Fixed: PHP syntax highlighting

View File

@ -30,8 +30,9 @@ built-in keymaps:
'.editor':
'enter': 'editor:newline'
".select-list .editor.mini":
'enter': 'core:confirm'
'body':
'ctrl-P': 'core:move-up'
'ctrl-p': 'core:move-down'
```
This keymap defines the meaning of `enter` in two different contexts. In a
@ -40,10 +41,9 @@ the editor to insert a newline. But if the same keystroke occurs inside of a
select list's mini-editor, it instead emits the `core:confirm` event based on
the binding in the more-specific selector.
By default, any keymap files in your `~/.atom/keymaps` directory are loaded
in alphabetical order when Atom is started. They will always be loaded last,
giving you the chance to override bindings that are defined by Atom's core
keymaps or third-party packages.
By default, `~/.atom/keymap.cson` is loaded when Atom is started. It will always
be loaded last, giving you the chance to override bindings that are defined by
Atom's core keymaps or third-party packages.
## Advanced Configuration

13
dot-atom/keymap.cson Normal file
View File

@ -0,0 +1,13 @@
# User keymap
#
# Atom keymaps work similarly to stylesheets. Just as stylesheets use selectors
# to apply styles to elements, Atom keymaps use selectors to associate
# keystrokes with events in specific contexts. Here's a small example, excerpted
# from Atom's built-in keymaps:
#
# '.editor':
# 'enter': 'editor:newline'
#
# 'body':
# 'ctrl-P': 'core:move-up'
# 'ctrl-p': 'core:move-down'

View File

@ -14,7 +14,7 @@
"async": "0.2.6",
"bootstrap": "git://github.com/twbs/bootstrap.git#v3.0.0",
"clear-cut": "0.1.0",
"coffee-script": "1.6.2",
"coffee-script": "1.6.3",
"coffeestack": "0.6.0",
"emissary": "0.6.0",
"first-mate": "0.5.0",
@ -23,8 +23,7 @@
"guid": "0.0.10",
"jasmine-focused": "~0.15.0",
"mkdirp": "0.3.5",
"less": "git://github.com/nathansobo/less.js.git",
"less-cache": "0.8.0",
"less-cache": "0.9.0",
"nslog": "0.1.0",
"oniguruma": "0.22.0",
"optimist": "0.4.0",
@ -52,7 +51,7 @@
"grunt-cson": "0.5.0",
"grunt-contrib-csslint": "~0.1.2",
"grunt-contrib-coffee": "~0.7.0",
"grunt-contrib-less": "~0.6.4",
"grunt-contrib-less": "~0.8.0",
"walkdir": "0.0.7",
"ws": "0.4.27",
"js-yaml": "~2.1.0",

View File

@ -24,7 +24,7 @@ var commands = [
joinCommands('cd vendor/apm', 'npm install --silent .'),
'npm install --silent vendor/apm',
echoNewLine,
'node vendor/apm/bin/apm install --silent',
'node node_modules/.bin/apm install --silent'
];
process.chdir(path.dirname(__dirname));

View File

@ -10,31 +10,31 @@ if (process.platform != 'darwin')
var homeDir = process.platform == 'win32' ? process.env.USERPROFILE : process.env.HOME;
function readEnvironmentVariables(callback) {
var credenticalsPath = '/var/lib/jenkins/config/atomcredentials';
fs.readFile(credenticalsPath, function(error, data) {
if (!error) {
var lines = String(data).trim().split('\n');
for (i in lines) {
var parts = lines[i].split('=');
var key = parts[0].trim();
var value = parts[1].trim().substr(1, parts[1].length - 2);
process.env[key] = value;
}
function readEnvironmentVariables() {
var credentialsPath = '/var/lib/jenkins/config/atomcredentials';
try {
var credentials = fs.readFileSync(credentialsPath, 'utf8');
var lines = credentials.trim().split('\n');
for (i in lines) {
var parts = lines[i].split('=');
var key = parts[0].trim();
var value = parts[1].trim().substr(1, parts[1].length - 2);
process.env[key] = value;
}
// Do not quit when got error.
callback(null);
});
} catch(error) { }
}
var async = require('async');
async.series([
readEnvironmentVariables,
cp.safeExec.bind(global, 'node script/bootstrap'),
require('rimraf').bind(global, path.join(homeDir, '.atom')),
cp.safeExec.bind(global, 'git clean -dff'),
cp.safeExec.bind(global, 'node node_modules/.bin/apm clean'),
cp.safeExec.bind(global, 'node node_modules/.bin/grunt ci --stack --no-color'),
], function(error) {
process.exit(error ? 1 : 0);
});
readEnvironmentVariables();
cp.safeExec.bind(global, 'node script/bootstrap', function(error) {
if (error)
process.exit(1);
var async = require('async');
async.series([
require('rimraf').bind(global, path.join(homeDir, '.atom')),
cp.safeExec.bind(global, 'git clean -dff'),
cp.safeExec.bind(global, 'node node_modules/.bin/apm clean'),
cp.safeExec.bind(global, 'node node_modules/.bin/grunt ci --stack --no-color'),
], function(error) {
process.exit(error ? 1 : 0);
});
})();

View File

@ -32,6 +32,18 @@ describe "LanguageMode", ->
expect(buffer.lineForRow(6)).toBe " // current < pivot ? left.push(current) : right.push(current);"
expect(buffer.lineForRow(7)).toBe " // }"
buffer.setText('\tvar i;')
languageMode.toggleLineCommentsForBufferRows(0, 0)
expect(buffer.lineForRow(0)).toBe "\t// var i;"
buffer.setText('var i;')
languageMode.toggleLineCommentsForBufferRows(0, 0)
expect(buffer.lineForRow(0)).toBe "// var i;"
buffer.setText(' var i;')
languageMode.toggleLineCommentsForBufferRows(0, 0)
expect(buffer.lineForRow(0)).toBe " // var i;"
describe "fold suggestion", ->
describe ".doesBufferRowStartFold(bufferRow)", ->
it "returns true only when the buffer row starts a foldable region", ->

View File

@ -425,8 +425,20 @@ describe "Project", ->
resultHandler = jasmine.createSpy("result found")
waitsForPromise ->
project.scan /dollar/, (results) ->
console.log results
resultHandler()
runs ->
expect(resultHandler).not.toHaveBeenCalled()
it "scans buffer contents if the buffer is modified", ->
editSession = project.openSync("a")
editSession.setText("Elephant")
results = []
waitsForPromise ->
project.scan /a|Elephant/, (result) -> results.push result
runs ->
expect(results).toHaveLength 3
resultForA = _.find results, ({filePath}) -> path.basename(filePath) == 'a'
expect(resultForA.matches).toHaveLength 1
expect(resultForA.matches[0].matchText).toBe 'Elephant'

View File

@ -5,7 +5,6 @@ describe "TextBuffer replication", ->
beforeEach ->
buffer1 = project.buildBufferSync('sample.js')
buffer1.insert([0, 0], 'changed\n')
doc1 = buffer1.getState()
doc2 = doc1.clone(new Site(2))
doc1.connect(doc2)
@ -14,6 +13,9 @@ describe "TextBuffer replication", ->
waitsFor ->
buffer1.loaded and buffer2.loaded
runs ->
buffer1.insert([0, 0], 'changed\n')
afterEach ->
buffer1.destroy()
buffer2.destroy()

View File

@ -949,24 +949,48 @@ describe 'TextBuffer', ->
expect(buffer2.getText()).toBe(buffer.getText())
describe "when the serialized buffer had unsaved changes", ->
it "restores the previous unsaved state of the buffer", ->
previousText = buffer.getText()
buffer.setText("abc")
describe "when the disk contents were changed since serialization", ->
it "loads the disk contents instead of the previous unsaved state", ->
buffer.release()
state = buffer.serialize()
expect(state.getObject('text')).toBe 'abc'
filePath = temp.openSync('atom').path
fs.writeSync(filePath, "words")
{buffer} = project.openSync(filePath)
buffer.setText("BUFFER CHANGE")
buffer2 = deserialize(state, {project})
state = buffer.serialize()
expect(state.getObject('text')).toBe 'BUFFER CHANGE'
fs.writeSync(filePath, "DISK CHANGE")
waitsFor ->
buffer2.cachedDiskContents
buffer2 = deserialize(state, {project})
runs ->
expect(buffer2.getPath()).toBe(buffer.getPath())
expect(buffer2.getText()).toBe(buffer.getText())
expect(buffer2.isModified()).toBeTruthy()
buffer2.setText(previousText)
expect(buffer2.isModified()).toBeFalsy()
waitsFor ->
buffer2.cachedDiskContents
runs ->
expect(buffer2.getPath()).toBe(buffer.getPath())
expect(buffer2.getText()).toBe("DISK CHANGE")
expect(buffer2.isModified()).toBeFalsy()
describe "when the disk contents are the same since serialization", ->
it "restores the previous unsaved state of the buffer", ->
previousText = buffer.getText()
buffer.setText("abc")
state = buffer.serialize()
expect(state.getObject('text')).toBe 'abc'
buffer2 = deserialize(state, {project})
waitsFor ->
buffer2.cachedDiskContents
runs ->
expect(buffer2.getPath()).toBe(buffer.getPath())
expect(buffer2.getText()).toBe(buffer.getText())
expect(buffer2.isModified()).toBeTruthy()
buffer2.setText(previousText)
expect(buffer2.isModified()).toBeFalsy()
describe "when the serialized buffer was unsaved and had no path", ->
it "restores the previous unsaved state of the buffer", ->

View File

@ -350,7 +350,8 @@ describe "TokenizedBuffer", ->
describe "when the buffer contains surrogate pairs", ->
beforeEach ->
atom.activatePackage('language-javascript', sync: true)
buffer = project.buildBufferSync 'sample-with-pairs.js', """
buffer = project.buildBufferSync 'sample-with-pairs.js'
buffer.setText """
'abc\uD835\uDF97def'
//\uD835\uDF97xyz
"""
@ -389,7 +390,8 @@ describe "TokenizedBuffer", ->
atom.activatePackage('language-ruby-on-rails', sync: true)
atom.activatePackage('language-ruby', sync: true)
buffer = project.bufferForPathSync(null, "<div class='name'><%= User.find(2).full_name %></div>")
buffer = project.bufferForPathSync()
buffer.setText "<div class='name'><%= User.find(2).full_name %></div>"
tokenizedBuffer = new TokenizedBuffer({buffer})
tokenizedBuffer.setGrammar(syntax.selectGrammar('test.erb'))
fullyTokenize(tokenizedBuffer)

View File

@ -1,3 +1,4 @@
crypto = require 'crypto'
path = require 'path'
pathWatcher = require 'pathwatcher'
Q = require 'q'
@ -68,6 +69,9 @@ class File
else
@cachedContents
@setDigest(@cachedContents)
@cachedContents
# Public: Reads the contents of the file.
#
# * flushCache:
@ -101,12 +105,19 @@ class File
promise = Q(@cachedContents)
promise.then (contents) =>
@setDigest(contents)
@cachedContents = contents
# Public: Returns whether the file exists.
exists: ->
fsUtils.exists(@getPath())
setDigest: (contents) ->
@digest = crypto.createHash('sha1').update(contents ? '').digest('hex')
getDigest: ->
@digest ? @setDigest(@readSync())
# Private:
handleNativeChangeEvent: (eventType, path) ->
if eventType is "delete"

View File

@ -36,8 +36,9 @@ class Keymap
@loadDirectory(config.bundledKeymapsDirPath)
@emit('bundled-keymaps-loaded')
loadUserKeymaps: ->
@loadDirectory(path.join(config.configDirPath, 'keymaps'))
loadUserKeymap: ->
userKeymapPath = CSON.resolve(path.join(config.configDirPath, 'keymap'))
@load(userKeymapPath) if userKeymapPath
loadDirectory: (directoryPath) ->
@load(filePath) for filePath in fsUtils.listSync(directoryPath, ['.cson', '.json'])

View File

@ -84,8 +84,14 @@ class LanguageMode
else
indent = @minIndentLevelForRowRange(start, end)
indentString = @editSession.buildIndentString(indent)
tabLength = @editSession.getTabLength()
indentRegex = new RegExp("(\t|[ ]{#{tabLength}}){#{Math.floor(indent)}}")
for row in [start..end]
buffer.change([[row, 0], [row, indentString.length]], indentString + commentStartString)
line = buffer.lineForRow(row)
if indentLength = line.match(indentRegex)?[0].length
buffer.insert([row, indentLength], commentStartString)
else
buffer.change([[row, 0], [row, indentString.length]], indentString + commentStartString)
# Folds all the foldable lines in the buffer.
foldAll: ->

View File

@ -218,14 +218,19 @@ class Project
getBuffers: ->
new Array(@buffers...)
isPathModified: (filePath) ->
absoluteFilePath = @resolve(filePath)
existingBuffer = _.find @buffers, (buffer) -> buffer.getPath() == absoluteFilePath
existingBuffer?.isModified()
# Private: Only to be used in specs
bufferForPathSync: (filePath, text) ->
bufferForPathSync: (filePath) ->
absoluteFilePath = @resolve(filePath)
if filePath
existingBuffer = _.find @buffers, (buffer) -> buffer.getPath() == absoluteFilePath
existingBuffer ? @buildBufferSync(absoluteFilePath, text)
existingBuffer ? @buildBufferSync(absoluteFilePath)
# Private: Given a file path, this retrieves or creates a new {TextBuffer}.
#
@ -233,23 +238,22 @@ class Project
# `text` is used as the contents of the new buffer.
#
# filePath - A {String} representing a path. If `null`, an "Untitled" buffer is created.
# text - The {String} text to use as a buffer, if the file doesn't have any contents
#
# Returns a promise that resolves to the {TextBuffer}.
bufferForPath: (filePath, text) ->
bufferForPath: (filePath) ->
absoluteFilePath = @resolve(filePath)
if absoluteFilePath
existingBuffer = _.find @buffers, (buffer) -> buffer.getPath() == absoluteFilePath
Q(existingBuffer ? @buildBuffer(absoluteFilePath, text))
Q(existingBuffer ? @buildBuffer(absoluteFilePath))
# Private:
bufferForId: (id) ->
_.find @buffers, (buffer) -> buffer.id is id
# Private: DEPRECATED
buildBufferSync: (absoluteFilePath, initialText) ->
buffer = new TextBuffer({project: this, filePath: absoluteFilePath, initialText})
buildBufferSync: (absoluteFilePath) ->
buffer = new TextBuffer({project: this, filePath: absoluteFilePath})
buffer.loadSync()
@addBuffer(buffer)
buffer
@ -260,8 +264,8 @@ class Project
# text - The {String} text to use as a buffer
#
# Returns a promise that resolves to the {TextBuffer}.
buildBuffer: (absoluteFilePath, initialText) ->
buffer = new TextBuffer({project: this, filePath: absoluteFilePath, initialText})
buildBuffer: (absoluteFilePath) ->
buffer = new TextBuffer({project: this, filePath: absoluteFilePath})
buffer.load().then (buffer) =>
@addBuffer(buffer)
buffer
@ -315,12 +319,18 @@ class Project
deferred.resolve()
task.on 'scan:result-found', (result) =>
iterator(result)
iterator(result) unless @isPathModified(result.filePath)
if _.isFunction(options.onPathsSearched)
task.on 'scan:paths-searched', (numberOfPathsSearched) ->
options.onPathsSearched(numberOfPathsSearched)
for buffer in @buffers when buffer.isModified()
filePath = buffer.getPath()
matches = []
buffer.scan regex, (match) -> matches.push match
iterator {filePath, matches} if matches.length > 0
deferred.promise
# Private:

View File

@ -15,7 +15,6 @@ child_process = require 'child_process'
module.exports =
class Task
Emitter.includeInto(this)
_.extend @prototype, Emitter
# Public: A helper method to easily launch and run a task once.
#

View File

@ -1,3 +1,4 @@
crypto = require 'crypto'
{Emitter, Subscriber} = require 'emissary'
guid = require 'guid'
Q = require 'q'
@ -38,8 +39,8 @@ class TextBuffer
# Creates a new buffer.
#
# path - A {String} representing the file path
# initialText - A {String} setting the starting text
# * optionsOrState - An {Object} or a telepath.Document
# + filePath - A {String} representing the file path
constructor: (optionsOrState={}, params={}) ->
if optionsOrState instanceof telepath.Document
{@project} = params
@ -47,9 +48,9 @@ class TextBuffer
@id = @state.get('id')
filePath = @state.get('relativePath')
@text = @state.get('text')
@loadFromDisk = @state.get('isModified') == false
@useSerializedText = @state.get('isModified') != false
else
{@project, filePath, initialText} = optionsOrState
{@project, filePath} = optionsOrState
@text = site.createDocument(initialText ? '', shareStrings: true)
@id = guid.create().toString()
@state = site.createDocument
@ -57,7 +58,6 @@ class TextBuffer
deserializer: @constructor.name
version: @constructor.version
text: @text
@loadFromDisk = not initialText
@loaded = false
@subscribe @text, 'changed', @handleTextChange
@ -68,14 +68,19 @@ class TextBuffer
loadSync: ->
@updateCachedDiskContentsSync()
@reload() if @loadFromDisk
@text.clearUndoStack()
@finishLoading()
load: ->
@updateCachedDiskContents().then =>
@reload() if @loadFromDisk
@text.clearUndoStack()
this
@updateCachedDiskContents().then => @finishLoading()
finishLoading: ->
@loaded = true
if @useSerializedText and @state.get('diskContentsDigest') == @file?.getDigest()
@emitModifiedStatusChanged(true)
else
@reload()
@text.clearUndoStack()
this
### Internal ###
@ -108,6 +113,7 @@ class TextBuffer
serialize: ->
state = @state.clone()
state.set('isModified', @isModified())
state.set('diskContentsDigest', @file.getDigest()) if @file
for marker in state.get('text').getMarkers() when marker.isRemote()
marker.destroy()
state
@ -158,13 +164,11 @@ class TextBuffer
# Private: Rereads the contents of the file, and stores them in the cache.
updateCachedDiskContentsSync: ->
@loaded = true
@cachedDiskContents = @file?.readSync() ? ""
# Private: Rereads the contents of the file, and stores them in the cache.
updateCachedDiskContents: ->
Q(@file?.read() ? "").then (contents) =>
@loaded = true
@cachedDiskContents = contents
# Gets the file's basename--that is, the file without any directory information.

View File

@ -53,7 +53,7 @@ window.startEditorWindow = ->
atom.packages.loadPackages()
deserializeEditorWindow()
atom.packages.activate()
atom.keymap.loadUserKeymaps()
atom.keymap.loadUserKeymap()
atom.requireUserInitScript()
atom.menu.update()
$(window).on 'unload', ->