Comparar commits

..

19 Commits

Autor SHA1 Mensagem Data
Kevin Sawicki 7ba57df6f7 Mention new fixes and additions 2013-08-12 10:10:22 -07:00
Nathan Sobo 5c2f4d939a Move new additions to philosophy section and tone-down the rhetoric 2013-08-12 10:46:46 -06:00
probablycorey 6c9c7b6d92 Fuzzy filter scores files more than 10 directories deep
All files more than 10 directories deep were accidentally being scored as 0.
2013-08-12 09:43:43 -07:00
Nathan Sobo 210dd61d2a Start adding some serious philosophy to the contribution guidelines 2013-08-12 00:18:58 -06:00
Kevin Sawicki aa302cb935 Add -syntax suffix to converted themes 2013-08-11 13:51:07 -07:00
Kevin Sawicki 994e856ccd Tweak error message when theme file is not found 2013-08-11 13:44:33 -07:00
Kevin Sawicki 808f7e6ed3 Add grunt task to convert TextMate themes to Atom themes 2013-08-11 13:42:34 -07:00
Kevin Sawicki 22f7bc8f26 Upgrade to terminal 0.3.0 2013-08-09 17:34:31 -07:00
Kevin Sawicki ab0b2cf12e Bundle atom/terminal package by default 2013-08-09 17:24:11 -07:00
Kevin Sawicki 599a2ad021 Group specs into four sections
1. Core specs located in spec/
2. Internal package specs in src/packages
3. Bundled package specs in node_modules
4. User package specs in ~/.atom/packages
2013-08-09 17:24:07 -07:00
Kevin Sawicki db649798ef Ignore missing symlinks in fsUtils.traverseTreeSync()
These were previously throwing an error from the call to
statSync().

Now statSync() is wrapped in a try block and only performed when
lstatSync() reports a symbolic link.
2013-08-09 17:23:29 -07:00
Jessica Lord & Kevin Sawicki 4f8f8c43a4 Rename event to open-settings from open-config 2013-08-09 13:38:01 -07:00
Jessica Lord & Kevin Sawicki 4491a9302b Forward config menu click event to focused window
Previously the Atom > Preferences... menu just logged an error message.

Now it fires a window:open-config event to the focused window.
2013-08-09 13:29:12 -07:00
Jessica Lord & Kevin Sawicki ce138b56c0 add jlord to pairs file 2013-08-09 13:28:25 -07:00
Kevin Sawicki 8f8c0cbf45 Mention theme not found fix 2013-08-09 11:26:37 -07:00
Kevin Sawicki 7e04d85e1e Log a warning when a theme fails to load
Previously Atom would fail to launch if a theme referenced in
the config was not found.
2013-08-09 11:25:07 -07:00
Kevin Sawicki 136836e615 Allow non-existent files to be opened from fuzzy finder
The previous isFileSync check prevented unsaved buffers with a path to a
non-existent file from being opened from the fuzzy finder.

Now an error is only displayed if the selected path is a directory.

Closes #686
2013-08-09 10:31:40 -07:00
Matt Colyer 82882624ce Handle atom standard output from atom.sh 2013-08-09 10:23:05 -07:00
Kevin Sawicki c03e849089 Add missing dot in usage ellipsis 2013-08-09 10:10:39 -07:00
19 arquivos alterados com 273 adições e 45 exclusões
+1
Ver Arquivo
@@ -9,6 +9,7 @@ pairs:
gt: Garen Torikian; garen
mc: Matt Colyer; mcolyer
jr: Jason Rudolph; jasonrudolph
jl: Jessica Lord; jlord
email:
domain: github.com
#global: true
+6
Ver Arquivo
@@ -1,3 +1,9 @@
* 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
+33
Ver Arquivo
@@ -1,5 +1,6 @@
# :rotating_light: Contributing to Atom :rotating_light:
## Issues
* Include screenshots and animated GIFs whenever possible, they are immensely
helpful
@@ -26,3 +27,35 @@
* Class methods (methods starting with a `@`)
* Instance variables
* Instance methods
## Philosophy
### Write Beautiful Code
Once you get something working, take the time to consider whether you can achieve it in a more elegant way. We're planning on open-sourcing Atom, so let's put our best foot forward.
### When in doubt, pair-up
Pairing can be an effective and fun way to pass on culture, knowledge, and taste. If you can find the time, we encourage you to work synchronously with other community members of all experience levels to help the knowledge-mulching process. It doesn't have to be all the time; a little pairing goes a long way.
### Write tests, and write them first
The test suite keeps protects our codebase from the ravages of entropy, but it only works when we have thorough coverage. Before you write implementation code, write a failing test proving that it's needed.
### Leave the test suite better than you found it
Consider how the specs you are adding fit into the spec-file as a whole. Is this the right place for your spec? Does the spec need to be reorganized now that you're adding this extra dimension? Specs are only as useful as the next person's ability to understand them.
### Solve today's problem
Avoid adding flexibility that isn't needed *today*. Nothing is ever set in stone, and we can always go back and add flexibility later. Adding it early just means we have to pay for complexity that we might not end up using.
### Favor clarity over brevity or cleverness.
Three lines that someone else can read are better than one line that's tricky.
### Don't be defensive
Only catch exceptions that are truly exceptional. Assume that components we control will honor their contracts. If they don't, the solution is to find and fix the problem in code rather than cluttering the code with attempts to foresee all potential issues at runtime.
### Don't be afraid to add classes and methods
Code rarely suffers from too many methods and classes, and often suffers from too few. Err on the side of numerous short, well-named methods. Pull out classes with well-defined roles.
### Rip shit out
Don't be afraid to delete code. Don't be afraid to rewrite something that needs to be refreshed. If it's in version control, we can always resurrect it.
### Maintain a consistent level of abstraction
Every line in a method should read at the same basic level of abstraction. If there's a section of a method that goes into a lot more detail than the rest of the method, consider extracting a new method and giving it a clear name.
+27 -11
Ver Arquivo
@@ -1,5 +1,6 @@
#!/bin/sh
ATOM_PATH=/Applications/Atom.app
ATOM_BINARY=$ATOM_PATH/Contents/MacOS/Atom
if [ ! -d $ATOM_PATH ]; then sleep 5; fi # Wait for Atom to reappear, Sparkle may be replacing it.
@@ -8,7 +9,32 @@ if [ ! -d $ATOM_PATH ]; then
exit 1
fi
open -a $ATOM_PATH -n --args --executed-from="$(pwd)" --pid=$$ $@
while getopts ":whv-:" opt; do
case "$opt" in
-)
case "${OPTARG}" in
wait)
WAIT=1
;;
help|version)
EXPECT_OUTPUT=1
;;
esac
;;
w)
WAIT=1
;;
h|v)
EXPECT_OUTPUT=1
;;
esac
done
if [ $EXPECT_OUTPUT ]; then
$ATOM_BINARY --executed-from="$(pwd)" --pid=$$ $@
else
open -a $ATOM_PATH -n --args --executed-from="$(pwd)" --pid=$$ $@
fi
# Used to exit process when atom is used as $EDITOR
on_die() {
@@ -16,16 +42,6 @@ on_die() {
}
trap 'on_die' SIGQUIT SIGTERM
# Don't exit process if we were told to wait.
while [ "$#" -gt "0" ]; do
case $1 in
-W|--wait)
WAIT=1
;;
esac
shift
done
if [ $WAIT ]; then
while true; do
sleep 1
+3 -1
Ver Arquivo
@@ -35,7 +35,9 @@
"semver": "1.1.4",
"guid": "0.0.10",
"tantamount": "0.3.0",
"nslog": "0.1.0",
"coffeestack": "0.4.0",
"first-mate": "0.1.0",
"c-tmbundle": "1.0.0",
"coffee-script-tmbundle": "4.0.0",
"css-tmbundle": "1.0.0",
@@ -67,7 +69,7 @@
"todo-tmbundle": "1.0.0",
"xml-tmbundle": "1.0.0",
"yaml-tmbundle": "1.0.0",
"nslog": "0.1.0"
"terminal": "0.3.0"
},
"devDependencies": {
"biscotto": "0.0.12",
+7
Ver Arquivo
@@ -23,3 +23,10 @@ describe "ThemeManager", ->
config.set('core.themes', [])
expect($('style.userTheme').length).toBe 0
describe "when a theme fails to load", ->
it "logs a warning", ->
themeManager = new ThemeManager()
spyOn(console, 'warn')
themeManager.loadTheme('a-theme-that-will-not-be-found')
expect(console.warn).toHaveBeenCalled()
+44 -13
Ver Arquivo
@@ -21,10 +21,18 @@ class AtomReporter extends View
@div id: 'HTMLReporter', class: 'jasmine_reporter', =>
@div outlet: 'specPopup', class: "spec-popup"
@div outlet: "suites"
@div outlet: 'coreHeader', class: 'symbolHeader'
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'packagesHeader', class: 'symbolHeader'
@ul outlet: 'packagesSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'coreArea', =>
@div outlet: 'coreHeader', class: 'symbolHeader'
@ul outlet: 'coreSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'internalArea', =>
@div outlet: 'internalHeader', class: 'symbolHeader'
@ul outlet: 'internalSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'bundledArea', =>
@div outlet: 'bundledHeader', class: 'symbolHeader'
@ul outlet: 'bundledSummary', class: 'symbolSummary list-unstyled'
@div outlet: 'userArea', =>
@div outlet: 'userHeader', class: 'symbolHeader'
@ul outlet: 'userSummary', class: 'symbolSummary list-unstyled'
@div outlet: "status", class: 'status', =>
@div outlet: "time", class: 'time'
@div outlet: "specCount", class: 'spec-count'
@@ -122,18 +130,41 @@ class AtomReporter extends View
addSpecs: (specs) ->
coreSpecs = 0
packageSpecs = 0
internalPackageSpecs = 0
bundledPackageSpecs = 0
userPackageSpecs = 0
for spec in specs
symbol = $$ -> @li class: "spec-summary pending spec-summary-#{spec.id}"
if spec.coreSpec
coreSpecs++
@coreSummary.append symbol
else
packageSpecs++
@packagesSummary.append symbol
switch spec.specType
when 'core'
coreSpecs++
@coreSummary.append symbol
when 'internal'
internalPackageSpecs++
@internalSummary.append symbol
when 'bundled'
bundledPackageSpecs++
@bundledSummary.append symbol
when 'user'
userPackageSpecs++
@userSummary.append symbol
@coreHeader.text("Core Specs (#{coreSpecs}):")
@packagesHeader.text("Package Specs (#{packageSpecs}):")
if coreSpecs > 0
@coreHeader.text("Core Specs (#{coreSpecs}):")
else
@coreArea.hide()
if internalPackageSpecs > 0
@internalHeader.text("Internal Package Specs (#{internalPackageSpecs}):")
else
@internalArea.hide()
if bundledPackageSpecs > 0
@bundledHeader.text("Bundled Package Specs (#{bundledPackageSpecs}):")
else
@bundledArea.hide()
if userPackageSpecs > 0
@userHeader.text("User Package Specs (#{userPackageSpecs}):")
else
@userArea.hide()
specStarted: (spec) ->
@runningSpecCount++
+17 -8
Ver Arquivo
@@ -5,14 +5,23 @@ measure 'spec suite require time', ->
path = require 'path'
require 'spec-helper'
requireSpecs = (directoryPath, specType) ->
for specPath in fsUtils.listTreeSync(path.join(directoryPath, 'spec')) when /-spec\.coffee$/.test specPath
require specPath
for spec in jasmine.getEnv().currentRunner().specs() when not spec.specType?
spec.specType = specType
# Run core specs
for specPath in fsUtils.listTreeSync(fsUtils.resolveOnLoadPath("spec")) when /-spec\.coffee$/.test specPath
require specPath
requireSpecs(window.resourcePath, 'core')
spec.coreSpec = true for spec in jasmine.getEnv().currentRunner().specs()
# Run internal package specs
for packagePath in fsUtils.listTreeSync(config.bundledPackagesDirPath)
requireSpecs(packagePath, 'internal')
# Run extension specs
for packageDirPath in config.packageDirPaths
for packagePath in fsUtils.listSync(packageDirPath)
for specPath in fsUtils.listTreeSync(path.join(packagePath, "spec")) when /-spec\.coffee$/.test specPath
require specPath
# Run bundled package specs
for packagePath in fsUtils.listTreeSync(config.nodeModulesDirPath) when atom.isInternalPackage(packagePath)
requireSpecs(packagePath, 'bundled')
# Run user package specs
for packagePath in fsUtils.listTreeSync(config.userPackagesDirPath)
requireSpecs(packagePath, 'user')
+9
Ver Arquivo
@@ -1,6 +1,7 @@
fsUtils = require 'fs-utils'
fs = require 'fs'
path = require 'path'
temp = require 'temp'
describe "fsUtils", ->
describe ".read(path)", ->
@@ -82,6 +83,14 @@ describe "fsUtils", ->
expect(symlinkPaths).toEqual(paths)
it "ignores missing symlinks", ->
directory = temp.mkdirSync('symlink-in-here')
paths = []
onPath = (childPath) -> paths.push(childPath)
fs.symlinkSync(path.join(directory, 'source'), path.join(directory, 'destination'))
fsUtils.traverseTreeSync(directory, onPath)
expect(paths.length).toBe 0
describe ".md5ForPath(path)", ->
it "returns the MD5 hash of the file at the given path", ->
expect(fsUtils.md5ForPath(require.resolve('fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b'
+2
Ver Arquivo
@@ -24,6 +24,8 @@ class Config
configDirPath: configDirPath
themeDirPaths: [userThemesDirPath, bundledThemesDirPath]
bundledPackageDirPaths: [bundledPackagesDirPath, nodeModulesDirPath]
bundledPackagesDirPath: bundledPackagesDirPath
nodeModulesDirPath: nodeModulesDirPath
packageDirPaths: [userPackagesDirPath, bundledPackagesDirPath]
userPackagesDirPath: userPackagesDirPath
userStoragePath: userStoragePath
+5 -1
Ver Arquivo
@@ -27,7 +27,11 @@ class ThemeManager
@loadTheme(themeName) for themeName in themeNames
@loadUserStylesheet()
loadTheme: (name) -> @loadedThemes.push(new Theme(name))
loadTheme: (name) ->
try
@loadedThemes.push(new Theme(name))
catch error
console.warn("Failed to load theme #{name}", error.stack ? error)
getUserStylesheetPath: ->
stylesheetPath = fsUtils.resolve(path.join(config.configDirPath, 'user'), ['css', 'less'])
+1 -1
Ver Arquivo
@@ -96,7 +96,7 @@ class AtomApplication
submenu: [
{ label: 'About Atom', selector: 'orderFrontStandardAboutPanel:' }
{ type: 'separator' }
{ label: 'Preferences...', accelerator: 'Command+,', click: => console.error("preferences not setup yet") }
{ label: 'Preferences...', accelerator: 'Command+,', click: => @sendCommand('window:open-settings') }
{ type: 'separator' }
{ label: 'Hide Atom', accelerator: 'Command+H', selector: 'hide:' }
{ label: 'Hide Others', accelerator: 'Command+Shift+H', selector: 'hideOtherApplications:' }
+1 -1
Ver Arquivo
@@ -59,7 +59,7 @@ parseCommandLine = ->
options.usage """
Atom #{version}
Usage: atom [options] [file ..]
Usage: atom [options] [file ...]
"""
options.alias('d', 'dev').boolean('d').describe('d', 'Run in development mode.')
options.alias('h', 'help').boolean('h').describe('h', 'Print this usage message.')
@@ -98,13 +98,13 @@ class FuzzyFinderView extends SelectList
confirmed : ({filePath}) ->
return unless filePath
if fsUtils.isFileSync(filePath)
if fsUtils.isDirectorySync(filePath)
@setError('Selected path is a directory')
setTimeout((=> @setError()), 2000)
else
lineNumber = @getLineNumber()
@cancel()
@openPath(filePath, lineNumber)
else
@setError('Selected path does not exist')
setTimeout((=> @setError()), 2000)
toggleFileFinder: ->
@finderMode = 'file'
@@ -109,12 +109,12 @@ describe 'FuzzyFinder', ->
expect(editor2.getPath()).toBe expectedPath
expect(editor2.isFocused).toBeTruthy()
describe "when the selected path isn't a file that exists", ->
describe "when the selected path is a directory", ->
it "leaves the the tree view open, doesn't open the path in the editor, and displays an error", ->
rootView.attachToDom()
editorPath = rootView.getActiveView().getPath()
rootView.trigger 'fuzzy-finder:toggle-file-finder'
finderView.confirmed({filePath: 'dir/this/is/not/a/file.txt'})
finderView.confirmed({filePath: project.resolve('dir')})
expect(finderView.hasParent()).toBeTruthy()
expect(rootView.getActiveView().getPath()).toBe editorPath
expect(finderView.error.text().length).toBeGreaterThan 0
@@ -25,6 +25,9 @@ class SettingsView extends ScrollView
rootView.command 'settings-view:toggle', ->
rootView.open(configUri)
$(window).on 'window:open-settings', ->
rootView.open(configUri)
@deserialize: ({activePanelName}={}) ->
new SettingsView(activePanelName)
+5 -2
Ver Arquivo
@@ -147,13 +147,16 @@ module.exports =
makeTree: (directoryPath) ->
mkdirp.sync(directoryPath) if directoryPath and not @exists(directoryPath)
traverseTreeSync: (rootPath, onFile, onDirectory) ->
traverseTreeSync: (rootPath, onFile, onDirectory=onFile) ->
return unless @isDirectorySync(rootPath)
traverse = (directoryPath, onFile, onDirectory) ->
for file in fs.readdirSync(directoryPath)
childPath = path.join(directoryPath, file)
stats = fs.statSync(childPath)
stats = fs.lstatSync(childPath)
if stats.isSymbolicLink()
try
stats = fs.statSync(childPath)
if stats.isDirectory()
traverse(childPath, onFile, onDirectory) if onDirectory(childPath)
else if stats.isFile()
+1 -1
Ver Arquivo
@@ -12,7 +12,7 @@ module.exports = (candidates, query, options={}) ->
score += stringScore(path.basename(string), query)
# Shallow files are scored higher
depth = Math.min(1, 10 - string.split('/').length - 1)
depth = Math.max(1, 10 - string.split('/').length - 1)
score *= depth * 0.01
{ candidate, score }
+102
Ver Arquivo
@@ -0,0 +1,102 @@
path = require 'path'
_ = require 'underscore'
plist = require 'plist'
{ScopeSelector} = require 'first-mate'
module.exports = (grunt) ->
grunt.registerTask 'convert-theme', 'Convert a TextMate theme to an Atom theme', ->
if textMateThemePath = grunt.option('path')
textMateThemePath = path.resolve(textMateThemePath)
if grunt.file.isFile(textMateThemePath)
textMateTheme = new TextMateTheme(textMateThemePath)
themeName = path.basename(textMateThemePath, path.extname(textMateThemePath))
atomThemePath = path.join(path.dirname(textMateThemePath), "#{themeName.toLowerCase()}-syntax.css")
grunt.file.write(atomThemePath, textMateTheme.getStylesheet())
grunt.log.ok("Atom theme written to: #{atomThemePath}")
else
grunt.log.error("No theme file found at: #{textMateThemePath}")
false
else
grunt.log.error('Must specify --path=<path to TextMate theme>')
false
class TextMateTheme
constructor: (@path) ->
@rulesets = []
@buildRulesets()
buildRulesets: ->
{settings} = plist.parseFileSync(@path)
@buildGlobalSettingsRulesets(settings[0])
@buildScopeSelectorRulesets(settings[1..])
getStylesheet: ->
lines = []
for {selector, properties} in @getRulesets()
lines.push("#{selector} {")
lines.push " #{name}: #{value};" for name, value of properties
lines.push("}\n")
lines.join('\n')
getRulesets: -> @rulesets
buildGlobalSettingsRulesets: ({settings}) ->
{ background, foreground, caret, selection, lineHighlight } = settings
@rulesets.push
selector: '.editor, .editor .gutter'
properties:
'background-color': @translateColor(background)
'color': @translateColor(foreground)
@rulesets.push
selector: '.editor.is-focused .cursor'
properties:
'border-color': @translateColor(caret)
@rulesets.push
selector: '.editor.is-focused .selection .region'
properties:
'background-color': @translateColor(selection)
@rulesets.push
selector: '.editor.is-focused .line-number.cursor-line-no-selection, .editor.is-focused .line.cursor-line'
properties:
'background-color': @translateColor(lineHighlight)
buildScopeSelectorRulesets: (scopeSelectorSettings) ->
for { name, scope, settings } in scopeSelectorSettings
continue unless scope
@rulesets.push
comment: name
selector: @translateScopeSelector(scope)
properties: @translateScopeSelectorSettings(settings)
translateScopeSelector: (textmateScopeSelector) ->
new ScopeSelector(textmateScopeSelector).toCssSelector()
translateScopeSelectorSettings: ({ foreground, background, fontStyle }) ->
properties = {}
if fontStyle
fontStyles = fontStyle.split(/\s+/)
properties['font-weight'] = 'bold' if _.contains(fontStyles, 'bold')
properties['font-style'] = 'italic' if _.contains(fontStyles, 'italic')
properties['text-decoration'] = 'underline' if _.contains(fontStyles, 'underline')
properties['color'] = @translateColor(foreground) if foreground
properties['background-color'] = @translateColor(background) if background
properties
translateColor: (textmateColor) ->
if textmateColor.length <= 7
textmateColor
else
r = parseInt(textmateColor[1..2], 16)
g = parseInt(textmateColor[3..4], 16)
b = parseInt(textmateColor[5..6], 16)
a = parseInt(textmateColor[7..8], 16)
a = Math.round((a / 255.0) * 100) / 100
"rgba(#{r}, #{g}, #{b}, #{a})"