diff --git a/.github b/.github index fc652aa74..f9562bce3 100644 --- a/.github +++ b/.github @@ -1,2 +1,2 @@ [docs] - title = The Guide to Atom +title = The Guide to Atom diff --git a/Rakefile b/Rakefile index f4fa7f69e..76c5a0c31 100644 --- a/Rakefile +++ b/Rakefile @@ -90,7 +90,7 @@ task :clean do end desc "Run the specs" -task :test => ["clean", "update-cef", "clone-default-bundles", "build"] do +task :test => ["update-cef", "clone-default-bundles", "build"] do `pkill Atom` if path = application_path() cmd = "#{path}/Contents/MacOS/Atom --test --resource-path=#{ATOM_SRC_PATH}" diff --git a/atom.gyp b/atom.gyp index e3ceb2326..ea825f03c 100644 --- a/atom.gyp +++ b/atom.gyp @@ -1,6 +1,5 @@ { 'variables': { - 'version': '2.0. #import +#import @implementation AtomApplication @@ -207,6 +208,11 @@ } - (void)applicationDidFinishLaunching:(NSNotification *)notification { + BWQuincyManager *manager = [BWQuincyManager sharedQuincyManager]; + [manager setCompanyName:@"GitHub"]; + [manager setSubmissionURL:@"https://speakeasy.githubapp.com/submit_crash_log"]; + [manager setAutoSubmitCrashReport:YES]; + if (!_filesOpened && [self shouldOpenFiles]) { NSString *path = [self.arguments objectForKey:@"path"]; NSNumber *pid = [self.arguments objectForKey:@"wait"] ? [self.arguments objectForKey:@"pid"] : nil; diff --git a/native/atom_cef_client.cpp b/native/atom_cef_client.cpp index 4427a8901..6ddf00ce1 100644 --- a/native/atom_cef_client.cpp +++ b/native/atom_cef_client.cpp @@ -87,6 +87,9 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr browser, else if (name == "getVersion") { GetVersion(messageId, browser); } + else if (name == "crash") { + __builtin_trap(); + } else { return false; } diff --git a/native/frameworks/Quincy.framework/Headers b/native/frameworks/Quincy.framework/Headers new file mode 120000 index 000000000..a177d2a6b --- /dev/null +++ b/native/frameworks/Quincy.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/native/frameworks/Quincy.framework/Quincy b/native/frameworks/Quincy.framework/Quincy new file mode 120000 index 000000000..9bbfc5b61 --- /dev/null +++ b/native/frameworks/Quincy.framework/Quincy @@ -0,0 +1 @@ +Versions/Current/Quincy \ No newline at end of file diff --git a/native/frameworks/Quincy.framework/Resources b/native/frameworks/Quincy.framework/Resources new file mode 120000 index 000000000..953ee36f3 --- /dev/null +++ b/native/frameworks/Quincy.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/native/frameworks/Quincy.framework/Versions/A/Headers/BWQuincyManager.h b/native/frameworks/Quincy.framework/Versions/A/Headers/BWQuincyManager.h new file mode 100644 index 000000000..bb6d91c01 --- /dev/null +++ b/native/frameworks/Quincy.framework/Versions/A/Headers/BWQuincyManager.h @@ -0,0 +1,169 @@ +/* + * Author: Andreas Linde + * Kent Sutherland + * + * Copyright (c) 2011 Andreas Linde & Kent Sutherland. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + +typedef enum CrashAlertType { + CrashAlertTypeSend = 0, + CrashAlertTypeFeedback = 1, +} CrashAlertType; + +typedef enum CrashReportStatus { + // This app version is set to discontinued, no new crash reports accepted by the server + CrashReportStatusFailureVersionDiscontinued = -30, + + // XML: Sender ersion string contains not allowed characters, only alphanumberical including space and . are allowed + CrashReportStatusFailureXMLSenderVersionNotAllowed = -21, + + // XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed + CrashReportStatusFailureXMLVersionNotAllowed = -20, + + // SQL for adding a symoblicate todo entry in the database failed + CrashReportStatusFailureSQLAddSymbolicateTodo = -18, + + // SQL for adding crash log in the database failed + CrashReportStatusFailureSQLAddCrashlog = -17, + + // SQL for adding a new version in the database failed + CrashReportStatusFailureSQLAddVersion = -16, + + // SQL for checking if the version is already added in the database failed + CrashReportStatusFailureSQLCheckVersionExists = -15, + + // SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed + CrashReportStatusFailureSQLAddPattern = -14, + + // SQL for checking the status of the bugfix version in the database failed + CrashReportStatusFailureSQLCheckBugfixStatus = -13, + + // SQL for updating the occurances of this pattern in the database failed + CrashReportStatusFailureSQLUpdatePatternOccurances = -12, + + // SQL for getting all the known bug patterns for the current app version in the database failed + CrashReportStatusFailureSQLFindKnownPatterns = -11, + + // SQL for finding the bundle identifier in the database failed + CrashReportStatusFailureSQLSearchAppName = -10, + + // the post request didn't contain valid data + CrashReportStatusFailureInvalidPostData = -3, + + // incoming data may not be added, because e.g. bundle identifier wasn't found + CrashReportStatusFailureInvalidIncomingData = -2, + + // database cannot be accessed, check hostname, username, password and database name settings in config.php + CrashReportStatusFailureDatabaseNotAvailable = -1, + + CrashReportStatusUnknown = 0, + + CrashReportStatusAssigned = 1, + + CrashReportStatusSubmitted = 2, + + CrashReportStatusAvailable = 3, +} CrashReportStatus; + + +@class BWQuincyUI; + +@protocol BWQuincyManagerDelegate + +@required + +// Invoked once the modal sheets are gone +- (void) showMainApplicationWindow; + +@optional + +// Return the description the crashreport should contain, empty by default. The string will automatically be wrapped into <[DATA[ ]]>, so make sure you don't do that in your string. +-(NSString *) crashReportDescription; + +// Return the userid the crashreport should contain, empty by default +-(NSString *) crashReportUserID; + +// Return the contact value (e.g. email) the crashreport should contain, empty by default +-(NSString *) crashReportContact; +@end + + +@interface BWQuincyManager : NSObject +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) + +#endif +{ + CrashReportStatus _serverResult; + NSInteger _statusCode; + + NSMutableString *_contentOfProperty; + + id _delegate; + + NSString *_submissionURL; + NSString *_companyName; + NSString *_appIdentifier; + BOOL _autoSubmitCrashReport; + + NSString *_crashFile; + + BWQuincyUI *_quincyUI; +} + +- (NSString*) modelVersion; + ++ (BWQuincyManager *)sharedQuincyManager; + +// submission URL defines where to send the crash reports to (required) +@property (nonatomic, retain) NSString *submissionURL; + +// defines the company name to be shown in the crash reporting dialog +@property (nonatomic, retain) NSString *companyName; + +// delegate is required +@property (nonatomic, assign) id delegate; + +// if YES, the crash report will be submitted without asking the user +// if NO, the user will be asked if the crash report can be submitted (default) +@property (nonatomic, assign, getter=isAutoSubmitCrashReport) BOOL autoSubmitCrashReport; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// settings + +// If you want to use HockeyApp instead of your own server, this is required +@property (nonatomic, retain) NSString *appIdentifier; + + +- (void) cancelReport; +- (void) sendReportCrash:(NSString*)crashContent + description:(NSString*)description; + +- (NSString *) applicationName; +- (NSString *) applicationVersionString; +- (NSString *) applicationVersion; + +@end diff --git a/native/frameworks/Quincy.framework/Versions/A/Quincy b/native/frameworks/Quincy.framework/Versions/A/Quincy new file mode 100755 index 000000000..5d8678492 Binary files /dev/null and b/native/frameworks/Quincy.framework/Versions/A/Quincy differ diff --git a/native/frameworks/Quincy.framework/Versions/A/Resources/BWQuincyMain.nib b/native/frameworks/Quincy.framework/Versions/A/Resources/BWQuincyMain.nib new file mode 100644 index 000000000..c3b6a17e1 Binary files /dev/null and b/native/frameworks/Quincy.framework/Versions/A/Resources/BWQuincyMain.nib differ diff --git a/native/frameworks/Quincy.framework/Versions/A/Resources/Info.plist b/native/frameworks/Quincy.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000..0f173aeb2 --- /dev/null +++ b/native/frameworks/Quincy.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,34 @@ + + + + + BuildMachineOSBuild + 12D78 + CFBundleDevelopmentRegion + English + CFBundleExecutable + Quincy + CFBundleIdentifier + de.buzzworks.Quincy + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + DTCompiler + + DTPlatformBuild + 4H512 + DTPlatformVersion + GM + DTSDKBuild + 12D75 + DTSDKName + macosx10.8 + DTXcode + 0461 + DTXcodeBuild + 4H512 + + diff --git a/native/frameworks/Quincy.framework/Versions/Current b/native/frameworks/Quincy.framework/Versions/Current new file mode 120000 index 000000000..8c7e5a667 --- /dev/null +++ b/native/frameworks/Quincy.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/native/v8_extensions/native.mm b/native/v8_extensions/native.mm index 03c92eda0..b1ff00f3f 100644 --- a/native/v8_extensions/native.mm +++ b/native/v8_extensions/native.mm @@ -24,7 +24,7 @@ namespace v8_extensions { const char* methodNames[] = { "writeToPasteboard", "readFromPasteboard", "quit", "watchPath", "unwatchPath", "getWatchedPaths", "unwatchAllPaths", "moveToTrash", - "reload", "setWindowState", "getWindowState", "beep" + "reload", "setWindowState", "getWindowState", "beep", "crash" }; CefRefPtr nativeObject = CefV8Value::CreateObject(NULL); @@ -166,6 +166,10 @@ namespace v8_extensions { NSBeep(); } + else if (name == "crash") { + __builtin_trap(); + } + return false; } }; diff --git a/package.json b/package.json index c57fb7ab4..1d2e2541e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "coffee-cache": "0.1.0", "pegjs": "0.7.0", "async": "0.2.6", + "nak": "git://github.com/kevinsawicki/nak.git", "spellchecker": "0.2.0", "plist": "git://github.com/nathansobo/node-plist.git", "space-pen": "git://github.com/nathansobo/space-pen.git" diff --git a/script/cibuild b/script/cibuild index b0d8fbb30..01a5298d3 100755 --- a/script/cibuild +++ b/script/cibuild @@ -2,4 +2,4 @@ set -ex rm -rf ~/.atom -CI_BUILD=true rake test +CI_BUILD=true rake clean test diff --git a/spec/app/atom-spec.coffee b/spec/app/atom-spec.coffee index df2ff94d0..82a3d7672 100644 --- a/spec/app/atom-spec.coffee +++ b/spec/app/atom-spec.coffee @@ -1,7 +1,7 @@ $ = require 'jquery' RootView = require 'root-view' {$$} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "the `atom` global", -> beforeEach -> @@ -129,9 +129,9 @@ describe "the `atom` global", -> describe "stylesheet loading", -> describe "when the metadata contains a 'stylesheets' manifest", -> it "loads stylesheets from the stylesheets directory as specified by the manifest", -> - one = fs.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/1.css") - two = fs.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/2.less") - three = fs.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/3.css") + one = fsUtils.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/1.css") + two = fsUtils.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/2.less") + three = fsUtils.resolveOnLoadPath("package-with-stylesheets-manifest/stylesheets/3.css") expect(stylesheetElementForId(one)).not.toExist() expect(stylesheetElementForId(two)).not.toExist() expect(stylesheetElementForId(three)).not.toExist() @@ -145,9 +145,9 @@ describe "the `atom` global", -> describe "when the metadata does not contain a 'stylesheets' manifest", -> it "loads all stylesheets from the stylesheets directory", -> - one = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/1.css") - two = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/2.less") - three = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/3.css") + one = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/1.css") + two = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/2.less") + three = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/3.css") expect(stylesheetElementForId(one)).not.toExist() expect(stylesheetElementForId(two)).not.toExist() expect(stylesheetElementForId(three)).not.toExist() @@ -215,9 +215,9 @@ describe "the `atom` global", -> it "removes the package's stylesheets", -> atom.activatePackage('package-with-stylesheets') atom.deactivatePackage('package-with-stylesheets') - one = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/1.css") - two = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/2.less") - three = fs.resolveOnLoadPath("package-with-stylesheets/stylesheets/3.css") + one = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/1.css") + two = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/2.less") + three = fsUtils.resolveOnLoadPath("package-with-stylesheets/stylesheets/3.css") expect(stylesheetElementForId(one)).not.toExist() expect(stylesheetElementForId(two)).not.toExist() expect(stylesheetElementForId(three)).not.toExist() @@ -249,7 +249,7 @@ describe "the `atom` global", -> versionHandler.callCount > 0 runs -> - expect(versionHandler.argsForCall[0][0]).toMatch /^\d+\.\d+\.\w+$/ + expect(versionHandler.argsForCall[0][0]).toBeDefined() describe "modal native dialogs", -> beforeEach -> diff --git a/spec/app/config-spec.coffee b/spec/app/config-spec.coffee index 2daa360cd..797923af1 100644 --- a/spec/app/config-spec.coffee +++ b/spec/app/config-spec.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "Config", -> describe ".get(keyPath) and .set(keyPath, value)", -> @@ -19,38 +19,38 @@ describe "Config", -> describe ".save()", -> beforeEach -> - spyOn(fs, 'write') + spyOn(fsUtils, 'write') jasmine.unspy config, 'save' describe "when ~/.atom/config.json exists", -> it "writes any non-default properties to ~/.atom/config.json", -> - config.configFilePath = fs.join(config.configDirPath, "config.json") + config.configFilePath = fsUtils.join(config.configDirPath, "config.json") config.set("a.b.c", 1) config.set("a.b.d", 2) config.set("x.y.z", 3) config.setDefaults("a.b", e: 4, f: 5) - fs.write.reset() + fsUtils.write.reset() config.save() - expect(fs.write.argsForCall[0][0]).toBe(fs.join(config.configDirPath, "config.json")) - writtenConfig = JSON.parse(fs.write.argsForCall[0][1]) + expect(fsUtils.write.argsForCall[0][0]).toBe(fsUtils.join(config.configDirPath, "config.json")) + writtenConfig = JSON.parse(fsUtils.write.argsForCall[0][1]) expect(writtenConfig).toEqual config.settings describe "when ~/.atom/config.json doesn't exist", -> it "writes any non-default properties to ~/.atom/config.cson", -> - config.configFilePath = fs.join(config.configDirPath, "config.cson") + config.configFilePath = fsUtils.join(config.configDirPath, "config.cson") config.set("a.b.c", 1) config.set("a.b.d", 2) config.set("x.y.z", 3) config.setDefaults("a.b", e: 4, f: 5) - fs.write.reset() + fsUtils.write.reset() config.save() - expect(fs.write.argsForCall[0][0]).toBe(fs.join(config.configDirPath, "config.cson")) + expect(fsUtils.write.argsForCall[0][0]).toBe(fsUtils.join(config.configDirPath, "config.cson")) CoffeeScript = require 'coffee-script' - writtenConfig = CoffeeScript.eval(fs.write.argsForCall[0][1], bare: true) + writtenConfig = CoffeeScript.eval(fsUtils.write.argsForCall[0][1], bare: true) expect(writtenConfig).toEqual config.settings describe ".setDefaults(keyPath, defaults)", -> @@ -113,40 +113,40 @@ describe "Config", -> describe "initializeConfigDirectory()", -> beforeEach -> config.configDirPath = '/tmp/dot-atom-dir' - expect(fs.exists(config.configDirPath)).toBeFalsy() + expect(fsUtils.exists(config.configDirPath)).toBeFalsy() afterEach -> - fs.remove('/tmp/dot-atom-dir') if fs.exists('/tmp/dot-atom-dir') + fsUtils.remove('/tmp/dot-atom-dir') if fsUtils.exists('/tmp/dot-atom-dir') describe "when the configDirPath doesn't exist", -> it "copies the contents of dot-atom to ~/.atom", -> config.initializeConfigDirectory() - expect(fs.exists(config.configDirPath)).toBeTruthy() - expect(fs.exists(fs.join(config.configDirPath, 'packages'))).toBeTruthy() - expect(fs.exists(fs.join(config.configDirPath, 'snippets'))).toBeTruthy() - expect(fs.exists(fs.join(config.configDirPath, 'themes'))).toBeTruthy() - expect(fs.isFile(fs.join(config.configDirPath, 'config.cson'))).toBeTruthy() + expect(fsUtils.exists(config.configDirPath)).toBeTruthy() + expect(fsUtils.exists(fsUtils.join(config.configDirPath, 'packages'))).toBeTruthy() + expect(fsUtils.exists(fsUtils.join(config.configDirPath, 'snippets'))).toBeTruthy() + expect(fsUtils.exists(fsUtils.join(config.configDirPath, 'themes'))).toBeTruthy() + expect(fsUtils.isFile(fsUtils.join(config.configDirPath, 'config.cson'))).toBeTruthy() it "copies the bundles themes to ~/.atom", -> config.initializeConfigDirectory() - expect(fs.isFile(fs.join(config.configDirPath, 'themes/atom-dark-ui/package.cson'))).toBeTruthy() - expect(fs.isFile(fs.join(config.configDirPath, 'themes/atom-light-ui/package.cson'))).toBeTruthy() - expect(fs.isFile(fs.join(config.configDirPath, 'themes/atom-dark-syntax.css'))).toBeTruthy() - expect(fs.isFile(fs.join(config.configDirPath, 'themes/atom-light-syntax.css'))).toBeTruthy() + expect(fsUtils.isFile(fsUtils.join(config.configDirPath, 'themes/atom-dark-ui/package.cson'))).toBeTruthy() + expect(fsUtils.isFile(fsUtils.join(config.configDirPath, 'themes/atom-light-ui/package.cson'))).toBeTruthy() + expect(fsUtils.isFile(fsUtils.join(config.configDirPath, 'themes/atom-dark-syntax.css'))).toBeTruthy() + expect(fsUtils.isFile(fsUtils.join(config.configDirPath, 'themes/atom-light-syntax.css'))).toBeTruthy() describe "when the config file is not parseable", -> beforeEach -> config.configDirPath = '/tmp/dot-atom-dir' - config.configFilePath = fs.join(config.configDirPath, "config.cson") - expect(fs.exists(config.configDirPath)).toBeFalsy() + config.configFilePath = fsUtils.join(config.configDirPath, "config.cson") + expect(fsUtils.exists(config.configDirPath)).toBeFalsy() afterEach -> - fs.remove('/tmp/dot-atom-dir') if fs.exists('/tmp/dot-atom-dir') + fsUtils.remove('/tmp/dot-atom-dir') if fsUtils.exists('/tmp/dot-atom-dir') it "logs an error to the console and does not overwrite the config file", -> config.save.reset() spyOn(console, 'error') - fs.write(config.configFilePath, "{{{{{") + fsUtils.write(config.configFilePath, "{{{{{") config.loadUserConfig() config.set("hair", "blonde") # trigger a save expect(console.error).toHaveBeenCalled() diff --git a/spec/app/directory-spec.coffee b/spec/app/directory-spec.coffee index 4bbd8ea02..a56eee671 100644 --- a/spec/app/directory-spec.coffee +++ b/spec/app/directory-spec.coffee @@ -1,11 +1,11 @@ Directory = require 'directory' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "Directory", -> directory = null beforeEach -> - directory = new Directory(fs.resolveOnLoadPath('fixtures')) + directory = new Directory(fsUtils.resolveOnLoadPath('fixtures')) afterEach -> directory.off() @@ -14,11 +14,11 @@ describe "Directory", -> temporaryFilePath = null beforeEach -> - temporaryFilePath = fs.join(fs.resolveOnLoadPath('fixtures'), 'temporary') - fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath) + temporaryFilePath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures'), 'temporary') + fsUtils.remove(temporaryFilePath) if fsUtils.exists(temporaryFilePath) afterEach -> - fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath) + fsUtils.remove(temporaryFilePath) if fsUtils.exists(temporaryFilePath) it "triggers 'contents-changed' event handlers", -> changeHandler = null @@ -26,13 +26,13 @@ describe "Directory", -> runs -> changeHandler = jasmine.createSpy('changeHandler') directory.on 'contents-changed', changeHandler - fs.write(temporaryFilePath, '') + fsUtils.write(temporaryFilePath, '') waitsFor "first change", -> changeHandler.callCount > 0 runs -> changeHandler.reset() - fs.remove(temporaryFilePath) + fsUtils.remove(temporaryFilePath) waitsFor "second change", -> changeHandler.callCount > 0 @@ -40,11 +40,11 @@ describe "Directory", -> temporaryFilePath = null beforeEach -> - temporaryFilePath = fs.join(directory.path, 'temporary') - fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath) + temporaryFilePath = fsUtils.join(directory.path, 'temporary') + fsUtils.remove(temporaryFilePath) if fsUtils.exists(temporaryFilePath) afterEach -> - fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath) + fsUtils.remove(temporaryFilePath) if fsUtils.exists(temporaryFilePath) it "no longer triggers events", -> changeHandler = null @@ -52,7 +52,7 @@ describe "Directory", -> runs -> changeHandler = jasmine.createSpy('changeHandler') directory.on 'contents-changed', changeHandler - fs.write(temporaryFilePath, '') + fsUtils.write(temporaryFilePath, '') waitsFor "change event", -> changeHandler.callCount > 0 @@ -61,7 +61,7 @@ describe "Directory", -> directory.off() waits 20 - runs -> fs.remove(temporaryFilePath) + runs -> fsUtils.remove(temporaryFilePath) waits 20 runs -> expect(changeHandler.callCount).toBe 0 diff --git a/spec/app/edit-session-spec.coffee b/spec/app/edit-session-spec.coffee index 3337d526b..06a0a047c 100644 --- a/spec/app/edit-session-spec.coffee +++ b/spec/app/edit-session-spec.coffee @@ -2060,18 +2060,18 @@ describe "EditSession", -> editSession.buffer.reload() expect(editSession.getCursorScreenPosition()).toEqual [0,1] - describe "when the 'grammars-loaded' event is triggered on the syntax global", -> - it "reloads the edit session's grammar and re-tokenizes the buffer if it changes", -> + describe "when a better-matched grammar is added to syntax", -> + it "switches to the better-matched grammar and re-tokenizes the buffer", -> editSession.destroy() jsGrammar = syntax.selectGrammar('a.js') - grammarToReturn = syntax.nullGrammar - spyOn(syntax, 'selectGrammar').andCallFake -> grammarToReturn + syntax.removeGrammar(jsGrammar) editSession = project.buildEditSession('sample.js', autoIndent: false) + expect(editSession.getGrammar()).toBe syntax.nullGrammar expect(editSession.lineForScreenRow(0).tokens.length).toBe 1 - grammarToReturn = jsGrammar - syntax.trigger 'grammars-loaded' + syntax.addGrammar(jsGrammar) + expect(editSession.getGrammar()).toBe jsGrammar expect(editSession.lineForScreenRow(0).tokens.length).toBeGreaterThan 1 describe "auto-indent", -> diff --git a/spec/app/editor-spec.coffee b/spec/app/editor-spec.coffee index bbfa1ba99..f5c7612c4 100644 --- a/spec/app/editor-spec.coffee +++ b/spec/app/editor-spec.coffee @@ -6,7 +6,7 @@ Project = require 'project' $ = require 'jquery' {$$} = require 'space-pen' _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "Editor", -> [buffer, editor, editSession, cachedLineHeight, cachedCharWidth] = [] @@ -83,7 +83,7 @@ describe "Editor", -> describe "when the activeEditSession's file is modified on disk", -> it "triggers an alert", -> path = "/tmp/atom-changed-file.txt" - fs.write(path, "") + fsUtils.write(path, "") editSession = project.buildEditSession(path) editor.edit(editSession) editor.insertText("now the buffer is modified") @@ -93,7 +93,7 @@ describe "Editor", -> spyOn(atom, "confirm") - fs.write(path, "a file change") + fsUtils.write(path, "a file change") waitsFor "file to trigger contents-changed event", -> fileChangeHandler.callCount > 0 @@ -147,7 +147,7 @@ describe "Editor", -> it "triggers alert if edit session's buffer goes into conflict with changes on disk", -> path = "/tmp/atom-changed-file.txt" - fs.write(path, "") + fsUtils.write(path, "") tempEditSession = project.buildEditSession(path) editor.edit(tempEditSession) tempEditSession.insertText("a buffer change") @@ -156,7 +156,7 @@ describe "Editor", -> contentsConflictedHandler = jasmine.createSpy("contentsConflictedHandler") tempEditSession.on 'contents-conflicted', contentsConflictedHandler - fs.write(path, "a file change") + fsUtils.write(path, "a file change") waitsFor -> contentsConflictedHandler.callCount > 0 @@ -228,10 +228,10 @@ describe "Editor", -> path = null beforeEach -> path = "/tmp/something.txt" - fs.write(path, path) + fsUtils.write(path, path) afterEach -> - fs.remove(path) if fs.exists(path) + fsUtils.remove(path) if fsUtils.exists(path) it "emits event when buffer's path is changed", -> eventHandler = jasmine.createSpy('eventHandler') @@ -390,7 +390,7 @@ describe "Editor", -> editor.clearFontFamily() it "positions the cursor to the clicked row and column", -> - {top, left} = editor.pixelOffsetForScreenPosition([3, 30]) + {top, left} = editor.pixelOffsUtilsetForScreenPosition([3, 30]) editor.renderedLines.trigger mousedownEvent(pageX: left, pageY: top) expect(editor.getCursorScreenPosition()).toEqual [3, 30] @@ -786,7 +786,7 @@ describe "Editor", -> setEditorHeightInLines(editor, 4) describe "if autoscroll is true", -> - it "centers the viewport on the selection if its vertical center is currently offscreen", -> + it "centers the viewport on the selection if its vertical center is currently offsUtilscreen", -> editor.setSelectedBufferRange([[2, 0], [4, 0]], autoscroll: true) expect(editor.scrollTop()).toBe 0 @@ -1197,7 +1197,7 @@ describe "Editor", -> expect(editor.renderedLines.find('.line:last').text()).toBe buffer.lineForRow(7) describe "when scrolling more than the editors height", -> - it "removes lines that are offscreen and not in range of the overdraw and builds lines that become visible", -> + it "removes lines that are offsUtilscreen and not in range of the overdraw and builds lines that become visible", -> editor.scrollTop(editor.scrollView.prop('scrollHeight') - editor.scrollView.height()) expect(editor.renderedLines.find('.line').length).toBe 8 expect(editor.renderedLines.find('.line:first').text()).toBe buffer.lineForRow(5) @@ -2003,11 +2003,11 @@ describe "Editor", -> beforeEach -> path = project.resolve('git/working-dir/file.txt') - originalPathText = fs.read(path) + originalPathText = fsUtils.read(path) editor.edit(project.buildEditSession(path)) afterEach -> - fs.write(path, originalPathText) + fsUtils.write(path, originalPathText) it "restores the contents of the editor to the HEAD revision", -> editor.setText('') @@ -2103,17 +2103,17 @@ describe "Editor", -> [path] = [] beforeEach -> - path = fs.join(fs.absolute("/tmp"), "grammar-change.txt") - fs.write(path, "var i;") + path = fsUtils.join(fsUtils.absolute("/tmp"), "grammar-change.txt") + fsUtils.write(path, "var i;") afterEach -> - fs.remove(path) if fs.exists(path) + fsUtils.remove(path) if fsUtils.exists(path) it "updates all the rendered lines when the grammar changes", -> editor.edit(project.buildEditSession(path)) expect(editor.getGrammar().name).toBe 'Plain Text' syntax.setGrammarOverrideForPath(path, 'source.js') - expect(editor.reloadGrammar()).toBeTruthy() + editor.reloadGrammar() expect(editor.getGrammar().name).toBe 'JavaScript' tokenizedBuffer = editor.activeEditSession.displayBuffer.tokenizedBuffer @@ -2451,12 +2451,12 @@ describe "Editor", -> it "saves the state of the rendered lines, the display buffer, and the buffer to a file of the user's choosing", -> saveDialogCallback = null spyOn(atom, 'showSaveDialog').andCallFake (callback) -> saveDialogCallback = callback - spyOn(fs, 'write') + spyOn(fsUtils, 'write') editor.trigger 'editor:save-debug-snapshot' expect(atom.showSaveDialog).toHaveBeenCalled() saveDialogCallback('/tmp/state') - expect(fs.write).toHaveBeenCalled() - expect(fs.write.argsForCall[0][0]).toBe '/tmp/state' - expect(typeof fs.write.argsForCall[0][1]).toBe 'string' + expect(fsUtils.write).toHaveBeenCalled() + expect(fsUtils.write.argsForCall[0][0]).toBe '/tmp/state' + expect(typeof fsUtils.write.argsForCall[0][1]).toBe 'string' diff --git a/spec/app/file-spec.coffee b/spec/app/file-spec.coffee index 21f57833f..9cbd613c0 100644 --- a/spec/app/file-spec.coffee +++ b/spec/app/file-spec.coffee @@ -1,33 +1,33 @@ File = require 'file' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe 'File', -> [path, file] = [] beforeEach -> - path = fs.join(fs.resolveOnLoadPath('fixtures'), "atom-file-test.txt") # Don't put in /tmp because /tmp symlinks to /private/tmp and screws up the rename test - fs.remove(path) if fs.exists(path) - fs.write(path, "this is old!") + path = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures'), "atom-file-test.txt") # Don't put in /tmp because /tmp symlinks to /private/tmp and screws up the rename test + fsUtils.remove(path) if fsUtils.exists(path) + fsUtils.write(path, "this is old!") file = new File(path) file.read() afterEach -> file.off() - fs.remove(path) if fs.exists(path) + fsUtils.remove(path) if fsUtils.exists(path) describe "when the contents of the file change", -> it "triggers 'contents-changed' event handlers", -> changeHandler = null changeHandler = jasmine.createSpy('changeHandler') file.on 'contents-changed', changeHandler - fs.write(file.getPath(), "this is new!") + fsUtils.write(file.getPath(), "this is new!") waitsFor "change event", -> changeHandler.callCount > 0 runs -> changeHandler.reset() - fs.write(file.getPath(), "this is newer!") + fsUtils.write(file.getPath(), "this is newer!") waitsFor "second change event", -> changeHandler.callCount > 0 @@ -37,7 +37,7 @@ describe 'File', -> removeHandler = null removeHandler = jasmine.createSpy('removeHandler') file.on 'removed', removeHandler - fs.remove(file.getPath()) + fsUtils.remove(file.getPath()) waitsFor "remove event", -> removeHandler.callCount > 0 @@ -46,11 +46,11 @@ describe 'File', -> newPath = null beforeEach -> - newPath = fs.join(fs.directory(path), "atom-file-was-moved-test.txt") + newPath = fsUtils.join(fsUtils.directory(path), "atom-file-was-moved-test.txt") afterEach -> - if fs.exists(newPath) - fs.remove(newPath) + if fsUtils.exists(newPath) + fsUtils.remove(newPath) waitsFor "remove event", (done) -> file.on 'removed', done it "it updates its path", -> @@ -58,7 +58,7 @@ describe 'File', -> moveHandler = jasmine.createSpy('moveHandler') file.on 'moved', moveHandler - fs.move(path, newPath) + fsUtils.move(path, newPath) waitsFor "move event", -> moveHandler.callCount > 0 @@ -74,14 +74,14 @@ describe 'File', -> changeHandler = jasmine.createSpy('changeHandler') file.on 'contents-changed', changeHandler - fs.move(path, newPath) + fsUtils.move(path, newPath) waitsFor "move event", -> moveHandler.callCount > 0 runs -> expect(changeHandler).not.toHaveBeenCalled() - fs.write(file.getPath(), "this is new!") + fsUtils.write(file.getPath(), "this is new!") waitsFor "change event", -> changeHandler.callCount > 0 @@ -98,12 +98,12 @@ describe 'File', -> expect(changeHandler).not.toHaveBeenCalled() - fs.remove(path) + fsUtils.remove(path) expect(changeHandler).not.toHaveBeenCalled() waits 20 runs -> - fs.write(path, "HE HAS RISEN!") + fsUtils.write(path, "HE HAS RISEN!") expect(changeHandler).not.toHaveBeenCalled() waitsFor "resurrection change event", -> @@ -111,7 +111,7 @@ describe 'File', -> runs -> expect(removeHandler).not.toHaveBeenCalled() - fs.write(path, "Hallelujah!") + fsUtils.write(path, "Hallelujah!") changeHandler.reset() waitsFor "post-resurrection change event", -> diff --git a/spec/app/git-spec.coffee b/spec/app/git-spec.coffee index 921d88cc5..ade848136 100644 --- a/spec/app/git-spec.coffee +++ b/spec/app/git-spec.coffee @@ -1,12 +1,12 @@ Git = require 'git' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Task = require 'task' describe "Git", -> repo = null beforeEach -> - fs.remove('/tmp/.git') if fs.isDirectory('/tmp/.git') + fsUtils.remove('/tmp/.git') if fsUtils.isDirectory('/tmp/.git') afterEach -> repo.destroy() if repo?.repo? @@ -21,55 +21,55 @@ describe "Git", -> describe ".getPath()", -> it "returns the repository path for a .git directory path", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/master.git/HEAD')) - expect(repo.getPath()).toBe fs.resolveOnLoadPath('fixtures/git/master.git') + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/master.git/HEAD')) + expect(repo.getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/git/master.git') it "returns the repository path for a repository path", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/master.git')) - expect(repo.getPath()).toBe fs.resolveOnLoadPath('fixtures/git/master.git') + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/master.git')) + expect(repo.getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/git/master.git') describe ".getHead()", -> it "returns a branch name for a non-empty repository", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/master.git')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/master.git')) expect(repo.getHead()).toBe 'refs/heads/master' describe ".getShortHead()", -> it "returns a branch name for a non-empty repository", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/master.git')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/master.git')) expect(repo.getShortHead()).toBe 'master' describe ".isPathIgnored(path)", -> it "returns true for an ignored path", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/ignore.git')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/ignore.git')) expect(repo.isPathIgnored('a.txt')).toBeTruthy() it "returns false for a non-ignored path", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/ignore.git')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/ignore.git')) expect(repo.isPathIgnored('b.txt')).toBeFalsy() describe ".isPathModified(path)", -> [repo, path, newPath, originalPathText] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) - path = fs.resolveOnLoadPath('fixtures/git/working-dir/file.txt') - newPath = fs.join(fs.resolveOnLoadPath('fixtures/git/working-dir'), 'new-path.txt') - originalPathText = fs.read(path) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) + path = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/file.txt') + newPath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/git/working-dir'), 'new-path.txt') + originalPathText = fsUtils.read(path) afterEach -> - fs.write(path, originalPathText) - fs.remove(newPath) if fs.exists(newPath) + fsUtils.write(path, originalPathText) + fsUtils.remove(newPath) if fsUtils.exists(newPath) describe "when the path is unstaged", -> it "returns false if the path has not been modified", -> expect(repo.isPathModified(path)).toBeFalsy() it "returns true if the path is modified", -> - fs.write(path, "change") + fsUtils.write(path, "change") expect(repo.isPathModified(path)).toBeTruthy() it "returns true if the path is deleted", -> - fs.remove(path) + fsUtils.remove(path) expect(repo.isPathModified(path)).toBeTruthy() it "returns false if the path is new", -> @@ -79,13 +79,13 @@ describe "Git", -> [path, newPath] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) - path = fs.resolveOnLoadPath('fixtures/git/working-dir/file.txt') - newPath = fs.join(fs.resolveOnLoadPath('fixtures/git/working-dir'), 'new-path.txt') - fs.write(newPath, "i'm new here") + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) + path = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/file.txt') + newPath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/git/working-dir'), 'new-path.txt') + fsUtils.write(newPath, "i'm new here") afterEach -> - fs.remove(newPath) if fs.exists(newPath) + fsUtils.remove(newPath) if fsUtils.exists(newPath) describe "when the path is unstaged", -> it "returns true if the path is new", -> @@ -98,37 +98,37 @@ describe "Git", -> [path1, path2, originalPath1Text, originalPath2Text] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) - path1 = fs.resolveOnLoadPath('fixtures/git/working-dir/file.txt') - originalPath1Text = fs.read(path1) - path2 = fs.resolveOnLoadPath('fixtures/git/working-dir/other.txt') - originalPath2Text = fs.read(path2) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) + path1 = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/file.txt') + originalPath1Text = fsUtils.read(path1) + path2 = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/other.txt') + originalPath2Text = fsUtils.read(path2) afterEach -> - fs.write(path1, originalPath1Text) - fs.write(path2, originalPath2Text) + fsUtils.write(path1, originalPath1Text) + fsUtils.write(path2, originalPath2Text) it "no longer reports a path as modified after checkout", -> expect(repo.isPathModified(path1)).toBeFalsy() - fs.write(path1, '') + fsUtils.write(path1, '') expect(repo.isPathModified(path1)).toBeTruthy() expect(repo.checkoutHead(path1)).toBeTruthy() expect(repo.isPathModified(path1)).toBeFalsy() it "restores the contents of the path to the original text", -> - fs.write(path1, '') + fsUtils.write(path1, '') expect(repo.checkoutHead(path1)).toBeTruthy() - expect(fs.read(path1)).toBe(originalPath1Text) + expect(fsUtils.read(path1)).toBe(originalPath1Text) it "only restores the path specified", -> - fs.write(path2, 'path 2 is edited') + fsUtils.write(path2, 'path 2 is edited') expect(repo.isPathModified(path2)).toBeTruthy() expect(repo.checkoutHead(path1)).toBeTruthy() - expect(fs.read(path2)).toBe('path 2 is edited') + expect(fsUtils.read(path2)).toBe('path 2 is edited') expect(repo.isPathModified(path2)).toBeTruthy() it "fires a status-changed event if the checkout completes successfully", -> - fs.write(path1, '') + fsUtils.write(path1, '') repo.getPathStatus(path1) statusHandler = jasmine.createSpy('statusHandler') repo.on 'status-changed', statusHandler @@ -141,7 +141,7 @@ describe "Git", -> describe ".destroy()", -> it "throws an exception when any method is called after it is called", -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/master.git/HEAD')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/master.git/HEAD')) repo.destroy() expect(-> repo.getHead()).toThrow() @@ -149,38 +149,38 @@ describe "Git", -> [path, originalPathText] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) - path = fs.resolveOnLoadPath('fixtures/git/working-dir/file.txt') - originalPathText = fs.read(path) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) + path = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/file.txt') + originalPathText = fsUtils.read(path) afterEach -> - fs.write(path, originalPathText) + fsUtils.write(path, originalPathText) it "returns the number of lines added and deleted", -> expect(repo.getDiffStats(path)).toEqual {added: 0, deleted: 0} - fs.write(path, "#{originalPathText} edited line") + fsUtils.write(path, "#{originalPathText} edited line") expect(repo.getDiffStats(path)).toEqual {added: 1, deleted: 1} describe ".getPathStatus(path)", -> [path, originalPathText] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) - path = fs.resolveOnLoadPath('fixtures/git/working-dir/file.txt') - originalPathText = fs.read(path) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) + path = fsUtils.resolveOnLoadPath('fixtures/git/working-dir/file.txt') + originalPathText = fsUtils.read(path) afterEach -> - fs.write(path, originalPathText) + fsUtils.write(path, originalPathText) it "trigger a status-changed event when the new status differs from the last cached one", -> statusHandler = jasmine.createSpy("statusHandler") repo.on 'status-changed', statusHandler - fs.write(path, '') + fsUtils.write(path, '') status = repo.getPathStatus(path) expect(statusHandler.callCount).toBe 1 expect(statusHandler.argsForCall[0][0..1]).toEqual [path, status] - fs.write(path, 'abc') + fsUtils.write(path, 'abc') status = repo.getPathStatus(path) expect(statusHandler.callCount).toBe 1 @@ -188,19 +188,19 @@ describe "Git", -> [newPath, modifiedPath, cleanPath, originalModifiedPathText] = [] beforeEach -> - repo = new Git(fs.resolveOnLoadPath('fixtures/git/working-dir')) + repo = new Git(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) modifiedPath = project.resolve('git/working-dir/file.txt') - originalModifiedPathText = fs.read(modifiedPath) + originalModifiedPathText = fsUtils.read(modifiedPath) newPath = project.resolve('git/working-dir/untracked.txt') cleanPath = project.resolve('git/working-dir/other.txt') - fs.write(newPath, '') + fsUtils.write(newPath, '') afterEach -> - fs.write(modifiedPath, originalModifiedPathText) - fs.remove(newPath) if fs.exists(newPath) + fsUtils.write(modifiedPath, originalModifiedPathText) + fsUtils.remove(newPath) if fsUtils.exists(newPath) it "returns status information for all new and modified files", -> - fs.write(modifiedPath, 'making this path modified') + fsUtils.write(modifiedPath, 'making this path modified') statusHandler = jasmine.createSpy('statusHandler') repo.on 'statuses-changed', statusHandler repo.refreshStatus() @@ -215,7 +215,7 @@ describe "Git", -> expect(repo.isStatusModified(statuses[modifiedPath])).toBeTruthy() it "only starts a single web worker at a time and schedules a restart if one is already running", => - fs.write(modifiedPath, 'making this path modified') + fsUtils.write(modifiedPath, 'making this path modified') statusHandler = jasmine.createSpy('statusHandler') repo.on 'statuses-changed', statusHandler diff --git a/spec/app/project-spec.coffee b/spec/app/project-spec.coffee index 48f483fc5..14e0af834 100644 --- a/spec/app/project-spec.coffee +++ b/spec/app/project-spec.coffee @@ -1,5 +1,5 @@ Project = require 'project' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' BufferedProcess = require 'buffered-process' @@ -29,12 +29,12 @@ describe "Project", -> editSession = project.buildEditSession() editSession.saveAs('/tmp/atom-test-save-sets-project-path') expect(project.getPath()).toBe '/tmp' - fs.remove('/tmp/atom-test-save-sets-project-path') + fsUtils.remove('/tmp/atom-test-save-sets-project-path') describe ".buildEditSession(path)", -> [absolutePath, newBufferHandler, newEditSessionHandler] = [] beforeEach -> - absolutePath = fs.resolveOnLoadPath('fixtures/dir/a') + absolutePath = fsUtils.resolveOnLoadPath('fixtures/dir/a') newBufferHandler = jasmine.createSpy('newBufferHandler') project.on 'buffer-created', newBufferHandler newEditSessionHandler = jasmine.createSpy('newEditSessionHandler') @@ -86,30 +86,30 @@ describe "Project", -> describe ".resolve(path)", -> it "returns an absolute path based on the project's root", -> - absolutePath = fs.resolveOnLoadPath('fixtures/dir/a') + absolutePath = fsUtils.resolveOnLoadPath('fixtures/dir/a') expect(project.resolve('a')).toBe absolutePath expect(project.resolve(absolutePath + '/../a')).toBe absolutePath expect(project.resolve('a/../a')).toBe absolutePath describe ".relativize(path)", -> it "returns an relative path based on the project's root", -> - absolutePath = fs.resolveOnLoadPath('fixtures/dir') - expect(project.relativize(fs.join(absolutePath, "b"))).toBe "b" - expect(project.relativize(fs.join(absolutePath, "b/file.coffee"))).toBe "b/file.coffee" - expect(project.relativize(fs.join(absolutePath, "file.coffee"))).toBe "file.coffee" + absolutePath = fsUtils.resolveOnLoadPath('fixtures/dir') + expect(project.relativize(fsUtils.join(absolutePath, "b"))).toBe "b" + expect(project.relativize(fsUtils.join(absolutePath, "b/file.coffee"))).toBe "b/file.coffee" + expect(project.relativize(fsUtils.join(absolutePath, "file.coffee"))).toBe "file.coffee" describe ".setPath(path)", -> describe "when path is a file", -> it "sets its path to the files parent directory and updates the root directory", -> - project.setPath(fs.resolveOnLoadPath('fixtures/dir/a')) - expect(project.getPath()).toEqual fs.resolveOnLoadPath('fixtures/dir') - expect(project.getRootDirectory().path).toEqual fs.resolveOnLoadPath('fixtures/dir') + project.setPath(fsUtils.resolveOnLoadPath('fixtures/dir/a')) + expect(project.getPath()).toEqual fsUtils.resolveOnLoadPath('fixtures/dir') + expect(project.getRootDirectory().path).toEqual fsUtils.resolveOnLoadPath('fixtures/dir') describe "when path is a directory", -> it "sets its path to the directory and updates the root directory", -> - project.setPath(fs.resolveOnLoadPath('fixtures/dir/a-dir')) - expect(project.getPath()).toEqual fs.resolveOnLoadPath('fixtures/dir/a-dir') - expect(project.getRootDirectory().path).toEqual fs.resolveOnLoadPath('fixtures/dir/a-dir') + project.setPath(fsUtils.resolveOnLoadPath('fixtures/dir/a-dir')) + expect(project.getPath()).toEqual fsUtils.resolveOnLoadPath('fixtures/dir/a-dir') + expect(project.getRootDirectory().path).toEqual fsUtils.resolveOnLoadPath('fixtures/dir/a-dir') describe "when path is null", -> it "sets its path and root directory to null", -> @@ -127,7 +127,7 @@ describe "Project", -> expect(paths.length).toBeGreaterThan 0 it "ignores files that return true from atom.ignorePath(path)", -> - spyOn(project, 'isPathIgnored').andCallFake (path) -> fs.base(path).match /a$/ + spyOn(project, 'isPathIgnored').andCallFake (path) -> fsUtils.base(path).match /a$/ paths = null waitsForPromise -> @@ -140,7 +140,7 @@ describe "Project", -> describe "when config.core.hideGitIgnoredFiles is true", -> it "ignores files that are present in .gitignore if the project is a git repo", -> config.set "core.hideGitIgnoredFiles", true - project.setPath(fs.resolveOnLoadPath('fixtures/git/working-dir')) + project.setPath(fsUtils.resolveOnLoadPath('fixtures/git/working-dir')) paths = null waitsForPromise -> project.getFilePaths().done (foundPaths) -> paths = foundPaths @@ -152,11 +152,11 @@ describe "Project", -> ignoredFile = null beforeEach -> - ignoredFile = fs.join(fs.resolveOnLoadPath('fixtures/dir'), 'ignored.txt') - fs.write(ignoredFile, "") + ignoredFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/dir'), 'ignored.txt') + fsUtils.write(ignoredFile, "") afterEach -> - fs.remove(ignoredFile) + fsUtils.remove(ignoredFile) it "ignores ignored.txt file", -> paths = null @@ -172,11 +172,11 @@ describe "Project", -> ignoredFile = null beforeEach -> - ignoredFile = fs.join(fs.resolveOnLoadPath('fixtures/dir'), 'ignored/ignored.txt') - fs.write(ignoredFile, "") + ignoredFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/dir'), 'ignored/ignored.txt') + fsUtils.write(ignoredFile, "") afterEach -> - fs.remove(ignoredFile) + fsUtils.remove(ignoredFile) it "ignores ignored folder", -> paths = null @@ -222,7 +222,7 @@ describe "Project", -> range: [[2, 6], [2, 11]] it "works on evil filenames", -> - project.setPath(fs.resolveOnLoadPath('fixtures/evil-files')) + project.setPath(fsUtils.resolveOnLoadPath('fixtures/evil-files')) paths = [] matches = [] waitsForPromise -> @@ -237,7 +237,7 @@ describe "Project", -> expect(paths[1]).toMatch /file with spaces.txt$/ expect(paths[2]).toMatch /goddam\nnewlines$/m expect(paths[3]).toMatch /quote".txt$/m - expect(fs.base(paths[4])).toBe "utfa\u0306.md" + expect(fsUtils.base(paths[4])).toBe "utfa\u0306.md" it "handles breaks in the search subprocess's output following the filename", -> spyOn(BufferedProcess.prototype, 'bufferStream') @@ -246,7 +246,7 @@ describe "Project", -> project.scan /a+/, iterator stdout = BufferedProcess.prototype.bufferStream.argsForCall[0][1] - stdout ":#{fs.resolveOnLoadPath('fixtures/dir/a')}\n" + stdout ":#{fsUtils.resolveOnLoadPath('fixtures/dir/a')}\n" stdout "1;0 3:aaa bbb\n2;3 2:cc aa cc\n" expect(iterator.argsForCall[0][0]).toEqual diff --git a/spec/app/root-view-spec.coffee b/spec/app/root-view-spec.coffee index 4935dbd1b..2651a45f6 100644 --- a/spec/app/root-view-spec.coffee +++ b/spec/app/root-view-spec.coffee @@ -1,5 +1,5 @@ $ = require 'jquery' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Project = require 'project' RootView = require 'root-view' Buffer = require 'text-buffer' @@ -83,7 +83,7 @@ describe "RootView", -> expect(editor3.isFocused).toBeFalsy() expect(editor4.isFocused).toBeFalsy() - expect(rootView.title).toBe "#{fs.base(editor2.getPath())} - #{project.getPath()}" + expect(rootView.title).toBe "#{fsUtils.base(editor2.getPath())} - #{project.getPath()}" describe "where there are no open editors", -> it "constructs the view with no open editors", -> @@ -175,10 +175,10 @@ describe "RootView", -> expect(rootView.title).toBe "#{item.getTitle()} - #{project.getPath()}" describe "when the last pane item is removed", -> - it "sets the title to the project's path", -> + it "update the title to contain the project's path", -> rootView.getActivePane().remove() expect(rootView.getActivePaneItem()).toBeUndefined() - expect(rootView.title).toBe project.getPath() + expect(rootView.title).toBe "atom - #{project.getPath()}" describe "when an inactive pane's item changes", -> it "does not update the title", -> @@ -223,7 +223,7 @@ describe "RootView", -> it "creates an edit session for the given path as an item on a new pane, and focuses the pane", -> editSession = rootView.open('b') expect(rootView.getActivePane().activeItem).toBe editSession - expect(editSession.getPath()).toBe fs.resolveOnLoadPath('fixtures/dir/b') + expect(editSession.getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/dir/b') expect(rootView.getActivePane().focus).toHaveBeenCalled() describe "when the changeFocus option is false", -> diff --git a/spec/app/syntax-spec.coffee b/spec/app/syntax-spec.coffee index ad12bee71..6f5ece9df 100644 --- a/spec/app/syntax-spec.coffee +++ b/spec/app/syntax-spec.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "the `syntax` global", -> beforeEach -> @@ -13,7 +13,7 @@ describe "the `syntax` global", -> expect(syntax.selectGrammar(path).name).not.toBe 'Ruby' syntax.setGrammarOverrideForPath(path, 'source.ruby') syntax2 = deserialize(syntax.serialize()) - syntax2.addGrammar(grammar) for grammar in syntax.grammars + syntax2.addGrammar(grammar) for grammar in syntax.grammars when grammar isnt syntax.nullGrammar expect(syntax2.selectGrammar(path).name).toBe 'Ruby' describe ".selectGrammar(filePath)", -> @@ -23,8 +23,8 @@ describe "the `syntax` global", -> expect(syntax.selectGrammar("file.js").name).toBe "JavaScript" # based on extension (.js) expect(syntax.selectGrammar("/tmp/.git/config").name).toBe "Git Config" # based on end of the path (.git/config) expect(syntax.selectGrammar("Rakefile").name).toBe "Ruby" # based on the file's basename (Rakefile) - expect(syntax.selectGrammar("curb").name).toBe "Plain Text" - expect(syntax.selectGrammar("/hu.git/config").name).toBe "Plain Text" + expect(syntax.selectGrammar("curb").name).toBe "Null Grammar" + expect(syntax.selectGrammar("/hu.git/config").name).toBe "Null Grammar" it "uses the filePath's shebang line if the grammar cannot be determined by the extension or basename", -> filePath = require.resolve("fixtures/shebang") @@ -37,17 +37,17 @@ describe "the `syntax` global", -> expect(syntax.selectGrammar("dummy.coffee", fileContent).name).toBe "CoffeeScript" fileContent = '' - expect(syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Plain Text" + expect(syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Null Grammar" fileContent += '\n' expect(syntax.selectGrammar("grammar.tmLanguage", fileContent).name).toBe "Property List (XML)" it "doesn't read the file when the file contents are specified", -> filePath = require.resolve("fixtures/shebang") - filePathContents = fs.read(filePath) - spyOn(fs, 'read').andCallThrough() + filePathContents = fsUtils.read(filePath) + spyOn(fsUtils, 'read').andCallThrough() expect(syntax.selectGrammar(filePath, filePathContents).name).toBe "Ruby" - expect(fs.read).not.toHaveBeenCalled() + expect(fsUtils.read).not.toHaveBeenCalled() it "allows the default grammar to be overridden for a path", -> path = '/foo/bar/file.js' diff --git a/spec/app/text-buffer-spec.coffee b/spec/app/text-buffer-spec.coffee index 72233ba16..8181e2ab6 100644 --- a/spec/app/text-buffer-spec.coffee +++ b/spec/app/text-buffer-spec.coffee @@ -1,6 +1,6 @@ Project = require 'project' Buffer = require 'text-buffer' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' describe 'Buffer', -> @@ -8,7 +8,7 @@ describe 'Buffer', -> beforeEach -> filePath = require.resolve('fixtures/sample.js') - fileContents = fs.read(filePath) + fileContents = fsUtils.read(filePath) buffer = project.bufferForPath(filePath) afterEach -> @@ -24,7 +24,7 @@ describe 'Buffer', -> it "loads the contents of that file", -> filePath = require.resolve 'fixtures/sample.txt' buffer = project.bufferForPath(filePath) - expect(buffer.getText()).toBe fs.read(filePath) + expect(buffer.getText()).toBe fsUtils.read(filePath) it "is not modified and has no undo history", -> buffer = project.bufferForPath(filePath) @@ -34,7 +34,7 @@ describe 'Buffer', -> describe "when no file exists for the path", -> it "throws an exception", -> filePath = "does-not-exist.txt" - expect(fs.exists(filePath)).toBeFalsy() + expect(fsUtils.exists(filePath)).toBeFalsy() expect(-> project.bufferForPath(filePath)).toThrow() describe "when no path is given", -> @@ -46,25 +46,25 @@ describe 'Buffer', -> [path, newPath, bufferToChange, eventHandler] = [] beforeEach -> - path = fs.join(fs.resolveOnLoadPath("fixtures"), "atom-manipulate-me") + path = fsUtils.join(fsUtils.resolveOnLoadPath("fixtures"), "atom-manipulate-me") newPath = "#{path}-i-moved" - fs.write(path, "") + fsUtils.write(path, "") bufferToChange = project.bufferForPath(path) eventHandler = jasmine.createSpy('eventHandler') bufferToChange.on 'path-changed', eventHandler afterEach -> bufferToChange.destroy() - fs.remove(path) if fs.exists(path) - fs.remove(newPath) if fs.exists(newPath) + fsUtils.remove(path) if fsUtils.exists(path) + fsUtils.remove(newPath) if fsUtils.exists(newPath) it "triggers a `path-changed` event when path is changed", -> bufferToChange.saveAs(newPath) expect(eventHandler).toHaveBeenCalledWith(bufferToChange) it "triggers a `path-changed` event when the file is moved", -> - fs.remove(newPath) if fs.exists(newPath) - fs.move(path, newPath) + fsUtils.remove(newPath) if fsUtils.exists(newPath) + fsUtils.move(path, newPath) waitsFor "buffer path change", -> eventHandler.callCount > 0 @@ -76,14 +76,14 @@ describe 'Buffer', -> path = null beforeEach -> path = "/tmp/tmp.txt" - fs.write(path, "first") + fsUtils.write(path, "first") buffer.release() buffer = project.bufferForPath(path).retain() afterEach -> buffer.release() buffer = null - fs.remove(path) if fs.exists(path) + fsUtils.remove(path) if fsUtils.exists(path) it "does not trigger a change event when Atom modifies the file", -> buffer.insert([0,0], "HELLO!") @@ -99,7 +99,7 @@ describe 'Buffer', -> it "changes the memory contents of the buffer to match the new disk contents and triggers a 'changed' event", -> changeHandler = jasmine.createSpy('changeHandler') buffer.on 'changed', changeHandler - fs.write(path, "second") + fsUtils.write(path, "second") expect(changeHandler.callCount).toBe 0 waitsFor "file to trigger change event", -> @@ -119,7 +119,7 @@ describe 'Buffer', -> buffer.file.on 'contents-changed', fileChangeHandler buffer.insert([0, 0], "a change") - fs.write(path, "second") + fsUtils.write(path, "second") expect(fileChangeHandler.callCount).toBe 0 waitsFor "file to trigger 'contents-changed' event", -> @@ -134,7 +134,7 @@ describe 'Buffer', -> buffer.insert([0, 0], "a second change") handler = jasmine.createSpy('fileChange') - fs.write(path, "second") + fsUtils.write(path, "second") buffer.on 'contents-conflicted', handler expect(handler.callCount).toBe 0 @@ -149,7 +149,7 @@ describe 'Buffer', -> beforeEach -> path = "/tmp/atom-file-to-delete.txt" - fs.write(path, 'delete me') + fsUtils.write(path, 'delete me') bufferToDelete = project.bufferForPath(path) path = bufferToDelete.getPath() # symlinks may have been converted @@ -158,7 +158,7 @@ describe 'Buffer', -> removeHandler = jasmine.createSpy('removeHandler') bufferToDelete.file.on 'removed', removeHandler - fs.remove(path) + fsUtils.remove(path) waitsFor "file to be removed", -> removeHandler.callCount > 0 @@ -174,7 +174,7 @@ describe 'Buffer', -> expect(bufferToDelete.fileExists()).toBeTruthy() expect(bufferToDelete.isInConflict()).toBeFalsy() - fs.write(path, 'moo') + fsUtils.write(path, 'moo') changeHandler = jasmine.createSpy('changeHandler') bufferToDelete.on 'changed', changeHandler @@ -207,19 +207,19 @@ describe 'Buffer', -> it "reports the modified status changing to true after the underlying file is deleted", -> buffer.release() filePath = "/tmp/atom-tmp-file" - fs.write(filePath, 'delete me') + fsUtils.write(filePath, 'delete me') buffer = project.bufferForPath(filePath) modifiedHandler = jasmine.createSpy("modifiedHandler") buffer.on 'modified-status-changed', modifiedHandler - fs.remove(filePath) + fsUtils.remove(filePath) waitsFor "modified status to change", -> modifiedHandler.callCount runs -> expect(buffer.isModified()).toBe true it "reports the modified status changing to false after a modified buffer is saved", -> filePath = "/tmp/atom-tmp-file" - fs.write(filePath, '') + fsUtils.write(filePath, '') buffer.release() buffer = project.bufferForPath(filePath) modifiedHandler = jasmine.createSpy("modifiedHandler") @@ -243,7 +243,7 @@ describe 'Buffer', -> it "reports the modified status changing to false after a modified buffer is reloaded", -> filePath = "/tmp/atom-tmp-file" - fs.write(filePath, '') + fsUtils.write(filePath, '') buffer.release() buffer = project.bufferForPath(filePath) modifiedHandler = jasmine.createSpy("modifiedHandler") @@ -420,16 +420,16 @@ describe 'Buffer', -> beforeEach -> filePath = '/tmp/temp.txt' - fs.write(filePath, "") + fsUtils.write(filePath, "") saveBuffer = project.bufferForPath(filePath) saveBuffer.setText("blah") it "saves the contents of the buffer to the path", -> saveBuffer.setText 'Buffer contents!' saveBuffer.save() - expect(fs.read(filePath)).toEqual 'Buffer contents!' + expect(fsUtils.read(filePath)).toEqual 'Buffer contents!' - it "fires will-be-saved and saved events around the call to fs.write", -> + it "fires will-be-saved and saved events around the call to fsUtils.write", -> events = [] beforeSave1 = -> events.push('beforeSave1') beforeSave2 = -> events.push('beforeSave2') @@ -438,12 +438,12 @@ describe 'Buffer', -> saveBuffer.on 'will-be-saved', beforeSave1 saveBuffer.on 'will-be-saved', beforeSave2 - spyOn(fs, 'write').andCallFake -> events.push 'fs.write' + spyOn(fsUtils, 'write').andCallFake -> events.push 'fsUtils.write' saveBuffer.on 'saved', afterSave1 saveBuffer.on 'saved', afterSave2 saveBuffer.save() - expect(events).toEqual ['beforeSave1', 'beforeSave2', 'fs.write', 'afterSave1', 'afterSave2'] + expect(events).toEqual ['beforeSave1', 'beforeSave2', 'fsUtils.write', 'afterSave1', 'afterSave2'] it "fires will-reload and reloaded events when reloaded", -> events = [] @@ -477,7 +477,7 @@ describe 'Buffer', -> it "saves the contents of the buffer to the path", -> filePath = '/tmp/temp.txt' - fs.remove filePath if fs.exists(filePath) + fsUtils.remove filePath if fsUtils.exists(filePath) saveAsBuffer = project.bufferForPath(null).retain() eventHandler = jasmine.createSpy('eventHandler') @@ -485,14 +485,14 @@ describe 'Buffer', -> saveAsBuffer.setText 'Buffer contents!' saveAsBuffer.saveAs(filePath) - expect(fs.read(filePath)).toEqual 'Buffer contents!' + expect(fsUtils.read(filePath)).toEqual 'Buffer contents!' expect(eventHandler).toHaveBeenCalledWith(saveAsBuffer) it "stops listening to events on previous path and begins listening to events on new path", -> originalPath = "/tmp/original.txt" newPath = "/tmp/new.txt" - fs.write(originalPath, "") + fsUtils.write(originalPath, "") saveAsBuffer = project.bufferForPath(originalPath).retain() changeHandler = jasmine.createSpy('changeHandler') @@ -500,11 +500,11 @@ describe 'Buffer', -> saveAsBuffer.saveAs(newPath) expect(changeHandler).not.toHaveBeenCalled() - fs.write(originalPath, "should not trigger buffer event") + fsUtils.write(originalPath, "should not trigger buffer event") waits 20 runs -> expect(changeHandler).not.toHaveBeenCalled() - fs.write(newPath, "should trigger buffer event") + fsUtils.write(newPath, "should trigger buffer event") waitsFor -> changeHandler.callCount > 0 @@ -546,7 +546,7 @@ describe 'Buffer', -> describe "when given a regex with a ignore case flag", -> it "does a case-insensitive search", -> matches = [] - buffer.scanInRange /cuRRent/i, [[0,0], [12,0]], (match, range) -> + buffer.scanInRange /cuRRent/i, [[0,0], [12,0]], ({match, range}) -> matches.push(match) expect(matches.length).toBe 1 @@ -554,7 +554,7 @@ describe 'Buffer', -> it "calls the iterator with the first match for the given regex in the given range", -> matches = [] ranges = [] - buffer.scanInRange /cu(rr)ent/, [[4,0], [6,44]], (match, range) -> + buffer.scanInRange /cu(rr)ent/, [[4,0], [6,44]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -569,7 +569,7 @@ describe 'Buffer', -> it "calls the iterator with each match for the given regex in the given range", -> matches = [] ranges = [] - buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range) -> + buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -593,7 +593,7 @@ describe 'Buffer', -> it "calls the iterator with the truncated match", -> matches = [] ranges = [] - buffer.scanInRange /cu(r*)/g, [[4,0], [6,9]], (match, range) -> + buffer.scanInRange /cu(r*)/g, [[4,0], [6,9]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -612,7 +612,7 @@ describe 'Buffer', -> it "calls the iterator with the truncated match", -> matches = [] ranges = [] - buffer.scanInRange /cu(r*)e/g, [[4,0], [6,9]], (match, range) -> + buffer.scanInRange /cu(r*)e/g, [[4,0], [6,9]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -626,7 +626,7 @@ describe 'Buffer', -> describe "when the iterator calls the 'replace' control function with a replacement string", -> it "replaces each occurrence of the regex match with the string", -> ranges = [] - buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range, { replace }) -> + buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({range, replace}) -> ranges.push(range) replace("foo") @@ -638,7 +638,7 @@ describe 'Buffer', -> expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' it "allows the match to be replaced with the empty string", -> - buffer.scanInRange /current/g, [[4,0], [6,59]], (match, range, { replace }) -> + buffer.scanInRange /current/g, [[4,0], [6,59]], ({replace}) -> replace("") expect(buffer.lineForRow(5)).toBe ' = items.shift();' @@ -647,7 +647,7 @@ describe 'Buffer', -> describe "when the iterator calls the 'stop' control function", -> it "stops the traversal", -> ranges = [] - buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range, { stop }) -> + buffer.scanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({range, stop}) -> ranges.push(range) stop() if ranges.length == 2 @@ -658,7 +658,7 @@ describe 'Buffer', -> it "calls the iterator with the last match for the given regex in the given range", -> matches = [] ranges = [] - buffer.backwardsScanInRange /cu(rr)ent/, [[4,0], [6,44]], (match, range) -> + buffer.backwardsScanInRange /cu(rr)ent/, [[4,0], [6,44]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -673,7 +673,7 @@ describe 'Buffer', -> it "calls the iterator with each match for the given regex in the given range, starting with the last match", -> matches = [] ranges = [] - buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range) -> + buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({match, range}) -> matches.push(match) ranges.push(range) @@ -695,7 +695,7 @@ describe 'Buffer', -> describe "when the iterator calls the 'replace' control function with a replacement string", -> it "replaces each occurrence of the regex match with the string", -> ranges = [] - buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range, { replace }) -> + buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({range, replace}) -> ranges.push(range) replace("foo") unless range.start.isEqual([6,6]) @@ -709,7 +709,7 @@ describe 'Buffer', -> describe "when the iterator calls the 'stop' control function", -> it "stops the traversal", -> ranges = [] - buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], (match, range, { stop }) -> + buffer.backwardsScanInRange /cu(rr)ent/g, [[4,0], [6,59]], ({range, stop}) -> ranges.push(range) stop() if ranges.length == 2 diff --git a/spec/app/text-mate-grammar-spec.coffee b/spec/app/text-mate-grammar-spec.coffee index c23bfd6b8..eb9033e14 100644 --- a/spec/app/text-mate-grammar-spec.coffee +++ b/spec/app/text-mate-grammar-spec.coffee @@ -1,7 +1,7 @@ TextMateGrammar = require 'text-mate-grammar' TextMatePackage = require 'text-mate-package' plist = require 'plist' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' describe "TextMateGrammar", -> @@ -16,13 +16,13 @@ describe "TextMateGrammar", -> describe "@loadSync(path)", -> it "loads grammars from plists", -> - grammar = TextMateGrammar.loadSync(fs.resolveOnLoadPath('packages/text.tmbundle/Syntaxes/Plain text.plist')) + grammar = TextMateGrammar.loadSync(fsUtils.resolveOnLoadPath('packages/text.tmbundle/Syntaxes/Plain text.plist')) expect(grammar.scopeName).toBe "text.plain" {tokens} = grammar.tokenizeLine("this text is so plain. i love it.") expect(tokens[0]).toEqual value: "this text is so plain. i love it.", scopes: ["text.plain", "meta.paragraph.text"] it "loads grammars from cson files", -> - grammar = TextMateGrammar.loadSync(fs.resolveOnLoadPath('package-with-grammars/grammars/alot.cson')) + grammar = TextMateGrammar.loadSync(fsUtils.resolveOnLoadPath('package-with-grammars/grammars/alot.cson')) expect(grammar.scopeName).toBe "source.alot" {tokens} = grammar.tokenizeLine("this is alot of code") expect(tokens[1]).toEqual value: "alot", scopes: ["source.alot", "keyword.alot"] @@ -138,7 +138,7 @@ describe "TextMateGrammar", -> describe "when the line matches a pattern with no `name` or `contentName`", -> it "creates tokens without adding a new scope", -> - grammar = syntax.grammarsByFileType["rb"] + grammar = syntax.selectGrammar('foo.rb') {tokens} = grammar.tokenizeLine('%w|oh \\look|') expect(tokens.length).toBe 5 expect(tokens[0]).toEqual value: '%w|', scopes: ["source.ruby", "string.quoted.other.literal.lower.ruby", "punctuation.definition.string.begin.ruby"] @@ -183,7 +183,7 @@ describe "TextMateGrammar", -> describe "when the end pattern contains a back reference", -> it "constructs the end rule based on its back-references to captures in the begin rule", -> - grammar = syntax.grammarsByFileType["rb"] + grammar = syntax.selectGrammar('foo.rb') {tokens} = grammar.tokenizeLine('%w|oh|,') expect(tokens.length).toBe 4 expect(tokens[0]).toEqual value: '%w|', scopes: ["source.ruby", "string.quoted.other.literal.lower.ruby", "punctuation.definition.string.begin.ruby"] @@ -192,7 +192,7 @@ describe "TextMateGrammar", -> expect(tokens[3]).toEqual value: ',', scopes: ["source.ruby", "punctuation.separator.object.ruby"] it "allows the rule containing that end pattern to be pushed to the stack multiple times", -> - grammar = syntax.grammarsByFileType["rb"] + grammar = syntax.selectGrammar('foo.rb') {tokens} = grammar.tokenizeLine('%Q+matz had some #{%Q-crazy ideas-} for ruby syntax+ # damn.') expect(tokens[0]).toEqual value: '%Q+', scopes: ["source.ruby","string.quoted.other.literal.upper.ruby","punctuation.definition.string.begin.ruby"] expect(tokens[1]).toEqual value: 'matz had some ', scopes: ["source.ruby","string.quoted.other.literal.upper.ruby"] @@ -212,7 +212,7 @@ describe "TextMateGrammar", -> atom.activatePackage('html.tmbundle', sync: true) atom.activatePackage('ruby-on-rails-tmbundle', sync: true) - grammar = syntax.grammarsByFileType["html.erb"] + grammar = syntax.selectGrammar('foo.html.erb') {tokens} = grammar.tokenizeLine("
<%= User.find(2).full_name %>
") expect(tokens[0]).toEqual value: '<', scopes: ["text.html.ruby","meta.tag.block.any.html","punctuation.definition.tag.begin.html"] diff --git a/spec/app/text-mate-theme-spec.coffee b/spec/app/text-mate-theme-spec.coffee index 16588606c..0292c714b 100644 --- a/spec/app/text-mate-theme-spec.coffee +++ b/spec/app/text-mate-theme-spec.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' plist = require 'plist' TextMateTheme = require 'text-mate-theme' Theme = require 'theme' @@ -7,7 +7,7 @@ describe "TextMateTheme", -> [theme, themePath] = [] beforeEach -> - themePath = fs.resolveOnLoadPath(fs.join('fixtures', 'test.tmTheme')) + themePath = fsUtils.resolveOnLoadPath(fsUtils.join('fixtures', 'test.tmTheme')) theme = Theme.load(themePath) afterEach -> diff --git a/spec/app/theme-spec.coffee b/spec/app/theme-spec.coffee index 86d703b9d..b447a8cf1 100644 --- a/spec/app/theme-spec.coffee +++ b/spec/app/theme-spec.coffee @@ -1,5 +1,5 @@ $ = require 'jquery' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Theme = require 'theme' describe "@load(name)", -> @@ -15,7 +15,7 @@ describe "@load(name)", -> it "applies the theme's stylesheet to the current window", -> expect($(".editor").css("background-color")).not.toBe("rgb(20, 20, 20)") - themePath = fs.resolveOnLoadPath(fs.join('fixtures', 'test.tmTheme')) + themePath = fsUtils.resolveOnLoadPath(fsUtils.join('fixtures', 'test.tmTheme')) theme = Theme.load(themePath) expect($(".editor").css("background-color")).toBe("rgb(20, 20, 20)") diff --git a/spec/app/window-spec.coffee b/spec/app/window-spec.coffee index 52c095904..c27a7a31e 100644 --- a/spec/app/window-spec.coffee +++ b/spec/app/window-spec.coffee @@ -1,5 +1,5 @@ $ = require 'jquery' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' {less} = require 'less' describe "Window", -> @@ -70,7 +70,7 @@ describe "Window", -> element = $('head style[id*="css.css"]') expect(element.attr('id')).toBe cssPath - expect(element.text()).toBe fs.read(cssPath) + expect(element.text()).toBe fsUtils.read(cssPath) # doesn't append twice requireStylesheet(cssPath) @@ -112,7 +112,7 @@ describe "Window", -> describe ".removeStylesheet(path)", -> it "removes styling applied by given stylesheet path", -> - cssPath = require.resolve(fs.join("fixtures", "css.css")) + cssPath = require.resolve(fsUtils.join("fixtures", "css.css")) expect($(document.body).css('font-weight')).not.toBe("bold") requireStylesheet(cssPath) @@ -159,14 +159,14 @@ describe "Window", -> commandPath = '/tmp/installed-atom-command/atom' afterEach -> - fs.remove(commandPath) if fs.exists(commandPath) + fsUtils.remove(commandPath) if fsUtils.exists(commandPath) describe "when the command path doesn't exist", -> it "copies atom.sh to the specified path", -> - expect(fs.exists(commandPath)).toBeFalsy() + expect(fsUtils.exists(commandPath)).toBeFalsy() window.installAtomCommand(commandPath) - expect(fs.exists(commandPath)).toBeTruthy() - expect(fs.read(commandPath).length).toBeGreaterThan 1 + expect(fsUtils.exists(commandPath)).toBeTruthy() + expect(fsUtils.read(commandPath).length).toBeGreaterThan 1 describe ".deserialize(state)", -> class Foo diff --git a/spec/fixtures/packages/package-with-activation-events/index.coffee b/spec/fixtures/packages/package-with-activation-events/index.coffee index 91f2230b1..44704fa79 100644 --- a/spec/fixtures/packages/package-with-activation-events/index.coffee +++ b/spec/fixtures/packages/package-with-activation-events/index.coffee @@ -10,5 +10,4 @@ module.exports = activate: -> @activateCallCount++ rootView.getActiveView()?.command 'activation-event', => - console.log "ACTIVATION EVENT" @activationEventCallCount++ diff --git a/spec/fixtures/packages/package-with-config-defaults/index.coffee b/spec/fixtures/packages/package-with-config-defaults/index.coffee index 5e0b1eed6..554c6c5eb 100644 --- a/spec/fixtures/packages/package-with-config-defaults/index.coffee +++ b/spec/fixtures/packages/package-with-config-defaults/index.coffee @@ -1,3 +1,5 @@ module.exports = configDefaults: numbers: { one: 1, two: 2 } + + activate: -> # no-op diff --git a/spec/fixtures/packages/package-with-main/main-module.coffee b/spec/fixtures/packages/package-with-main/main-module.coffee index 46920ab78..825eb4055 100644 --- a/spec/fixtures/packages/package-with-main/main-module.coffee +++ b/spec/fixtures/packages/package-with-main/main-module.coffee @@ -1,2 +1,2 @@ module.exports = -activate: -> \ No newline at end of file +activate: -> diff --git a/spec/jasmine-helper.coffee b/spec/jasmine-helper.coffee index fb6175ae0..86a8bb625 100644 --- a/spec/jasmine-helper.coffee +++ b/spec/jasmine-helper.coffee @@ -1,8 +1,8 @@ window.nakedLoad = (file) -> - fs = require 'fs-utils' + fsUtils = require 'fs-utils' file = require.resolve(file) - code = fs.read(file) - if fs.extension(file) is '.coffee' + code = fsUtils.read(file) + if fsUtils.extension(file) is '.coffee' require('coffee-script').eval(code, filename: file) else window.eval("#{code}\n//@ sourceURL=#{file}") diff --git a/spec/spec-helper.coffee b/spec/spec-helper.coffee index 0475902a7..d4dcac2cb 100644 --- a/spec/spec-helper.coffee +++ b/spec/spec-helper.coffee @@ -12,11 +12,11 @@ Directory = require 'directory' File = require 'file' Editor = require 'editor' TokenizedBuffer = require 'tokenized-buffer' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' RootView = require 'root-view' Git = require 'git' requireStylesheet "jasmine" -fixturePackagesPath = fs.resolveOnLoadPath('fixtures/packages') +fixturePackagesPath = fsUtils.resolveOnLoadPath('fixtures/packages') config.packageDirPaths.unshift(fixturePackagesPath) keymap.loadBundledKeymaps() [bindingSetsToRestore, bindingSetsByFirstKeystrokeToRestore] = [] @@ -30,7 +30,7 @@ jasmine.getEnv().defaultTimeoutInterval = 5000 beforeEach -> jQuery.fx.off = true - window.project = new Project(fs.resolveOnLoadPath('fixtures')) + window.project = new Project(fsUtils.resolveOnLoadPath('fixtures')) window.git = Git.open(project.getPath()) window.project.on 'path-changed', -> window.git?.destroy() @@ -126,7 +126,7 @@ addCustomMatchers = (spec) -> toExistOnDisk: (expected) -> notText = this.isNot and " not" or "" @message = -> return "Expected path '" + @actual + "'" + notText + " to exist." - fs.exists(@actual) + fsUtils.exists(@actual) window.keyIdentifierForKey = (key) -> if key.length > 1 # named key @@ -241,5 +241,5 @@ $.fn.textInput = (data) -> event = jQuery.event.fix(event) $(this).trigger(event) -unless fs.md5ForPath(require.resolve('fixtures/sample.js')) == "dd38087d0d7e3e4802a6d3f9b9745f2b" +unless fsUtils.md5ForPath(require.resolve('fixtures/sample.js')) == "dd38087d0d7e3e4802a6d3f9b9745f2b" throw new Error("Sample.js is modified") diff --git a/spec/spec-suite.coffee b/spec/spec-suite.coffee index 0c7ebc37e..7fc7cdadd 100644 --- a/spec/spec-suite.coffee +++ b/spec/spec-suite.coffee @@ -1,15 +1,15 @@ require 'window' measure 'spec suite require time', -> - fs = require 'fs-utils' + fsUtils = require 'fs-utils' require 'spec-helper' # Run core specs - for path in fs.listTree(fs.resolveOnLoadPath("spec")) when /-spec\.coffee$/.test path + for path in fsUtils.listTree(fsUtils.resolveOnLoadPath("spec")) when /-spec\.coffee$/.test path require path # Run extension specs for packageDirPath in config.packageDirPaths - for packagePath in fs.list(packageDirPath) - for path in fs.listTree(fs.join(packagePath, "spec")) when /-spec\.coffee$/.test path + for packagePath in fsUtils.list(packageDirPath) + for path in fsUtils.listTree(fsUtils.join(packagePath, "spec")) when /-spec\.coffee$/.test path require path diff --git a/spec/stdlib/fs-utils-spec.coffee b/spec/stdlib/fs-utils-spec.coffee index 5317be474..8d2204a8b 100644 --- a/spec/stdlib/fs-utils-spec.coffee +++ b/spec/stdlib/fs-utils-spec.coffee @@ -1,95 +1,95 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' -describe "fs", -> +describe "fsUtils", -> describe ".read(path)", -> it "return contents of file", -> - expect(fs.read(require.resolve("fixtures/sample.txt"))).toBe "Some text.\n" + expect(fsUtils.read(require.resolve("fixtures/sample.txt"))).toBe "Some text.\n" it "does not through an exception when the path is a binary file", -> - expect(-> fs.read(require.resolve("fixtures/binary-file.png"))).not.toThrow() + expect(-> fsUtils.read(require.resolve("fixtures/binary-file.png"))).not.toThrow() describe ".isFile(path)", -> - fixturesDir = fs.resolveOnLoadPath('fixtures') + fixturesDir = fsUtils.resolveOnLoadPath('fixtures') it "returns true with a file path", -> - expect(fs.isFile(fs.join(fixturesDir, 'sample.js'))).toBe true + expect(fsUtils.isFile(fsUtils.join(fixturesDir, 'sample.js'))).toBe true it "returns false with a directory path", -> - expect(fs.isFile(fixturesDir)).toBe false + expect(fsUtils.isFile(fixturesDir)).toBe false it "returns false with a non-existent path", -> - expect(fs.isFile(fs.join(fixturesDir, 'non-existent'))).toBe false - expect(fs.isFile(null)).toBe false + expect(fsUtils.isFile(fsUtils.join(fixturesDir, 'non-existent'))).toBe false + expect(fsUtils.isFile(null)).toBe false describe ".directory(path)", -> describe "when called with a file path", -> it "returns the path to the directory", -> - expect(fs.directory(fs.resolveOnLoadPath('fixtures/dir/a'))).toBe fs.resolveOnLoadPath('fixtures/dir') + expect(fsUtils.directory(fsUtils.resolveOnLoadPath('fixtures/dir/a'))).toBe fsUtils.resolveOnLoadPath('fixtures/dir') describe "when called with a directory path", -> it "return the path it was given", -> - expect(fs.directory("/a/b/c")).toBe "/a/b" - expect(fs.directory("/a")).toBe "" - expect(fs.directory("a")).toBe "" - expect(fs.directory("/a/b/c++")).toBe "/a/b" + expect(fsUtils.directory("/a/b/c")).toBe "/a/b" + expect(fsUtils.directory("/a")).toBe "" + expect(fsUtils.directory("a")).toBe "" + expect(fsUtils.directory("/a/b/c++")).toBe "/a/b" describe ".base(path, ext)", -> describe "when called with an extension", -> it "return the base name without the extension when the path has the given extension", -> - expect(fs.base("/a/b/c.txt", '.txt')).toBe "c" - expect(fs.base("/a/b/c.txt", '.txt2')).toBe "c.txt" - expect(fs.base("/a/b/c.+", '.+')).toBe "c" + expect(fsUtils.base("/a/b/c.txt", '.txt')).toBe "c" + expect(fsUtils.base("/a/b/c.txt", '.txt2')).toBe "c.txt" + expect(fsUtils.base("/a/b/c.+", '.+')).toBe "c" describe ".exists(path)", -> it "returns true when path exsits", -> - expect(fs.exists(fs.resolveOnLoadPath('fixtures'))).toBe true + expect(fsUtils.exists(fsUtils.resolveOnLoadPath('fixtures'))).toBe true it "returns false when path doesn't exsit", -> - expect(fs.exists(fs.resolveOnLoadPath("fixtures") + "/-nope-does-not-exist")).toBe false - expect(fs.exists("")).toBe false - expect(fs.exists(null)).toBe false + expect(fsUtils.exists(fsUtils.resolveOnLoadPath("fixtures") + "/-nope-does-not-exist")).toBe false + expect(fsUtils.exists("")).toBe false + expect(fsUtils.exists(null)).toBe false describe ".join(paths...)", -> it "concatenates the given paths with the directory separator", -> - expect(fs.join('a')).toBe 'a' - expect(fs.join('a', 'b', 'c')).toBe 'a/b/c' - expect(fs.join('/a/b/', 'c', 'd')).toBe '/a/b/c/d' - expect(fs.join('a', 'b/c/', 'd/')).toBe 'a/b/c/d/' + expect(fsUtils.join('a')).toBe 'a' + expect(fsUtils.join('a', 'b', 'c')).toBe 'a/b/c' + expect(fsUtils.join('/a/b/', 'c', 'd')).toBe '/a/b/c/d' + expect(fsUtils.join('a', 'b/c/', 'd/')).toBe 'a/b/c/d/' describe ".split(path)", -> it "returns path components", -> - expect(fs.split("/a/b/c.txt")).toEqual ["", "a", "b", "c.txt"] - expect(fs.split("a/b/c.txt")).toEqual ["a", "b", "c.txt"] + expect(fsUtils.split("/a/b/c.txt")).toEqual ["", "a", "b", "c.txt"] + expect(fsUtils.split("a/b/c.txt")).toEqual ["a", "b", "c.txt"] describe ".extension(path)", -> it "returns the extension of a file", -> - expect(fs.extension("a/b/corey.txt")).toBe '.txt' - expect(fs.extension("a/b/corey.txt.coffee")).toBe '.coffee' + expect(fsUtils.extension("a/b/corey.txt")).toBe '.txt' + expect(fsUtils.extension("a/b/corey.txt.coffee")).toBe '.coffee' it "returns an empty string for paths without an extension", -> - expect(fs.extension("a/b.not-extension/a-dir")).toBe '' + expect(fsUtils.extension("a/b.not-extension/a-dir")).toBe '' describe ".makeTree(path)", -> beforeEach -> - fs.remove("/tmp/a") if fs.exists("/tmp/a") + fsUtils.remove("/tmp/a") if fsUtils.exists("/tmp/a") it "creates all directories in path including any missing parent directories", -> - fs.makeTree("/tmp/a/b/c") - expect(fs.exists("/tmp/a/b/c")).toBeTruthy() + fsUtils.makeTree("/tmp/a/b/c") + expect(fsUtils.exists("/tmp/a/b/c")).toBeTruthy() describe ".traverseTreeSync(path, onFile, onDirectory)", -> fixturesDir = null beforeEach -> - fixturesDir = fs.resolveOnLoadPath('fixtures') + fixturesDir = fsUtils.resolveOnLoadPath('fixtures') it "calls fn for every path in the tree at the given path", -> paths = [] onPath = (path) -> paths.push(path) true - fs.traverseTreeSync fixturesDir, onPath, onPath - expect(paths).toEqual fs.listTree(fixturesDir) + fsUtils.traverseTreeSync fixturesDir, onPath, onPath + expect(paths).toEqual fsUtils.listTree(fixturesDir) it "does not recurse into a directory if it is pruned", -> paths = [] @@ -99,43 +99,43 @@ describe "fs", -> else paths.push(path) true - fs.traverseTreeSync fixturesDir, onPath, onPath + fsUtils.traverseTreeSync fixturesDir, onPath, onPath expect(paths.length).toBeGreaterThan 0 for path in paths expect(path).not.toMatch /\/dir\// it "returns entries if path is a symlink", -> - symlinkPath = fs.join(fixturesDir, 'symlink-to-dir') + symlinkPath = fsUtils.join(fixturesDir, 'symlink-to-dir') symlinkPaths = [] onSymlinkPath = (path) -> symlinkPaths.push(path.substring(symlinkPath.length + 1)) - regularPath = fs.join(fixturesDir, 'dir') + regularPath = fsUtils.join(fixturesDir, 'dir') paths = [] onPath = (path) -> paths.push(path.substring(regularPath.length + 1)) - fs.traverseTreeSync(symlinkPath, onSymlinkPath, onSymlinkPath) - fs.traverseTreeSync(regularPath, onPath, onPath) + fsUtils.traverseTreeSync(symlinkPath, onSymlinkPath, onSymlinkPath) + fsUtils.traverseTreeSync(regularPath, onPath, onPath) expect(symlinkPaths).toEqual(paths) describe ".md5ForPath(path)", -> it "returns the MD5 hash of the file at the given path", -> - expect(fs.md5ForPath(require.resolve('fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b' + expect(fsUtils.md5ForPath(require.resolve('fixtures/sample.js'))).toBe 'dd38087d0d7e3e4802a6d3f9b9745f2b' describe ".list(path, extensions)", -> it "returns the absolute paths of entries within the given directory", -> - paths = fs.list(project.getPath()) + paths = fsUtils.list(project.getPath()) expect(paths).toContain project.resolve('css.css') expect(paths).toContain project.resolve('coffee.coffee') expect(paths).toContain project.resolve('two-hundred.txt') it "returns an empty array for paths that aren't directories or don't exist", -> - expect(fs.list(project.resolve('sample.js'))).toEqual [] - expect(fs.list('/non/existent/directory')).toEqual [] + expect(fsUtils.list(project.resolve('sample.js'))).toEqual [] + expect(fsUtils.list('/non/existent/directory')).toEqual [] it "can filter the paths by an optional array of file extensions", -> - paths = fs.list(project.getPath(), ['.css', 'coffee']) + paths = fsUtils.list(project.getPath(), ['.css', 'coffee']) expect(paths).toContain project.resolve('css.css') expect(paths).toContain project.resolve('coffee.coffee') expect(path).toMatch /(css|coffee)$/ for path in paths @@ -145,7 +145,7 @@ describe "fs", -> it "calls the callback with the absolute paths of entries within the given directory", -> waitsFor (done) -> - fs.listAsync project.getPath(), (err, result) -> + fsUtils.listAsync project.getPath(), (err, result) -> paths = result done() runs -> @@ -155,7 +155,7 @@ describe "fs", -> it "can filter the paths by an optional array of file extensions", -> waitsFor (done) -> - fs.listAsync project.getPath(), ['css', '.coffee'], (err, result) -> + fsUtils.listAsync project.getPath(), ['css', '.coffee'], (err, result) -> paths = result done() runs -> diff --git a/src/app/atom-theme.coffee b/src/app/atom-theme.coffee index 3fab3f9e7..c679298a1 100644 --- a/src/app/atom-theme.coffee +++ b/src/app/atom-theme.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Theme = require 'theme' CSON = require 'cson' @@ -9,17 +9,17 @@ class AtomTheme extends Theme @stylesheets[stylesheetPath] = window.loadStylesheet(stylesheetPath) load: -> - if fs.extension(@path) in ['.css', '.less'] + if fsUtils.extension(@path) in ['.css', '.less'] @loadStylesheet(@path) else - metadataPath = fs.resolveExtension(fs.join(@path, 'package'), ['cson', 'json']) - if fs.isFile(metadataPath) + metadataPath = fsUtils.resolveExtension(fsUtils.join(@path, 'package'), ['cson', 'json']) + if fsUtils.isFile(metadataPath) stylesheetNames = CSON.readObject(metadataPath)?.stylesheets if stylesheetNames for name in stylesheetNames - filename = fs.resolveExtension(fs.join(@path, name), ['.css', '.less', '']) + filename = fsUtils.resolveExtension(fsUtils.join(@path, name), ['.css', '.less', '']) @loadStylesheet(filename) else - @loadStylesheet(stylesheetPath) for stylesheetPath in fs.list(@path, ['.css', '.less']) + @loadStylesheet(stylesheetPath) for stylesheetPath in fsUtils.list(@path, ['.css', '.less']) super diff --git a/src/app/atom.coffee b/src/app/atom.coffee index 6294b8961..debc9b02f 100644 --- a/src/app/atom.coffee +++ b/src/app/atom.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' Package = require 'package' TextMatePackage = require 'text-mate-package' @@ -74,9 +74,9 @@ _.extend atom, throw new Error("Could not resolve '#{id}' to a package path") resolvePackagePath: _.memoize (id) -> - return id if fs.isDirectory(id) - path = fs.resolve(config.packageDirPaths..., id) - path if fs.isDirectory(path) + return id if fsUtils.isDirectory(id) + path = fsUtils.resolve(config.packageDirPaths..., id) + path if fsUtils.isDirectory(path) getLoadedPackage: (id) -> if path = @resolvePackagePath(id) @@ -90,13 +90,13 @@ _.extend atom, isPackageDisabled: (id) -> if path = @resolvePackagePath(id) - _.include(config.get('core.disabledPackages') ? [], fs.base(path)) + _.include(config.get('core.disabledPackages') ? [], fsUtils.base(path)) getPackagePaths: -> packagePaths = [] for packageDirPath in config.packageDirPaths - for packagePath in fs.list(packageDirPath) - packagePaths.push(packagePath) if fs.isDirectory(packagePath) + for packagePath in fsUtils.list(packageDirPath) + packagePaths.push(packagePath) if fsUtils.isDirectory(packagePath) _.uniq(packagePaths) loadThemes: -> @@ -109,8 +109,8 @@ _.extend atom, @loadedThemes.push Theme.load(name) loadUserStylesheet: -> - userStylesheetPath = fs.resolve(fs.join(config.configDirPath, 'user'), ['css', 'less']) - if fs.isFile(userStylesheetPath) + userStylesheetPath = fsUtils.resolve(fsUtils.join(config.configDirPath, 'user'), ['css', 'less']) + if fsUtils.isFile(userStylesheetPath) userStyleesheetContents = loadStylesheet(userStylesheetPath) applyStylesheet(userStylesheetPath, userStyleesheetContents, 'userTheme') @@ -233,10 +233,12 @@ _.extend atom, null getSavedWindowState: -> - localStorage[window.location.params.pathToOpen] + if pathToOpen = window.location.params.pathToOpen + localStorage[pathToOpen] saveWindowState: -> - localStorage[@getPathToOpen()] = JSON.stringify(@getWindowState()) + if pathToOpen = @getPathToOpen() + localStorage[pathToOpen] = JSON.stringify(@getWindowState()) update: -> @sendMessageToBrowserProcess('update') @@ -244,10 +246,16 @@ _.extend atom, getUpdateStatus: (callback) -> @sendMessageToBrowserProcess('getUpdateStatus', [], callback) + crashMainProcess: -> + @sendMessageToBrowserProcess('crash') + + crashRenderProcess: -> + $native.crash() + requireUserInitScript: -> - userInitScriptPath = fs.join(config.configDirPath, "user.coffee") + userInitScriptPath = fsUtils.join(config.configDirPath, "user.coffee") try - require userInitScriptPath if fs.isFile(userInitScriptPath) + require userInitScriptPath if fsUtils.isFile(userInitScriptPath) catch error console.error "Failed to load `#{userInitScriptPath}`", error.stack, error diff --git a/src/app/binding-set.coffee b/src/app/binding-set.coffee index 3bf87dab8..e9017d1f9 100644 --- a/src/app/binding-set.coffee +++ b/src/app/binding-set.coffee @@ -1,6 +1,6 @@ $ = require 'jquery' _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Specificity = require 'specificity' PEG = require 'pegjs' @@ -17,7 +17,7 @@ class BindingSet name: null constructor: (@selector, commandsByKeystrokes, @index, @name) -> - BindingSet.parser ?= PEG.buildParser(fs.read(require.resolve 'keystroke-pattern.pegjs')) + BindingSet.parser ?= PEG.buildParser(fsUtils.read(require.resolve 'keystroke-pattern.pegjs')) @specificity = Specificity(@selector) @commandsByKeystrokes = @normalizeCommandsByKeystrokes(commandsByKeystrokes) diff --git a/src/app/config.coffee b/src/app/config.coffee index c8d36db6e..79cb4d35e 100644 --- a/src/app/config.coffee +++ b/src/app/config.coffee @@ -1,15 +1,15 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' EventEmitter = require 'event-emitter' CSON = require 'cson' -configDirPath = fs.absolute("~/.atom") -bundledPackagesDirPath = fs.join(resourcePath, "src/packages") -bundledThemesDirPath = fs.join(resourcePath, "themes") -vendoredPackagesDirPath = fs.join(resourcePath, "vendor/packages") -vendoredThemesDirPath = fs.join(resourcePath, "vendor/themes") -userThemesDirPath = fs.join(configDirPath, "themes") -userPackagesDirPath = fs.join(configDirPath, "packages") +configDirPath = fsUtils.absolute("~/.atom") +bundledPackagesDirPath = fsUtils.join(resourcePath, "src/packages") +bundledThemesDirPath = fsUtils.join(resourcePath, "themes") +vendoredPackagesDirPath = fsUtils.join(resourcePath, "vendor/packages") +vendoredThemesDirPath = fsUtils.join(resourcePath, "vendor/themes") +userThemesDirPath = fsUtils.join(configDirPath, "themes") +userPackagesDirPath = fsUtils.join(configDirPath, "packages") module.exports = class Config @@ -26,34 +26,34 @@ class Config core: _.clone(require('root-view').configDefaults) editor: _.clone(require('editor').configDefaults) @settings = {} - @configFilePath = fs.resolve(configDirPath, 'config', ['json', 'cson']) - @configFilePath ?= fs.join(configDirPath, 'config.cson') + @configFilePath = fsUtils.resolve(configDirPath, 'config', ['json', 'cson']) + @configFilePath ?= fsUtils.join(configDirPath, 'config.cson') initializeConfigDirectory: -> - return if fs.exists(@configDirPath) + return if fsUtils.exists(@configDirPath) - fs.makeDirectory(@configDirPath) + fsUtils.makeDirectory(@configDirPath) - templateConfigDirPath = fs.resolve(window.resourcePath, 'dot-atom') + templateConfigDirPath = fsUtils.resolve(window.resourcePath, 'dot-atom') onConfigDirFile = (path) => relativePath = path.substring(templateConfigDirPath.length + 1) - configPath = fs.join(@configDirPath, relativePath) - fs.write(configPath, fs.read(path)) - fs.traverseTreeSync(templateConfigDirPath, onConfigDirFile, (path) -> true) + configPath = fsUtils.join(@configDirPath, relativePath) + fsUtils.write(configPath, fsUtils.read(path)) + fsUtils.traverseTreeSync(templateConfigDirPath, onConfigDirFile, (path) -> true) - configThemeDirPath = fs.join(@configDirPath, 'themes') + configThemeDirPath = fsUtils.join(@configDirPath, 'themes') onThemeDirFile = (path) -> relativePath = path.substring(bundledThemesDirPath.length + 1) - configPath = fs.join(configThemeDirPath, relativePath) - fs.write(configPath, fs.read(path)) - fs.traverseTreeSync(bundledThemesDirPath, onThemeDirFile, (path) -> true) + configPath = fsUtils.join(configThemeDirPath, relativePath) + fsUtils.write(configPath, fsUtils.read(path)) + fsUtils.traverseTreeSync(bundledThemesDirPath, onThemeDirFile, (path) -> true) load: -> @initializeConfigDirectory() @loadUserConfig() loadUserConfig: -> - if fs.exists(@configFilePath) + if fsUtils.exists(@configFilePath) try userConfig = CSON.readObject(@configFilePath) _.extend(@settings, userConfig) diff --git a/src/app/cursor.coffee b/src/app/cursor.coffee index 5708d4bf7..8f1a21d67 100644 --- a/src/app/cursor.coffee +++ b/src/app/cursor.coffee @@ -133,20 +133,20 @@ class Cursor moveToFirstCharacterOfLine: -> position = @getBufferPosition() - range = @getCurrentLineBufferRange() + scanRange = @getCurrentLineBufferRange() newPosition = null - @editSession.scanInRange /^\s*/, range, (match, matchRange) => - newPosition = matchRange.end + @editSession.scanInBufferRange /^\s*/, scanRange, ({range}) => + newPosition = range.end return unless newPosition newPosition = [position.row, 0] if newPosition.isEqual(position) @setBufferPosition(newPosition) skipLeadingWhitespace: -> position = @getBufferPosition() - range = @getCurrentLineBufferRange() + scanRange = @getCurrentLineBufferRange() endOfLeadingWhitespace = null - @editSession.scanInRange /^[ \t]*/, range, (match, matchRange) => - endOfLeadingWhitespace = matchRange.end + @editSession.scanInBufferRange /^[ \t]*/, scanRange, ({range}) => + endOfLeadingWhitespace = range.end @setBufferPosition(endOfLeadingWhitespace) if endOfLeadingWhitespace.isGreaterThan(position) @@ -164,12 +164,12 @@ class Cursor allowPrevious = options.allowPrevious ? true currentBufferPosition = @getBufferPosition() previousNonBlankRow = @editSession.buffer.previousNonBlankRow(currentBufferPosition.row) - range = [[previousNonBlankRow, 0], currentBufferPosition] + scanRange = [[previousNonBlankRow, 0], currentBufferPosition] beginningOfWordPosition = null - @editSession.backwardsScanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => - if matchRange.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious - beginningOfWordPosition = matchRange.start + @editSession.backwardsScanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) => + if range.end.isGreaterThanOrEqual(currentBufferPosition) or allowPrevious + beginningOfWordPosition = range.start if not beginningOfWordPosition?.isEqual(currentBufferPosition) stop() @@ -178,12 +178,12 @@ class Cursor getEndOfCurrentWordBufferPosition: (options = {}) -> allowNext = options.allowNext ? true currentBufferPosition = @getBufferPosition() - range = [currentBufferPosition, @editSession.getEofBufferPosition()] + scanRange = [currentBufferPosition, @editSession.getEofBufferPosition()] endOfWordPosition = null - @editSession.scanInRange (options.wordRegex ? @wordRegExp()), range, (match, matchRange, { stop }) => - if matchRange.start.isLessThanOrEqual(currentBufferPosition) or allowNext - endOfWordPosition = matchRange.end + @editSession.scanInBufferRange (options.wordRegex ? @wordRegExp()), scanRange, ({range, stop}) => + if range.start.isLessThanOrEqual(currentBufferPosition) or allowNext + endOfWordPosition = range.end if not endOfWordPosition?.isEqual(currentBufferPosition) stop() diff --git a/src/app/edit-session.coffee b/src/app/edit-session.coffee index 36884284a..c72fc5302 100644 --- a/src/app/edit-session.coffee +++ b/src/app/edit-session.coffee @@ -8,12 +8,14 @@ EventEmitter = require 'event-emitter' Subscriber = require 'subscriber' Range = require 'range' _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class EditSession registerDeserializer(this) + @version: 1 + @deserialize: (state) -> session = project.buildEditSessionForBuffer(Buffer.deserialize(state.buffer)) if !session? @@ -43,7 +45,7 @@ class EditSession @buffer.retain() @subscribe @buffer, "path-changed", => - @project.setPath(fs.directory(@getPath())) unless @project.getPath()? + @project.setPath(fsUtils.directory(@getPath())) unless @project.getPath()? @trigger "title-changed" @trigger "path-changed" @subscribe @buffer, "contents-conflicted", => @trigger "contents-conflicted" @@ -55,21 +57,21 @@ class EditSession @subscribe @displayBuffer, "changed", (e) => @trigger 'screen-lines-changed', e - @subscribe syntax, 'grammars-loaded', => @reloadGrammar() + @languageMode.on 'grammar-changed', => @handleGrammarChange() getViewClass: -> require 'editor' getTitle: -> if path = @getPath() - fs.base(path) + fsUtils.base(path) else 'untitled' getLongTitle: -> if path = @getPath() - fileName = fs.base(path) - directory = fs.base(fs.directory(path)) + fileName = fsUtils.base(path) + directory = fsUtils.base(fsUtils.directory(path)) "#{fileName} - #{directory}" else 'untitled' @@ -81,12 +83,14 @@ class EditSession @buffer.release() selection.destroy() for selection in @getSelections() @displayBuffer.destroy() + @languageMode.destroy() @project?.removeEditSession(this) @trigger 'destroyed' @off() serialize: -> deserializer: 'EditSession' + version: @constructor.version buffer: @buffer.serialize() scrollTop: @getScrollTop() scrollLeft: @getScrollLeft() @@ -160,8 +164,8 @@ class EditSession bufferRangeForBufferRow: (row, options) -> @buffer.rangeForRow(row, options) lineForBufferRow: (row) -> @buffer.lineForRow(row) lineLengthForBufferRow: (row) -> @buffer.lineLengthForRow(row) - scanInRange: (args...) -> @buffer.scanInRange(args...) - backwardsScanInRange: (args...) -> @buffer.backwardsScanInRange(args...) + scanInBufferRange: (args...) -> @buffer.scanInRange(args...) + backwardsScanInBufferRange: (args...) -> @buffer.backwardsScanInRange(args...) isModified: -> @buffer.isModified() hasEditors: -> @buffer.hasEditors() @@ -242,7 +246,7 @@ class EditSession normalizeTabsInBufferRange: (bufferRange) -> return unless @softTabs - @scanInRange /\t/, bufferRange, (match, range, {replace}) => replace(@getTabText()) + @scanInBufferRange /\t/, bufferRange, ({replace}) => replace(@getTabText()) cutToEndOfLine: -> maintainPasteboard = false @@ -843,17 +847,14 @@ class EditSession getGrammar: -> @languageMode.grammar setGrammar: (grammar) -> - @languageMode.grammar = grammar - @handleGrammarChange() + @languageMode.setGrammar(grammar) reloadGrammar: -> - @handleGrammarChange() if @languageMode.reloadGrammar() + @languageMode.reloadGrammar() handleGrammarChange: -> @unfoldAll() - @displayBuffer.tokenizedBuffer.resetScreenLines() @trigger 'grammar-changed' - true getDebugSnapshot: -> [ diff --git a/src/app/editor.coffee b/src/app/editor.coffee index 53f58e5e8..3a505257e 100644 --- a/src/app/editor.coffee +++ b/src/app/editor.coffee @@ -6,7 +6,7 @@ Range = require 'range' EditSession = require 'edit-session' CursorView = require 'cursor-view' SelectionView = require 'selection-view' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' $ = require 'jquery' _ = require 'underscore' @@ -319,8 +319,8 @@ class Editor extends View lineForBufferRow: (row) -> @getBuffer().lineForRow(row) lineLengthForBufferRow: (row) -> @getBuffer().lineLengthForRow(row) rangeForBufferRow: (row) -> @getBuffer().rangeForRow(row) - scanInRange: (args...) -> @getBuffer().scanInRange(args...) - backwardsScanInRange: (args...) -> @getBuffer().backwardsScanInRange(args...) + scanInBufferRange: (args...) -> @getBuffer().scanInRange(args...) + backwardsScanInBufferRange: (args...) -> @getBuffer().backwardsScanInRange(args...) configure: -> @observeConfig 'editor.showLineNumbers', (showLineNumbers) => @gutter.setShowLineNumbers(showLineNumbers) @@ -1102,7 +1102,7 @@ class Editor extends View range.detach() leftPixels - pixelOffsetForScreenPosition: (position) -> + pixelOffsUtilsetForScreenPosition: (position) -> {top, left} = @pixelPositionForScreenPosition(position) offset = @renderedLines.offset() {top: top + offset.top, left: left + offset.left} @@ -1151,16 +1151,9 @@ class Editor extends View setGrammar: (grammar) -> throw new Error("Only mini-editors can explicity set their grammar") unless @mini @activeEditSession.setGrammar(grammar) - @handleGrammarChange() reloadGrammar: -> - grammarChanged = @activeEditSession.reloadGrammar() - @handleGrammarChange() if grammarChanged - grammarChanged - - handleGrammarChange: -> - @clearRenderedLines() - @updateDisplay() + @activeEditSession.reloadGrammar() bindToKeyedEvent: (key, event, callback) -> binding = {} @@ -1185,7 +1178,7 @@ class Editor extends View saveDebugSnapshot: -> atom.showSaveDialog (path) => - fs.write(path, @getDebugSnapshot()) if path + fsUtils.write(path, @getDebugSnapshot()) if path getDebugSnapshot: -> [ diff --git a/src/app/git.coffee b/src/app/git.coffee index 21128dfbd..9bbe63117 100644 --- a/src/app/git.coffee +++ b/src/app/git.coffee @@ -1,5 +1,5 @@ _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' Subscriber = require 'subscriber' EventEmitter = require 'event-emitter' RepositoryStatusTask = require 'repository-status-task' @@ -48,7 +48,7 @@ class Git refreshIndex: -> @getRepo().refreshIndex() getPath: -> - @path ?= fs.absolute(@getRepo().getPath()) + @path ?= fsUtils.absolute(@getRepo().getPath()) destroy: -> if @statusTask? diff --git a/src/app/keymap.coffee b/src/app/keymap.coffee index 23e585ee7..0cc615726 100644 --- a/src/app/keymap.coffee +++ b/src/app/keymap.coffee @@ -1,6 +1,6 @@ $ = require 'jquery' _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' CSON = require 'cson' BindingSet = require 'binding-set' @@ -32,13 +32,13 @@ class Keymap $(document).command 'open-dev', => atom.openDev() loadBundledKeymaps: -> - @loadDirectory(fs.resolveOnLoadPath('keymaps')) + @loadDirectory(fsUtils.resolveOnLoadPath('keymaps')) loadUserKeymaps: -> - @loadDirectory(fs.join(config.configDirPath, 'keymaps')) + @loadDirectory(fsUtils.join(config.configDirPath, 'keymaps')) loadDirectory: (directoryPath) -> - @load(filePath) for filePath in fs.list(directoryPath, ['.cson', '.json']) + @load(filePath) for filePath in fsUtils.list(directoryPath, ['.cson', '.json']) load: (path) -> @add(path, CSON.readObject(path)) diff --git a/src/app/language-mode.coffee b/src/app/language-mode.coffee index dc13fae18..447cf576a 100644 --- a/src/app/language-mode.coffee +++ b/src/app/language-mode.coffee @@ -2,24 +2,37 @@ Range = require 'range' _ = require 'underscore' require 'underscore-extensions' {OnigRegExp} = require 'oniguruma' +EventEmitter = require 'event-emitter' +Subscriber = require 'subscriber' module.exports = class LanguageMode buffer = null grammar = null editSession = null + currentGrammarScore: null constructor: (@editSession) -> @buffer = @editSession.buffer @reloadGrammar() + @subscribe syntax, 'grammar-added', (grammar) => + newScore = grammar.getScore(@buffer.getPath(), @buffer.getText()) + @setGrammar(grammar, newScore) if newScore > @currentGrammarScore + + destroy: -> + @unsubscribe() + + setGrammar: (grammar, score) -> + return if grammar is @grammar + @grammar = grammar + @currentGrammarScore = score ? grammar.getScore(@buffer.getPath(), @buffer.getText()) + @trigger 'grammar-changed', grammar reloadGrammar: -> - path = @buffer.getPath() - pathContents = @buffer.cachedDiskContents - previousGrammar = @grammar - @grammar = syntax.selectGrammar(path, pathContents) - throw new Error("No grammar found for path: #{path}") unless @grammar - previousGrammar isnt @grammar + if grammar = syntax.selectGrammar(@buffer.getPath(), @buffer.getText()) + @setGrammar(grammar) + else + throw new Error("No grammar found for path: #{path}") toggleLineCommentsForBufferRows: (start, end) -> scopes = @editSession.scopesForBufferPosition([start, 0]) @@ -158,3 +171,6 @@ class LanguageMode foldEndRegexForScopes: (scopes) -> if foldEndPattern = syntax.getProperty(scopes, 'editor.foldEndPattern') new OnigRegExp(foldEndPattern) + +_.extend LanguageMode.prototype, EventEmitter +_.extend LanguageMode.prototype, Subscriber diff --git a/src/app/null-grammar.coffee b/src/app/null-grammar.coffee index 21c7877a2..2f2a37108 100644 --- a/src/app/null-grammar.coffee +++ b/src/app/null-grammar.coffee @@ -5,5 +5,7 @@ class NullGrammar name: 'Null Grammar' scopeName: 'text.plain.null-grammar' + getScore: -> 0 + tokenizeLine: (line) -> { tokens: [new Token(value: line, scopes: ['null-grammar.text.plain'])] } diff --git a/src/app/package.coffee b/src/app/package.coffee index c03e082d5..b3f3333e0 100644 --- a/src/app/package.coffee +++ b/src/app/package.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class Package @@ -20,4 +20,4 @@ class Package path: null constructor: (@path) -> - @name = fs.base(@path) + @name = fsUtils.base(@path) diff --git a/src/app/project.coffee b/src/app/project.coffee index 81bf19c76..bc4c6187e 100644 --- a/src/app/project.coffee +++ b/src/app/project.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' $ = require 'jquery' Range = require 'range' @@ -41,7 +41,7 @@ class Project @rootDirectory?.off() if path? - directory = if fs.isDirectory(path) then path else fs.directory(path) + directory = if fsUtils.isDirectory(path) then path else fsUtils.directory(path) @rootDirectory = new Directory(directory) else @rootDirectory = null @@ -56,7 +56,7 @@ class Project paths = [] onFile = (path) => paths.push(path) unless @isPathIgnored(path) onDirectory = -> true - fs.traverseTreeSync(@getPath(), onFile, onDirectory) + fsUtils.traverseTreeSync(@getPath(), onFile, onDirectory) deferred.resolve(paths) deferred.promise() @@ -68,11 +68,11 @@ class Project @ignoreRepositoryPath(path) ignoreRepositoryPath: (path) -> - config.get("core.hideGitIgnoredFiles") and git?.isPathIgnored(fs.join(@getPath(), path)) + config.get("core.hideGitIgnoredFiles") and git?.isPathIgnored(fsUtils.join(@getPath(), path)) resolve: (filePath) -> - filePath = fs.join(@getPath(), filePath) unless filePath[0] == '/' - fs.absolute filePath + filePath = fsUtils.join(@getPath(), filePath) unless filePath[0] == '/' + fsUtils.absolute filePath relativize: (fullPath) -> return fullPath unless fullPath.lastIndexOf(@getPath()) is 0 @@ -191,8 +191,9 @@ class Project readPath(line) if state is 'readingPath' readLine(line) if state is 'readingLines' - command = require.resolve('ag') + command = require.resolve('nak') args = ['--ackmate', regex.source, @getPath()] + args.unshift("--addVCSIgnores") if config.get('core.excludeVcsIgnoredPaths') new BufferedProcess({command, args, stdout, exit}) deferred diff --git a/src/app/repository-status-handler.coffee b/src/app/repository-status-handler.coffee index 7816cf383..05f866a96 100644 --- a/src/app/repository-status-handler.coffee +++ b/src/app/repository-status-handler.coffee @@ -1,5 +1,5 @@ Git = require 'git-utils' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = loadStatuses: (path) -> @@ -8,7 +8,7 @@ module.exports = workingDirectoryPath = repo.getWorkingDirectory() statuses = {} for path, status of repo.getStatus() - statuses[fs.join(workingDirectoryPath, path)] = status + statuses[fsUtils.join(workingDirectoryPath, path)] = status upstream = repo.getAheadBehindCount() repo.release() else diff --git a/src/app/root-view.coffee b/src/app/root-view.coffee index fc1fdb4e1..a8a2ada13 100644 --- a/src/app/root-view.coffee +++ b/src/app/root-view.coffee @@ -1,6 +1,6 @@ $ = require 'jquery' {$$} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' _ = require 'underscore' {View} = require 'space-pen' @@ -82,7 +82,7 @@ class RootView extends View @getActivePane().focus() false else - @setTitle(null) + @updateTitle() focusableChild = this.find("[tabindex=-1]:visible:first") if focusableChild.length focusableChild.focus() @@ -115,7 +115,7 @@ class RootView extends View if item = @getActivePaneItem() @setTitle("#{item.getTitle?() ? 'untitled'} - #{projectPath}") else - @setTitle(projectPath) + @setTitle("atom - #{projectPath}") else @setTitle('untitled') @@ -174,4 +174,3 @@ class RootView extends View eachBuffer: (callback) -> project.eachBuffer(callback) - diff --git a/src/app/syntax.coffee b/src/app/syntax.coffee index 7ab711a14..3aebccbb8 100644 --- a/src/app/syntax.coffee +++ b/src/app/syntax.coffee @@ -2,11 +2,9 @@ _ = require 'underscore' jQuery = require 'jquery' Specificity = require 'specificity' {$$} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' EventEmitter = require 'event-emitter' NullGrammar = require 'null-grammar' -nodePath = require 'path' -pathSplitRegex = new RegExp("[#{nodePath.sep}.]") module.exports = class Syntax @@ -18,27 +16,24 @@ class Syntax syntax constructor: -> - @grammars = [] - @grammarsByFileType = {} + @nullGrammar = new NullGrammar + @grammars = [@nullGrammar] @grammarsByScopeName = {} @grammarOverridesByPath = {} @scopedPropertiesIndex = 0 @scopedProperties = [] - @nullGrammar = new NullGrammar serialize: -> { deserializer: @constructor.name, @grammarOverridesByPath } addGrammar: (grammar) -> @grammars.push(grammar) - @grammarsByFileType[fileType] = grammar for fileType in grammar.fileTypes @grammarsByScopeName[grammar.scopeName] = grammar + @trigger 'grammar-added', grammar removeGrammar: (grammar) -> - if _.include(@grammars, grammar) - _.remove(@grammars, grammar) - delete @grammarsByFileType[fileType] for fileType in grammar.fileTypes - delete @grammarsByScopeName[grammar.scopeName] + _.remove(@grammars, grammar) + delete @grammarsByScopeName[grammar.scopeName] setGrammarOverrideForPath: (path, scopeName) -> @grammarOverridesByPath[path] = scopeName @@ -50,51 +45,10 @@ class Syntax @grammarOverridesByPath = {} selectGrammar: (filePath, fileContents) -> - - return @grammarsByFileType["txt"] ? @nullGrammar unless filePath - - @grammarOverrideForPath(filePath) ? - @grammarByFirstLineRegex(filePath, fileContents) ? - @grammarByPath(filePath) ? - @grammarsByFileType["txt"] ? - @nullGrammar + _.max @grammars, (grammar) -> grammar.getScore(filePath, fileContents) grammarOverrideForPath: (path) -> - @grammarsByScopeName[@grammarOverridesByPath[path]] - - grammarByPath: (path) -> - pathComponents = path.split(pathSplitRegex) - for fileType, grammar of @grammarsByFileType - fileTypeComponents = fileType.split(pathSplitRegex) - pathSuffix = pathComponents[-fileTypeComponents.length..-1] - return grammar if _.isEqual(pathSuffix, fileTypeComponents) - - grammarByFirstLineRegex: (filePath, fileContents) -> - try - fileContents ?= fs.read(filePath) - catch e - return - - return unless fileContents - - lines = fileContents.split('\n') - _.find @grammars, (grammar) -> - regex = grammar.firstLineRegex - return unless regex? - - escaped = false - numberOfNewlinesInRegex = 0 - for character in regex.source - switch character - when '\\' - escaped = !escaped - when 'n' - numberOfNewlinesInRegex++ if escaped - escaped = false - else - escaped = false - - regex.test(lines[0..numberOfNewlinesInRegex].join('\n')) + @grammarOverridesByPath[path] grammarForScopeName: (scopeName) -> @grammarsByScopeName[scopeName] diff --git a/src/app/text-buffer.coffee b/src/app/text-buffer.coffee index 228aa73c5..ea6116a12 100644 --- a/src/app/text-buffer.coffee +++ b/src/app/text-buffer.coffee @@ -1,5 +1,5 @@ _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' File = require 'file' Point = require 'point' Range = require 'range' @@ -37,9 +37,8 @@ class Buffer @lineEndings = [] if path - # throw "Path '#{path}' does not exist" unless fs.exists(path) - if fs.exists(path) - @setPath(path) + throw "Path '#{path}' does not exist" unless fsUtils.exists(path) + @setPath(path) if initialText? @setText(initialText) @updateCachedDiskContents() @@ -406,7 +405,7 @@ class Buffer range = new Range(startPosition, endPosition) keepLooping = true replacementText = null - iterator(match, range, { stop, replace }) + iterator({match, range, stop, replace }) if replacementText? @change(range, replacementText) diff --git a/src/app/text-mate-grammar.coffee b/src/app/text-mate-grammar.coffee index 03b35b6ca..95d52db1c 100644 --- a/src/app/text-mate-grammar.coffee +++ b/src/app/text-mate-grammar.coffee @@ -1,24 +1,25 @@ _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' plist = require 'plist' Token = require 'token' -CSON = require 'cson' {OnigRegExp, OnigScanner} = require 'oniguruma' +nodePath = require 'path' +pathSplitRegex = new RegExp("[#{nodePath.sep}.]") module.exports = class TextMateGrammar @readFromPath: (path) -> - fs.readPlist(path) + fsUtils.readPlist(path) @load: (path, done) -> - fs.readObjectAsync path, (err, object) -> + fsUtils.readObjectAsync path, (err, object) -> if err done(err) else done(null, new TextMateGrammar(object)) @loadSync: (path) -> - new TextMateGrammar(fs.readObject(path)) + new TextMateGrammar(fsUtils.readObject(path)) name: null fileTypes: null @@ -38,6 +39,43 @@ class TextMateGrammar data = {patterns: [data], tempName: name} if data.begin? or data.match? @repository[name] = new Rule(this, data) + getScore: (path, contents) -> + contents = fsUtils.read(path) if not contents? and fsUtils.isFile(path) + + if syntax.grammarOverrideForPath(path) is @scopeName + 3 + else if @matchesContents(contents) + 2 + else if @matchesPath(path) + 1 + else + -1 + + matchesContents: (contents) -> + return false unless contents? and @firstLineRegex? + + escaped = false + numberOfNewlinesInRegex = 0 + for character in @firstLineRegex.source + switch character + when '\\' + escaped = !escaped + when 'n' + numberOfNewlinesInRegex++ if escaped + escaped = false + else + escaped = false + lines = contents.split('\n') + @firstLineRegex.test(lines[0..numberOfNewlinesInRegex].join('\n')) + + matchesPath: (path) -> + return false unless path? + pathComponents = path.split(pathSplitRegex) + _.find @fileTypes, (fileType) -> + fileTypeComponents = fileType.split(pathSplitRegex) + pathSuffix = pathComponents[-fileTypeComponents.length..-1] + _.isEqual(pathSuffix, fileTypeComponents) + tokenizeLine: (line, ruleStack=[@initialRule], firstLine=false) -> originalRuleStack = ruleStack ruleStack = new Array(ruleStack...) # clone ruleStack diff --git a/src/app/text-mate-package.coffee b/src/app/text-mate-package.coffee index a6ef9b8fd..10156f4ba 100644 --- a/src/app/text-mate-package.coffee +++ b/src/app/text-mate-package.coffee @@ -13,7 +13,6 @@ class TextMatePackage extends Package @getLoadQueue: -> return @loadQueue if @loadQueue @loadQueue = async.queue (pack, done) -> pack.loadGrammars(done) - @loadQueue.drain = -> syntax.trigger 'grammars-loaded' @loadQueue constructor: -> diff --git a/src/app/text-mate-theme.coffee b/src/app/text-mate-theme.coffee index 2424bc2d3..3054b0633 100644 --- a/src/app/text-mate-theme.coffee +++ b/src/app/text-mate-theme.coffee @@ -1,5 +1,5 @@ _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' plist = require 'plist' Theme = require 'theme' diff --git a/src/app/theme.coffee b/src/app/theme.coffee index 6ca385d66..da038e391 100644 --- a/src/app/theme.coffee +++ b/src/app/theme.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class Theme @@ -8,10 +8,10 @@ class Theme TextMateTheme = require 'text-mate-theme' AtomTheme = require 'atom-theme' - if fs.exists(name) + if fsUtils.exists(name) path = name else - path = fs.resolve(config.themeDirPaths..., name, ['', '.tmTheme', '.css', 'less']) + path = fsUtils.resolve(config.themeDirPaths..., name, ['', '.tmTheme', '.css', 'less']) throw new Error("No theme exists named '#{name}'") unless path diff --git a/src/app/tokenized-buffer.coffee b/src/app/tokenized-buffer.coffee index 70e982e28..f35c94680 100644 --- a/src/app/tokenized-buffer.coffee +++ b/src/app/tokenized-buffer.coffee @@ -23,6 +23,7 @@ class TokenizedBuffer @id = @constructor.idCounter++ @resetScreenLines() @buffer.on "changed.tokenized-buffer#{@id}", (e) => @handleBufferChange(e) + @languageMode.on 'grammar-changed', => @resetScreenLines() resetScreenLines: -> @screenLines = @buildPlaceholderScreenLinesForRows(0, @buffer.getLastRow()) diff --git a/src/app/window.coffee b/src/app/window.coffee index 78fc1bd42..272f91029 100644 --- a/src/app/window.coffee +++ b/src/app/window.coffee @@ -1,8 +1,8 @@ -fs = require 'fs-utils' +fs = require 'fs' +fsUtils = require 'fs-utils' $ = require 'jquery' _ = require 'underscore' {less} = require 'less' -{spawn} = require 'child_process' require 'jquery-extensions' require 'underscore-extensions' require 'space-pen-extensions' @@ -32,14 +32,14 @@ window.setUpEnvironment = -> requireStylesheet 'notification' requireStylesheet 'markdown' - if nativeStylesheetPath = fs.resolveOnLoadPath(process.platform, ['css', 'less']) + if nativeStylesheetPath = fsUtils.resolveOnLoadPath(process.platform, ['css', 'less']) requireStylesheet(nativeStylesheetPath) # This method is only called when opening a real application window window.startup = -> - directory = _.find ['/opt/boxen', '/opt/github', '/usr/local'], (dir) -> fs.isDirectory(dir) + directory = _.find ['/opt/boxen', '/opt/github', '/usr/local'], (dir) -> fsUtils.isDirectory(dir) if directory - installAtomCommand(fs.join(directory, 'bin/atom')) + installAtomCommand(fsUtils.join(directory, 'bin/atom')) else console.warn "Failed to install `atom` binary" @@ -73,18 +73,19 @@ window.shutdown = -> window.git = null window.installAtomCommand = (commandPath) -> - return if fs.exists(commandPath) + return if fsUtils.exists(commandPath) - bundledCommandPath = fs.resolve(window.resourcePath, 'atom.sh') + bundledCommandPath = fsUtils.resolve(window.resourcePath, 'atom.sh') if bundledCommandPath? - fs.write(commandPath, fs.read(bundledCommandPath)) - spawn('chmod', ['u+x', commandPath]) + fsUtils.write(commandPath, fsUtils.read(bundledCommandPath)) + fs.chmod(commandPath, 0o755, commandPath) window.handleWindowEvents = -> $(window).command 'window:toggle-full-screen', => atom.toggleFullScreen() $(window).on 'focus', -> $("body").removeClass('is-blurred') $(window).on 'blur', -> $("body").addClass('is-blurred') $(window).command 'window:close', => confirmClose() + $(window).command 'window:reload', => reload() window.deserializeWindowState = -> RootView = require 'root-view' @@ -99,7 +100,7 @@ window.deserializeWindowState = -> window.project = deserialize(windowState.project) ? new Project(pathToOpen) window.rootView = deserialize(windowState.rootView) ? new RootView - if !windowState.rootView and (!pathToOpen or fs.isFile(pathToOpen)) + if !windowState.rootView and (!pathToOpen or fsUtils.isFile(pathToOpen)) rootView.open(pathToOpen) $(rootViewParentSelector).append(rootView) @@ -113,10 +114,10 @@ window.stylesheetElementForId = (id) -> $("head style[id='#{id}']") window.resolveStylesheet = (path) -> - if fs.extension(path).length > 0 - fs.resolveOnLoadPath(path) + if fsUtils.extension(path).length > 0 + fsUtils.resolveOnLoadPath(path) else - fs.resolveOnLoadPath(path, ['css', 'less']) + fsUtils.resolveOnLoadPath(path, ['css', 'less']) window.requireStylesheet = (path) -> if fullPath = window.resolveStylesheet(path) @@ -126,8 +127,8 @@ window.requireStylesheet = (path) -> throw new Error("Could not find a file at path '#{path}'") window.loadStylesheet = (path) -> - content = fs.read(path) - if fs.extension(path) == '.less' + content = fsUtils.read(path) + if fsUtils.extension(path) == '.less' (new less.Parser).parse content, (e, tree) -> throw new Error(e.message, path, e.line) if e content = tree.toCSS() diff --git a/src/packages/autocomplete/lib/autocomplete-view.coffee b/src/packages/autocomplete/lib/autocomplete-view.coffee index 48948a4fc..e559e7a97 100644 --- a/src/packages/autocomplete/lib/autocomplete-view.coffee +++ b/src/packages/autocomplete/lib/autocomplete-view.coffee @@ -144,7 +144,7 @@ class AutocompleteView extends SelectList lineRange = [[selectionRange.start.row, 0], [selectionRange.end.row, @editor.lineLengthForBufferRow(selectionRange.end.row)]] [prefix, suffix] = ["", ""] - @currentBuffer.scanInRange @wordRegex, lineRange, (match, range, {stop}) -> + @currentBuffer.scanInRange @wordRegex, lineRange, ({match, range, stop}) -> stop() if range.start.isGreaterThan(selectionRange.end) if range.intersectsWith(selectionRange) diff --git a/src/packages/bracket-matcher/lib/bracket-matcher.coffee b/src/packages/bracket-matcher/lib/bracket-matcher.coffee index a08e49e43..18c4c6f55 100644 --- a/src/packages/bracket-matcher/lib/bracket-matcher.coffee +++ b/src/packages/bracket-matcher/lib/bracket-matcher.coffee @@ -122,7 +122,7 @@ module.exports = regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g') endPairPosition = null unpairedCount = 0 - buffer.scanInRange regex, scanRange, (match, range, {stop}) => + buffer.scanInRange regex, scanRange, ({match, range, stop}) => if match[0] is startPair unpairedCount++ else if match[0] is endPair @@ -136,14 +136,13 @@ module.exports = regex = new RegExp("[#{_.escapeRegExp(startPair + endPair)}]", 'g') startPairPosition = null unpairedCount = 0 - scanner = (match, range, {stop}) => + buffer.backwardsScanInRange regex, scanRange, ({match, range, stop}) => if match[0] is endPair unpairedCount++ else if match[0] is startPair unpairedCount-- startPairPosition = range.start stop() if unpairedCount < 0 - buffer.scanInRange(regex, scanRange, scanner, true) startPairPosition updateMatch: (editor) -> diff --git a/src/packages/command-panel/lib/command-interpreter.coffee b/src/packages/command-panel/lib/command-interpreter.coffee index 07f53672e..8022fcb81 100644 --- a/src/packages/command-panel/lib/command-interpreter.coffee +++ b/src/packages/command-panel/lib/command-interpreter.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' PEG = require 'pegjs' module.exports = @@ -6,7 +6,7 @@ class CommandInterpreter constructor: (@project) -> eval: (string, activeEditSession) -> - @parser ?= PEG.buildParser(fs.read(require.resolve 'command-panel/lib/commands.pegjs')) + @parser ?= PEG.buildParser(fsUtils.read(require.resolve 'command-panel/lib/commands.pegjs')) compositeCommand = @parser.parse(string) @lastRelativeAddress = compositeCommand if compositeCommand.isRelativeAddress() compositeCommand.execute(@project, activeEditSession) diff --git a/src/packages/command-panel/lib/command-panel-view.coffee b/src/packages/command-panel/lib/command-panel-view.coffee index a0255a6c0..13d773e41 100644 --- a/src/packages/command-panel/lib/command-panel-view.coffee +++ b/src/packages/command-panel/lib/command-panel-view.coffee @@ -120,6 +120,8 @@ class CommandPanelView extends View execute: (command=@escapedCommand()) -> @loadingMessage.show() + @previewList.hide() + @previewHeader.hide() @errorMessages.empty() try diff --git a/src/packages/command-panel/lib/commands/regex-address.coffee b/src/packages/command-panel/lib/commands/regex-address.coffee index d2828a6be..9764d0cae 100644 --- a/src/packages/command-panel/lib/commands/regex-address.coffee +++ b/src/packages/command-panel/lib/commands/regex-address.coffee @@ -24,12 +24,12 @@ class RegexAddress extends Address rangeToReturn = null scanMethodName = if @isReversed then "backwardsScanInRange" else "scanInRange" - buffer[scanMethodName] @regex, rangeToSearch, (match, range) -> + buffer[scanMethodName] @regex, rangeToSearch, ({range}) -> rangeToReturn = range if not rangeToReturn rangeToSearch = if @isReversed then rangeAfter else rangeBefore - buffer[scanMethodName] @regex, rangeToSearch, (match, range) -> + buffer[scanMethodName] @regex, rangeToSearch, ({range}) -> rangeToReturn = range if not rangeToReturn diff --git a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee index 619378ed3..c9255a4fc 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches-in-project.coffee @@ -8,7 +8,7 @@ class SelectAllMatchesInProject extends Command previewOperations: true constructor: (pattern) -> - @regex = new RegExp(pattern, 'g') + @regex = new RegExp(pattern) compile: (project, buffer, range) -> deferred = $.Deferred() diff --git a/src/packages/command-panel/lib/commands/select-all-matches.coffee b/src/packages/command-panel/lib/commands/select-all-matches.coffee index ad1b0bca9..dc0eaef35 100644 --- a/src/packages/command-panel/lib/commands/select-all-matches.coffee +++ b/src/packages/command-panel/lib/commands/select-all-matches.coffee @@ -12,12 +12,12 @@ class SelectAllMatches extends Command compile: (project, buffer, ranges) -> deferred = $.Deferred() operations = [] - for range in ranges - buffer.scanInRange @regex, range, (match, matchRange) -> + for scanRange in ranges + buffer.scanInRange @regex, scanRange, ({range}) -> operations.push(new Operation( project: project buffer: buffer - bufferRange: matchRange + bufferRange: range )) deferred.resolve(operations) deferred.promise() diff --git a/src/packages/command-panel/lib/commands/substitution.coffee b/src/packages/command-panel/lib/commands/substitution.coffee index 66a621bc2..71a229c32 100644 --- a/src/packages/command-panel/lib/commands/substitution.coffee +++ b/src/packages/command-panel/lib/commands/substitution.coffee @@ -15,12 +15,12 @@ class Substitution extends Command compile: (project, buffer, ranges) -> deferred = $.Deferred() operations = [] - for range in ranges - buffer.scanInRange @regex, range, (match, matchRange) => + for scanRange in ranges + buffer.scanInRange @regex, scanRange, ({range}) => operations.push(new Operation( project: project buffer: buffer - bufferRange: matchRange + bufferRange: range newText: @replacementText preserveSelection: true )) diff --git a/src/packages/command-panel/lib/operation.coffee b/src/packages/command-panel/lib/operation.coffee index 9be9ad7f6..7f70b75e0 100644 --- a/src/packages/command-panel/lib/operation.coffee +++ b/src/packages/command-panel/lib/operation.coffee @@ -23,7 +23,7 @@ class Operation @getBufferRange() unless @preserveSelection preview: -> - range = @getBuffer().getMarkerRange(@getMarker()) + range = @getBufferRange() line = @getBuffer().lineForRow(range.start.row) prefix = line[0...range.start.column] match = line[range.start.column...range.end.column] diff --git a/src/packages/command-panel/lib/path-view.coffee b/src/packages/command-panel/lib/path-view.coffee index 9561d019b..d4727da86 100644 --- a/src/packages/command-panel/lib/path-view.coffee +++ b/src/packages/command-panel/lib/path-view.coffee @@ -1,5 +1,5 @@ {View} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' OperationView = require './operation-view' $ = require 'jquery' @@ -7,7 +7,7 @@ module.exports = class PathView extends View @content: ({path, previewList} = {}) -> classes = ['path'] - classes.push('readme') if fs.isReadmePath(path) + classes.push('readme') if fsUtils.isReadmePath(path) @li class: classes.join(' '), => @div outlet: 'pathDetails', class: 'path-details', => @span class: 'path-name', path @@ -17,9 +17,11 @@ class PathView extends View initialize: ({@previewList}) -> @pathDetails.on 'mousedown', => @toggle(true) @subscribe @previewList, 'command-panel:collapse-result', => - @collapse(true) if @isSelected() + if @isSelected() + @collapse() + @previewList.renderOperations() @subscribe @previewList, 'command-panel:expand-result', => - @expand(true) if @isSelected() + @expand() if @isSelected() @subscribe @previewList, 'core:confirm', => if @hasClass('selected') @toggle(true) @@ -36,30 +38,22 @@ class PathView extends View @previewList.find('.selected').removeClass('selected') @addClass('selected') - toggle: (animate) -> + toggle: -> if @hasClass('is-collapsed') - @expand(animate) + @expand() else - @collapse(animate) + @collapse() - expand: (animate=false) -> - if animate - @matches.show 100, => @removeClass 'is-collapsed' - else - @matches.show() - @removeClass 'is-collapsed' + expand: -> + @matches.show() + @removeClass 'is-collapsed' scrollTo: -> top = @previewList.scrollTop() + @offset().top - @previewList.offset().top bottom = top + @pathDetails.outerHeight() @previewList.scrollTo(top, bottom) - collapse: (animate=false) -> - if animate - @matches.hide 100, => - @addClass 'is-collapsed' - @setSelected() if @isSelected() - else - @matches.hide() - @addClass 'is-collapsed' - @setSelected() if @isSelected() + collapse: -> + @matches.hide() + @addClass 'is-collapsed' + @setSelected() if @isSelected() diff --git a/src/packages/command-panel/lib/preview-list.coffee b/src/packages/command-panel/lib/preview-list.coffee index 7f70db89d..6cbdd7bf2 100644 --- a/src/packages/command-panel/lib/preview-list.coffee +++ b/src/packages/command-panel/lib/preview-list.coffee @@ -1,7 +1,6 @@ $ = require 'jquery' ScrollView = require 'scroll-view' _ = require 'underscore' -fs = require 'fs-utils' PathView = require './path-view' OperationView = require './operation-view' @@ -21,8 +20,7 @@ class PreviewList extends ScrollView @on 'core:move-down', => @selectNextOperation(); false @on 'core:move-up', => @selectPreviousOperation(); false @on 'scroll', => - @renderOperations() if @scrollBottom() >= (@prop('scrollHeight')) - + @renderOperations() if @scrollBottom() >= @prop('scrollHeight') @command 'command-panel:collapse-all', => @collapseAllPaths() @command 'command-panel:expand-all', => @expandAllPaths() @@ -114,6 +112,8 @@ class PreviewList extends ScrollView @scrollTop(top) if top < @scrollTop() scrollToBottom: -> + @renderOperations(renderAll: true) + super() @find('.selected').removeClass('selected') diff --git a/src/packages/command-panel/spec/preview-list-spec.coffee b/src/packages/command-panel/spec/preview-list-spec.coffee index ce91de176..f1bfafa85 100644 --- a/src/packages/command-panel/spec/preview-list-spec.coffee +++ b/src/packages/command-panel/spec/preview-list-spec.coffee @@ -43,3 +43,25 @@ describe "Preview List", -> previousOperationCount = previewList.find("li").length previewList.collapseAllPaths() expect(previewList.find("li").length).toBeGreaterThan previousOperationCount + + it "renders more operations when a preview item is collapsed", -> + waitsForPromise -> + commandPanelView.execute('X x/so/') + + runs -> + expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() + previousScrollHeight = previewList.prop('scrollHeight') + previousOperationCount = previewList.find("li").length + previewList.trigger 'command-panel:collapse-result' + expect(previewList.find("li").length).toBeGreaterThan previousOperationCount + + it "renders all operations when core:move-to-bottom is triggered", -> + waitsForPromise -> + commandPanelView.execute('X x/so/') + + runs -> + expect(previewList.prop('scrollHeight')).toBeGreaterThan previewList.height() + previousScrollHeight = previewList.prop('scrollHeight') + previewList.trigger 'core:move-to-bottom' + liCount = previewList.getPathCount() + previewList.getOperations().length + expect(previewList.find("li").length).toBe liCount diff --git a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee index 1c11229db..8bdfc5521 100644 --- a/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee +++ b/src/packages/fuzzy-finder/lib/fuzzy-finder-view.coffee @@ -2,7 +2,7 @@ SelectList = require 'select-list' _ = require 'underscore' $ = require 'jquery' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' LoadPathsTask = require './load-paths-task' module.exports = @@ -45,22 +45,22 @@ class FuzzyFinderView extends SelectList else if git.isStatusModified(status) @div class: 'status modified' - ext = fs.extension(path) - if fs.isReadmePath(path) + ext = fsUtils.extension(path) + if fsUtils.isReadmePath(path) typeClass = 'readme-name' - else if fs.isCompressedExtension(ext) + else if fsUtils.isCompressedExtension(ext) typeClass = 'compressed-name' - else if fs.isImageExtension(ext) + else if fsUtils.isImageExtension(ext) typeClass = 'image-name' - else if fs.isPdfExtension(ext) + else if fsUtils.isPdfExtension(ext) typeClass = 'pdf-name' - else if fs.isBinaryExtension(ext) + else if fsUtils.isBinaryExtension(ext) typeClass = 'binary-name' else typeClass = 'text-name' - @span fs.base(path), class: "file label #{typeClass}" - if folder = project.relativize(fs.directory(path)) + @span fsUtils.base(path), class: "file label #{typeClass}" + if folder = project.relativize(fsUtils.directory(path)) @span " - #{folder}/", class: 'directory' openPath: (path) -> @@ -76,7 +76,7 @@ class FuzzyFinderView extends SelectList confirmed : (path) -> return unless path.length - if fs.isFile(path) + if fsUtils.isFile(path) @cancel() @openPath(path) else @@ -134,7 +134,7 @@ class FuzzyFinderView extends SelectList populateGitStatusPaths: -> paths = [] - paths.push(path) for path, status of git.statuses when fs.isFile(path) + paths.push(path) for path, status of git.statuses when fsUtils.isFile(path) @setArray(paths) diff --git a/src/packages/fuzzy-finder/lib/load-paths-task.coffee b/src/packages/fuzzy-finder/lib/load-paths-task.coffee index 12ef322f9..bb358db8e 100644 --- a/src/packages/fuzzy-finder/lib/load-paths-task.coffee +++ b/src/packages/fuzzy-finder/lib/load-paths-task.coffee @@ -1,33 +1,33 @@ _ = require 'underscore' -fs = require 'fs-utils' +BufferedProcess = require 'buffered-process' module.exports = class LoadPathsTask - aborted: false - constructor: (@callback) -> start: -> rootPath = project.getPath() ignoredNames = config.get('fuzzyFinder.ignoredNames') ? [] ignoredNames = ignoredNames.concat(config.get('core.ignoredNames') ? []) - ignoreGitIgnoredFiles = config.get('core.hideGitIgnoredFiles') + + command = require.resolve 'nak' + args = ['--list', rootPath] + args.unshift('--addVCSIgnores') if config.get('core.excludeVcsIgnoredPaths') + args.unshift('--ignore', ignoredNames.join(',')) if ignoredNames.length > 0 + args.unshift('--follow') paths = [] - isIgnored = (path) -> - path = path.substring(rootPath.length + 1) - for segment in path.split('/') - return true if _.contains(ignoredNames, segment) - ignoreGitIgnoredFiles and git?.isPathIgnored(fs.join(rootPath, path)) - onFile = (path) -> - return if @aborted - paths.push(path) unless isIgnored(path) - onDirectory = (path) => - not @aborted and not isIgnored(path) - onDone = => - @callback(paths) unless @aborted + exit = (code) => + if code is 0 + @callback(paths) + else + @callback([]) + stdout = (data) -> + paths.push(_.compact(data.split('\n'))...) - fs.traverseTree(rootPath, onFile, onDirectory, onDone) + @process = new BufferedProcess({command, args, stdout, exit}) abort: -> - @aborted = true + if @process? + @process.kill() + @process = null diff --git a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee index 3c9a5c6e4..15035a371 100644 --- a/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee +++ b/src/packages/fuzzy-finder/spec/fuzzy-finder-spec.coffee @@ -4,7 +4,7 @@ LoadPathsTask = require 'fuzzy-finder/lib/load-paths-task' _ = require 'underscore' $ = require 'jquery' {$$} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe 'FuzzyFinder', -> [finderView] = [] @@ -43,7 +43,6 @@ describe 'FuzzyFinder', -> it "shows all relative file paths for the current project and selects the first", -> rootView.attachToDom() finderView.maxItems = Infinity - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' paths = null expect(finderView.find(".loading")).toBeVisible() @@ -57,10 +56,21 @@ describe 'FuzzyFinder', -> runs -> expect(finderView.list.children('li').length).toBe paths.length for path in paths - expect(finderView.list.find("li:contains(#{fs.base(path)})")).toExist() + expect(finderView.list.find("li:contains(#{fsUtils.base(path)})")).toExist() expect(finderView.list.children().first()).toHaveClass 'selected' expect(finderView.find(".loading")).not.toBeVisible() + it "includes symlinked file paths", -> + rootView.attachToDom() + finderView.maxItems = Infinity + rootView.trigger 'fuzzy-finder:toggle-file-finder' + + waitsFor "all project paths to load", 5000, -> + not finderView.reloadProjectPaths + + runs -> + expect(finderView.list.find("li:contains(symlink-to-file)")).toExist() + describe "when root view's project has no path", -> beforeEach -> project.setPath(null) @@ -218,16 +228,16 @@ describe 'FuzzyFinder', -> editor = rootView.getActiveView() originalText = editor.getText() originalPath = editor.getPath() - fs.write(originalPath, 'making a change for the better') + fsUtils.write(originalPath, 'making a change for the better') git.getPathStatus(originalPath) newPath = project.resolve('newsample.js') - fs.write(newPath, '') + fsUtils.write(newPath, '') git.getPathStatus(newPath) afterEach -> - fs.write(originalPath, originalText) - fs.remove(newPath) if fs.exists(newPath) + fsUtils.write(originalPath, originalText) + fsUtils.remove(newPath) if fsUtils.exists(newPath) it "displays all new and modified paths", -> expect(rootView.find('.fuzzy-finder')).not.toExist() @@ -280,7 +290,6 @@ describe 'FuzzyFinder', -> describe "cached file paths", -> it "caches file paths after first time", -> spyOn(LoadPathsTask.prototype, "start").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' waitsFor -> @@ -300,7 +309,6 @@ describe 'FuzzyFinder', -> it "doesn't cache buffer paths", -> spyOn(project, "getEditSessions").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-buffer-finder' waitsFor -> @@ -320,7 +328,6 @@ describe 'FuzzyFinder', -> it "busts the cache when the window gains focus", -> spyOn(LoadPathsTask.prototype, "start").andCallThrough() - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' waitsFor -> @@ -337,7 +344,6 @@ describe 'FuzzyFinder', -> describe "path ignoring", -> it "ignores paths that match entries in config.fuzzyFinder.ignoredNames", -> config.set("fuzzyFinder.ignoredNames", ["tree-view.js"]) - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:toggle-file-finder' finderView.maxItems = Infinity @@ -356,7 +362,6 @@ describe 'FuzzyFinder', -> it "opens the fuzzy finder window when there are multiple matches", -> editor.setText("sample") - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' waitsFor -> @@ -368,7 +373,6 @@ describe 'FuzzyFinder', -> it "opens a file directly when there is a single match", -> editor.setText("sample.txt") - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' openedPath = null @@ -386,7 +390,6 @@ describe 'FuzzyFinder', -> editor.setText("moogoogaipan") editor.setCursorBufferPosition([0,5]) - jasmine.unspy(window, "setTimeout") rootView.trigger 'fuzzy-finder:find-under-cursor' waitsFor -> @@ -468,11 +471,11 @@ describe 'FuzzyFinder', -> originalText = editor.getText() originalPath = editor.getPath() newPath = project.resolve('newsample.js') - fs.write(newPath, '') + fsUtils.write(newPath, '') afterEach -> - fs.write(originalPath, originalText) - fs.remove(newPath) if fs.exists(newPath) + fsUtils.write(originalPath, originalText) + fsUtils.remove(newPath) if fsUtils.exists(newPath) describe "when a modified file is shown in the list", -> it "displays the modified icon", -> diff --git a/src/packages/grammar-selector/lib/grammar-selector.coffee b/src/packages/grammar-selector/lib/grammar-selector.coffee index ca0aa828b..81f678a52 100644 --- a/src/packages/grammar-selector/lib/grammar-selector.coffee +++ b/src/packages/grammar-selector/lib/grammar-selector.coffee @@ -61,4 +61,4 @@ class GrammarSelector extends SelectList attach: -> super rootView.append(this) - @miniEditor.focus() \ No newline at end of file + @miniEditor.focus() diff --git a/src/packages/markdown-preview/lib/markdown-preview-view.coffee b/src/packages/markdown-preview/lib/markdown-preview-view.coffee index 62a832e5c..5a8de69de 100644 --- a/src/packages/markdown-preview/lib/markdown-preview-view.coffee +++ b/src/packages/markdown-preview/lib/markdown-preview-view.coffee @@ -1,4 +1,3 @@ -fs = require 'fs-utils' $ = require 'jquery' ScrollView = require 'scroll-view' {$$$} = require 'space-pen' diff --git a/src/packages/package-generator/lib/package-generator-view.coffee b/src/packages/package-generator/lib/package-generator-view.coffee index 63f07890f..eebbf88c2 100644 --- a/src/packages/package-generator/lib/package-generator-view.coffee +++ b/src/packages/package-generator/lib/package-generator-view.coffee @@ -2,7 +2,7 @@ Editor = require 'editor' $ = require 'jquery' _ = require 'underscore' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class PackageGeneratorView extends View @@ -24,7 +24,7 @@ class PackageGeneratorView extends View @previouslyFocusedElement = $(':focus') @message.text("Enter package path") placeholderName = "package-name" - @miniEditor.setText(fs.join(config.userPackagesDirPath, placeholderName)); + @miniEditor.setText(fsUtils.join(config.userPackagesDirPath, placeholderName)); pathLength = @miniEditor.getText().length @miniEditor.setSelectedBufferRange([[0, pathLength - placeholderName.length], [0, pathLength]]) @@ -44,11 +44,11 @@ class PackageGeneratorView extends View getPackagePath: -> packagePath = @miniEditor.getText() - packageName = _.dasherize(fs.base(packagePath)) - fs.join(fs.directory(packagePath), packageName) + packageName = _.dasherize(fsUtils.base(packagePath)) + fsUtils.join(fsUtils.directory(packagePath), packageName) validPackagePath: -> - if fs.exists(@getPackagePath()) + if fsUtils.exists(@getPackagePath()) @error.text("Path already exists at '#{@getPackagePath()}'") @error.show() false @@ -56,22 +56,22 @@ class PackageGeneratorView extends View true createPackageFiles: -> - templatePath = fs.resolveOnLoadPath(fs.join("package-generator", "template")) - packageName = fs.base(@getPackagePath()) + templatePath = fsUtils.resolveOnLoadPath(fsUtils.join("package-generator", "template")) + packageName = fsUtils.base(@getPackagePath()) - for path in fs.listTree(templatePath) + for path in fsUtils.listTree(templatePath) relativePath = path.replace(templatePath, "") relativePath = relativePath.replace(/^\//, '') relativePath = relativePath.replace(/\.template$/, '') relativePath = @replacePackageNamePlaceholders(relativePath, packageName) - sourcePath = fs.join(@getPackagePath(), relativePath) - if fs.isDirectory(path) - fs.makeTree(sourcePath) - if fs.isFile(path) - fs.makeTree(fs.directory(sourcePath)) - content = @replacePackageNamePlaceholders(fs.read(path), packageName) - fs.write(sourcePath, content) + sourcePath = fsUtils.join(@getPackagePath(), relativePath) + if fsUtils.isDirectory(path) + fsUtils.makeTree(sourcePath) + if fsUtils.isFile(path) + fsUtils.makeTree(fsUtils.directory(sourcePath)) + content = @replacePackageNamePlaceholders(fsUtils.read(path), packageName) + fsUtils.write(sourcePath, content) replacePackageNamePlaceholders: (string, packageName) -> placeholderRegex = /__(?:(package-name)|([pP]ackageName)|(package_name))__/g diff --git a/src/packages/package-generator/spec/package-generator-spec.coffee b/src/packages/package-generator/spec/package-generator-spec.coffee index 87d57bbdd..b237dc285 100644 --- a/src/packages/package-generator/spec/package-generator-spec.coffee +++ b/src/packages/package-generator/spec/package-generator-spec.coffee @@ -1,5 +1,5 @@ RootView = require 'root-view' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe 'Package Generator', -> [packageGenerator] = [] @@ -35,21 +35,21 @@ describe 'Package Generator', -> packageName = "sweet-package-dude" packagePath = "/tmp/atom-packages/#{packageName}" - fs.remove(packagePath) if fs.exists(packagePath) + fsUtils.remove(packagePath) if fsUtils.exists(packagePath) afterEach -> - fs.remove(packagePath) if fs.exists(packagePath) + fsUtils.remove(packagePath) if fsUtils.exists(packagePath) it "forces the package's name to be lowercase with dashes", -> packageName = "CamelCaseIsForTheBirds" - packagePath = fs.join(fs.directory(packagePath), packageName) + packagePath = fsUtils.join(fsUtils.directory(packagePath), packageName) rootView.trigger("package-generator:generate") packageGeneratorView = rootView.find(".package-generator").view() packageGeneratorView.miniEditor.setText(packagePath) packageGeneratorView.trigger "core:confirm" expect(packagePath).not.toExistOnDisk() - expect(fs.join(fs.directory(packagePath), "camel-case-is-for-the-birds")).toExistOnDisk() + expect(fsUtils.join(fsUtils.directory(packagePath), "camel-case-is-for-the-birds")).toExistOnDisk() it "correctly lays out the package files and closes the package generator view", -> rootView.attachToDom() @@ -77,16 +77,16 @@ describe 'Package Generator', -> packageGeneratorView.miniEditor.setText(packagePath) packageGeneratorView.trigger "core:confirm" - lines = fs.read("#{packagePath}/package.cson").split("\n") + lines = fsUtils.read("#{packagePath}/package.cson").split("\n") expect(lines[0]).toBe "'main': 'lib\/#{packageName}'" - lines = fs.read("#{packagePath}/lib/#{packageName}.coffee").split("\n") + lines = fsUtils.read("#{packagePath}/lib/#{packageName}.coffee").split("\n") expect(lines[0]).toBe "SweetPackageDudeView = require 'sweet-package-dude/lib/sweet-package-dude-view'" expect(lines[3]).toBe " sweetPackageDudeView: null" it "displays an error when the package path already exists", -> rootView.attachToDom() - fs.makeTree(packagePath) + fsUtils.makeTree(packagePath) rootView.trigger("package-generator:generate") packageGeneratorView = rootView.find(".package-generator").view() diff --git a/src/packages/snippets/lib/snippet-body-parser.coffee b/src/packages/snippets/lib/snippet-body-parser.coffee index f4c3f99f7..15e6bb289 100644 --- a/src/packages/snippets/lib/snippet-body-parser.coffee +++ b/src/packages/snippets/lib/snippet-body-parser.coffee @@ -1,4 +1,4 @@ PEG = require 'pegjs' -fs = require 'fs-utils' -grammarSrc = fs.read(require.resolve('./snippet-body.pegjs')) +fsUtils = require 'fs-utils' +grammarSrc = fsUtils.read(require.resolve('./snippet-body.pegjs')) module.exports = PEG.buildParser(grammarSrc, trackLineAndColumn: true) diff --git a/src/packages/snippets/spec/snippets-spec.coffee b/src/packages/snippets/spec/snippets-spec.coffee index 2236757e7..de27a456a 100644 --- a/src/packages/snippets/spec/snippets-spec.coffee +++ b/src/packages/snippets/spec/snippets-spec.coffee @@ -3,7 +3,6 @@ RootView = require 'root-view' Buffer = require 'text-buffer' Editor = require 'editor' _ = require 'underscore' -fs = require 'fs-utils' Package = require 'package' describe "Snippets extension", -> diff --git a/src/packages/spell-check/lib/spell-check.coffee b/src/packages/spell-check/lib/spell-check.coffee index 9256e6c3c..5a41afc41 100644 --- a/src/packages/spell-check/lib/spell-check.coffee +++ b/src/packages/spell-check/lib/spell-check.coffee @@ -9,12 +9,6 @@ module.exports = ] activate: -> - syntax.on 'grammars-loaded.spell-check', => @subscribeToEditors() - - deactivate: -> - syntax.off '.spell-check' - - subscribeToEditors: -> rootView.eachEditor (editor) -> if editor.attached and not editor.mini editor.underlayer.append(new SpellCheckView(editor)) diff --git a/src/packages/spell-check/spec/spell-check-spec.coffee b/src/packages/spell-check/spec/spell-check-spec.coffee index 5ac927d96..97fcc2bd9 100644 --- a/src/packages/spell-check/spec/spell-check-spec.coffee +++ b/src/packages/spell-check/spec/spell-check-spec.coffee @@ -10,7 +10,6 @@ describe "Spell check", -> rootView.open('sample.js') config.set('spell-check.grammars', []) atom.activatePackage('spell-check', immediate: true) - syntax.trigger 'grammars-loaded' rootView.attachToDom() editor = rootView.getActiveView() diff --git a/src/packages/status-bar/spec/status-bar-spec.coffee b/src/packages/status-bar/spec/status-bar-spec.coffee index 497a4143d..ead338eae 100644 --- a/src/packages/status-bar/spec/status-bar-spec.coffee +++ b/src/packages/status-bar/spec/status-bar-spec.coffee @@ -2,7 +2,7 @@ $ = require 'jquery' _ = require 'underscore' RootView = require 'root-view' StatusBar = require 'status-bar/lib/status-bar-view' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "StatusBar", -> [editor, statusBar, buffer] = [] @@ -57,7 +57,7 @@ describe "StatusBar", -> describe "when the buffer content has changed from the content on disk", -> it "disables the buffer modified indicator on save", -> path = "/tmp/atom-whitespace.txt" - fs.write(path, "") + fsUtils.write(path, "") rootView.open(path) expect(statusBar.bufferModified.text()).toBe '' editor.insertText("\n") @@ -107,12 +107,12 @@ describe "StatusBar", -> describe "git branch label", -> beforeEach -> - fs.remove('/tmp/.git') if fs.isDirectory('/tmp/.git') + fsUtils.remove('/tmp/.git') if fsUtils.isDirectory('/tmp/.git') rootView.attachToDom() it "displays the current branch for files in repositories", -> path = require.resolve('fixtures/git/master.git/HEAD') - project.setPath(fs.resolveOnLoadPath('fixtures/git/master.git')) + project.setPath(fsUtils.resolveOnLoadPath('fixtures/git/master.git')) rootView.open(path) expect(statusBar.branchArea).toBeVisible() expect(statusBar.branchLabel.text()).toBe 'master' @@ -128,22 +128,22 @@ describe "StatusBar", -> beforeEach -> path = require.resolve('fixtures/git/working-dir/file.txt') - newPath = fs.join(fs.resolveOnLoadPath('fixtures/git/working-dir'), 'new.txt') - fs.write(newPath, "I'm new here") - ignoredPath = fs.join(fs.resolveOnLoadPath('fixtures/git/working-dir'), 'ignored.txt') - fs.write(ignoredPath, 'ignored.txt') + newPath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/git/working-dir'), 'new.txt') + fsUtils.write(newPath, "I'm new here") + ignoredPath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/git/working-dir'), 'ignored.txt') + fsUtils.write(ignoredPath, 'ignored.txt') git.getPathStatus(path) git.getPathStatus(newPath) - originalPathText = fs.read(path) + originalPathText = fsUtils.read(path) rootView.attachToDom() afterEach -> - fs.write(path, originalPathText) - fs.remove(newPath) if fs.exists(newPath) - fs.remove(ignoredPath) if fs.exists(ignoredPath) + fsUtils.write(path, originalPathText) + fsUtils.remove(newPath) if fsUtils.exists(newPath) + fsUtils.remove(ignoredPath) if fsUtils.exists(ignoredPath) it "displays the modified icon for a changed file", -> - fs.write(path, "i've changed for the worse") + fsUtils.write(path, "i've changed for the worse") git.getPathStatus(path) rootView.open(path) expect(statusBar.gitStatusIcon).toHaveClass('modified-status-icon') @@ -161,16 +161,16 @@ describe "StatusBar", -> expect(statusBar.gitStatusIcon).toHaveClass('ignored-status-icon') it "updates when a status-changed event occurs", -> - fs.write(path, "i've changed for the worse") + fsUtils.write(path, "i've changed for the worse") git.getPathStatus(path) rootView.open(path) expect(statusBar.gitStatusIcon).toHaveClass('modified-status-icon') - fs.write(path, originalPathText) + fsUtils.write(path, originalPathText) git.getPathStatus(path) expect(statusBar.gitStatusIcon).not.toHaveClass('modified-status-icon') it "displays the diff stat for modified files", -> - fs.write(path, "i've changed for the worse") + fsUtils.write(path, "i've changed for the worse") git.getPathStatus(path) rootView.open(path) expect(statusBar.gitStatusIcon).toHaveText('+1,-1') @@ -183,7 +183,6 @@ describe "StatusBar", -> beforeEach -> atom.activatePackage('text.tmbundle', sync: true) atom.activatePackage('javascript.tmbundle', sync: true) - syntax.trigger 'grammars-loaded' it "displays the name of the current grammar", -> expect(statusBar.find('.grammar-name').text()).toBe 'JavaScript' diff --git a/src/packages/symbols-view/lib/load-tags-handler.coffee b/src/packages/symbols-view/lib/load-tags-handler.coffee index 860d037f5..c29957822 100644 --- a/src/packages/symbols-view/lib/load-tags-handler.coffee +++ b/src/packages/symbols-view/lib/load-tags-handler.coffee @@ -1,13 +1,13 @@ ctags = require 'ctags' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = getTagsFile: (path) -> - tagsFile = fs.join(path, "tags") - return tagsFile if fs.isFile(tagsFile) + tagsFile = fsUtils.join(path, "tags") + return tagsFile if fsUtils.isFile(tagsFile) - tagsFile = fs.join(path, "TAGS") - return tagsFile if fs.isFile(tagsFile) + tagsFile = fsUtils.join(path, "TAGS") + return tagsFile if fsUtils.isFile(tagsFile) loadTags: (path) -> tagsFile = @getTagsFile(path) diff --git a/src/packages/symbols-view/lib/symbols-view.coffee b/src/packages/symbols-view/lib/symbols-view.coffee index 816be9739..a6f617139 100644 --- a/src/packages/symbols-view/lib/symbols-view.coffee +++ b/src/packages/symbols-view/lib/symbols-view.coffee @@ -3,7 +3,7 @@ SelectList = require 'select-list' TagGenerator = require './tag-generator' TagReader = require './tag-reader' Point = require 'point' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' $ = require 'jquery' module.exports = @@ -30,7 +30,7 @@ class SymbolsView extends SelectList if position text = "Line #{position.row + 1}" else - text = fs.base(file) + text = fsUtils.base(file) @div text, class: 'right function-details' toggleFileSymbols: -> @@ -75,7 +75,7 @@ class SymbolsView extends SelectList setTimeout (=> @cancel()), 2000 confirmed : (tag) -> - if tag.file and not fs.isFile(project.resolve(tag.file)) + if tag.file and not fsUtils.isFile(project.resolve(tag.file)) @setError('Selected file does not exist') setTimeout((=> @setError()), 2000) else @@ -104,8 +104,8 @@ class SymbolsView extends SelectList pattern = $.trim(tag.pattern?.replace(/(^^\/\^)|(\$\/$)/g, '')) # Remove leading /^ and trailing $/ return unless pattern file = project.resolve(tag.file) - return unless fs.isFile(file) - for line, index in fs.read(file).split('\n') + return unless fsUtils.isFile(file) + for line, index in fsUtils.read(file).split('\n') return new Point(index, 0) if pattern is $.trim(line) goToDeclaration: -> @@ -123,7 +123,7 @@ class SymbolsView extends SelectList continue unless position tags.push file: match.file - name: fs.base(match.file) + name: fsUtils.base(match.file) position: position @miniEditor.show() @setArray(tags) diff --git a/src/packages/symbols-view/lib/tag-generator.coffee b/src/packages/symbols-view/lib/tag-generator.coffee index 5960ed6a2..8a847ea25 100644 --- a/src/packages/symbols-view/lib/tag-generator.coffee +++ b/src/packages/symbols-view/lib/tag-generator.coffee @@ -1,7 +1,7 @@ Point = require 'point' $ = require 'jquery' BufferedProcess = require 'buffered-process' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class TagGenerator @@ -18,7 +18,7 @@ class TagGenerator generate: -> deferred = $.Deferred() tags = [] - command = fs.resolveOnLoadPath('ctags') + command = fsUtils.resolveOnLoadPath('ctags') args = ['--fields=+KS', '-nf', '-', @path] stdout = (lines) => for line in lines.split('\n') diff --git a/src/packages/symbols-view/lib/tag-reader.coffee b/src/packages/symbols-view/lib/tag-reader.coffee index dd7f069a7..d243535e8 100644 --- a/src/packages/symbols-view/lib/tag-reader.coffee +++ b/src/packages/symbols-view/lib/tag-reader.coffee @@ -1,4 +1,4 @@ -fs = require 'fs-utils' +fsUtils = require 'fs-utils' $ = require 'jquery' LoadTagsTask = require './load-tags-task' ctags = require 'ctags' @@ -7,7 +7,7 @@ module.exports = getTagsFile: (project) -> tagsFile = project.resolve("tags") or project.resolve("TAGS") - return tagsFile if fs.isFile(tagsFile) + return tagsFile if fsUtils.isFile(tagsFile) find: (editor) -> word = editor.getTextInRange(editor.getCursor().getCurrentWordBufferRange()) diff --git a/src/packages/symbols-view/spec/symbols-view-spec.coffee b/src/packages/symbols-view/spec/symbols-view-spec.coffee index 7401a4448..4762ba421 100644 --- a/src/packages/symbols-view/spec/symbols-view-spec.coffee +++ b/src/packages/symbols-view/spec/symbols-view-spec.coffee @@ -1,7 +1,7 @@ RootView = require 'root-view' SymbolsView = require 'symbols-view/lib/symbols-view' TagGenerator = require 'symbols-view/lib/tag-generator' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "SymbolsView", -> [symbolsView, setArraySpy] = [] @@ -162,11 +162,11 @@ describe "SymbolsView", -> beforeEach -> renamedPath = project.resolve("tagged-duplicate-renamed.js") - fs.remove(renamedPath) if fs.exists(renamedPath) - fs.move(project.resolve("tagged-duplicate.js"), renamedPath) + fsUtils.remove(renamedPath) if fsUtils.exists(renamedPath) + fsUtils.move(project.resolve("tagged-duplicate.js"), renamedPath) afterEach -> - fs.move(renamedPath, project.resolve("tagged-duplicate.js")) + fsUtils.move(renamedPath, project.resolve("tagged-duplicate.js")) it "doesn't display the tag", -> rootView.open("tagged.js") @@ -205,11 +205,11 @@ describe "SymbolsView", -> beforeEach -> renamedPath = project.resolve("tagged-renamed.js") - fs.remove(renamedPath) if fs.exists(renamedPath) - fs.move(project.resolve("tagged.js"), renamedPath) + fsUtils.remove(renamedPath) if fsUtils.exists(renamedPath) + fsUtils.move(project.resolve("tagged.js"), renamedPath) afterEach -> - fs.move(renamedPath, project.resolve("tagged.js")) + fsUtils.move(renamedPath, project.resolve("tagged.js")) it "doesn't open the editor", -> rootView.trigger "symbols-view:toggle-project-symbols" diff --git a/src/packages/tabs/lib/tab-view.coffee b/src/packages/tabs/lib/tab-view.coffee index 9e9594ef1..9c5faab90 100644 --- a/src/packages/tabs/lib/tab-view.coffee +++ b/src/packages/tabs/lib/tab-view.coffee @@ -1,6 +1,6 @@ $ = require 'jquery' {View} = require 'space-pen' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class TabView extends View @@ -46,7 +46,7 @@ class TabView extends View if fileNameText? duplicates = @editor.getEditSessions().filter (session) -> fileNameText is session.buffer.getBaseName() if duplicates.length > 1 - directory = fs.base(fs.directory(@editSession.getPath())) + directory = fsUtils.base(fsUtils.directory(@editSession.getPath())) fileNameText = "#{fileNameText} - #{directory}" if directory else fileNameText = 'untitled' diff --git a/src/packages/tabs/spec/tabs-spec.coffee b/src/packages/tabs/spec/tabs-spec.coffee index a366126d9..7eb59d232 100644 --- a/src/packages/tabs/spec/tabs-spec.coffee +++ b/src/packages/tabs/spec/tabs-spec.coffee @@ -4,7 +4,6 @@ RootView = require 'root-view' Pane = require 'pane' PaneContainer = require 'pane-container' TabBarView = require 'tabs/lib/tab-bar-view' -fs = require 'fs-utils' {View} = require 'space-pen' describe "Tabs package main", -> diff --git a/src/packages/tree-view/lib/dialog.coffee b/src/packages/tree-view/lib/dialog.coffee index 858db818a..d1d4787bd 100644 --- a/src/packages/tree-view/lib/dialog.coffee +++ b/src/packages/tree-view/lib/dialog.coffee @@ -1,6 +1,6 @@ {View} = require 'space-pen' Editor = require 'editor' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' $ = require 'jquery' module.exports = @@ -21,8 +21,8 @@ class Dialog extends View @miniEditor.setText(path) if select - extension = fs.extension(path) - baseName = fs.base(path) + extension = fsUtils.extension(path) + baseName = fsUtils.base(path) if baseName is extension selectionEnd = path.length else diff --git a/src/packages/tree-view/lib/file-view.coffee b/src/packages/tree-view/lib/file-view.coffee index 1ff73c910..1aea8286b 100644 --- a/src/packages/tree-view/lib/file-view.coffee +++ b/src/packages/tree-view/lib/file-view.coffee @@ -1,7 +1,7 @@ {View} = require 'space-pen' $ = require 'jquery' Git = require 'git' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class FileView extends View @@ -17,16 +17,16 @@ class FileView extends View if @file.symlink @fileName.addClass('symlink-icon') else - extension = fs.extension(@getPath()) - if fs.isReadmePath(@getPath()) + extension = fsUtils.extension(@getPath()) + if fsUtils.isReadmePath(@getPath()) @fileName.addClass('readme-icon') - else if fs.isCompressedExtension(extension) + else if fsUtils.isCompressedExtension(extension) @fileName.addClass('compressed-icon') - else if fs.isImageExtension(extension) + else if fsUtils.isImageExtension(extension) @fileName.addClass('image-icon') - else if fs.isPdfExtension(extension) + else if fsUtils.isPdfExtension(extension) @fileName.addClass('pdf-icon') - else if fs.isBinaryExtension(extension) + else if fsUtils.isBinaryExtension(extension) @fileName.addClass('binary-icon') else @fileName.addClass('text-icon') diff --git a/src/packages/tree-view/lib/tree-view.coffee b/src/packages/tree-view/lib/tree-view.coffee index c7e72221e..6e0aa25b2 100644 --- a/src/packages/tree-view/lib/tree-view.coffee +++ b/src/packages/tree-view/lib/tree-view.coffee @@ -4,7 +4,7 @@ Directory = require 'directory' DirectoryView = require './directory-view' FileView = require './file-view' Dialog = require './dialog' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' $ = require 'jquery' _ = require 'underscore' @@ -230,14 +230,14 @@ class TreeView extends ScrollView dialog.close() return - if fs.exists(newPath) + if fsUtils.exists(newPath) dialog.showError("Error: #{newPath} already exists. Try a different path.") return - directoryPath = fs.directory(newPath) + directoryPath = fsUtils.directory(newPath) try - fs.makeTree(directoryPath) unless fs.exists(directoryPath) - fs.move(oldPath, newPath) + fsUtils.makeTree(directoryPath) unless fsUtils.exists(directoryPath) + fsUtils.move(oldPath, newPath) dialog.close() catch e dialog.showError("Error: #{e.message} Try a different path.") @@ -254,13 +254,13 @@ class TreeView extends ScrollView "You are deleting #{entry.getPath()}", "Move to Trash", (=> $native.moveToTrash(entry.getPath())), "Cancel", null - "Delete", (=> fs.remove(entry.getPath())) + "Delete", (=> fsUtils.remove(entry.getPath())) ) add: -> selectedEntry = @selectedEntry() or @root selectedPath = selectedEntry.getPath() - directoryPath = if fs.isFile(selectedPath) then fs.directory(selectedPath) else selectedPath + directoryPath = if fsUtils.isFile(selectedPath) then fsUtils.directory(selectedPath) else selectedPath relativeDirectoryPath = project.relativize(directoryPath) relativeDirectoryPath += '/' if relativeDirectoryPath.length > 0 @@ -274,16 +274,16 @@ class TreeView extends ScrollView endsWithDirectorySeparator = /\/$/.test(relativePath) path = project.resolve(relativePath) try - if fs.exists(path) - pathType = if fs.isFile(path) then "file" else "directory" + if fsUtils.exists(path) + pathType = if fsUtils.isFile(path) then "file" else "directory" dialog.showError("Error: A #{pathType} already exists at path '#{path}'. Try a different path.") else if endsWithDirectorySeparator - fs.makeTree(path) + fsUtils.makeTree(path) dialog.cancel() @entryForPath(path).buildEntries() @selectEntryForPath(path) else - fs.write(path, "") + fsUtils.write(path, "") rootView.open(path) dialog.close() catch e diff --git a/src/packages/tree-view/spec/tree-view-spec.coffee b/src/packages/tree-view/spec/tree-view-spec.coffee index f5f01aace..a79b4f116 100644 --- a/src/packages/tree-view/spec/tree-view-spec.coffee +++ b/src/packages/tree-view/spec/tree-view-spec.coffee @@ -4,7 +4,7 @@ _ = require 'underscore' TreeView = require 'tree-view/lib/tree-view' RootView = require 'root-view' Directory = require 'directory' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "TreeView", -> [treeView, sampleJs, sampleTxt] = [] @@ -259,20 +259,20 @@ describe "TreeView", -> sampleJs.trigger clickEvent(originalEvent: { detail: 1 }) expect(sampleJs).toHaveClass 'selected' - expect(rootView.getActiveView().getPath()).toBe fs.resolveOnLoadPath('fixtures/tree-view/tree-view.js') + expect(rootView.getActiveView().getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/tree-view/tree-view.js') expect(rootView.getActiveView().isFocused).toBeFalsy() sampleTxt.trigger clickEvent(originalEvent: { detail: 1 }) expect(sampleTxt).toHaveClass 'selected' expect(treeView.find('.selected').length).toBe 1 - expect(rootView.getActiveView().getPath()).toBe fs.resolveOnLoadPath('fixtures/tree-view/tree-view.txt') + expect(rootView.getActiveView().getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/tree-view/tree-view.txt') expect(rootView.getActiveView().isFocused).toBeFalsy() describe "when a file is double-clicked", -> it "selects the file and opens it in the active editor on the first click, then changes focus to the active editor on the second", -> sampleJs.trigger clickEvent(originalEvent: { detail: 1 }) expect(sampleJs).toHaveClass 'selected' - expect(rootView.getActiveView().getPath()).toBe fs.resolveOnLoadPath('fixtures/tree-view/tree-view.js') + expect(rootView.getActiveView().getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/tree-view/tree-view.js') expect(rootView.getActiveView().isFocused).toBeFalsy() sampleJs.trigger clickEvent(originalEvent: { detail: 2 }) @@ -568,7 +568,7 @@ describe "TreeView", -> it "opens the file in the editor and focuses it", -> treeView.root.find('.file:contains(tree-view.js)').click() treeView.root.trigger 'tree-view:open-selected-entry' - expect(rootView.getActiveView().getPath()).toBe fs.resolveOnLoadPath('fixtures/tree-view/tree-view.js') + expect(rootView.getActiveView().getPath()).toBe fsUtils.resolveOnLoadPath('fixtures/tree-view/tree-view.js') expect(rootView.getActiveView().isFocused).toBeTruthy() describe "when a directory is selected", -> @@ -593,14 +593,14 @@ describe "TreeView", -> beforeEach -> atom.deactivatePackage('tree-view') - rootDirPath = fs.join(fs.absolute("/tmp"), "atom-tests") - fs.remove(rootDirPath) if fs.exists(rootDirPath) + rootDirPath = fsUtils.join(fsUtils.absolute("/tmp"), "atom-tests") + fsUtils.remove(rootDirPath) if fsUtils.exists(rootDirPath) - dirPath = fs.join(rootDirPath, "test-dir") - filePath = fs.join(dirPath, "test-file.txt") - fs.makeDirectory(rootDirPath) - fs.makeDirectory(dirPath) - fs.write(filePath, "doesn't matter") + dirPath = fsUtils.join(rootDirPath, "test-dir") + filePath = fsUtils.join(dirPath, "test-file.txt") + fsUtils.makeDirectory(rootDirPath) + fsUtils.makeDirectory(dirPath) + fsUtils.write(filePath, "doesn't matter") project.setPath(rootDirPath) @@ -612,7 +612,7 @@ describe "TreeView", -> fileView = treeView.find('.file:contains(test-file.txt)').view() afterEach -> - fs.remove(rootDirPath) if fs.exists(rootDirPath) + fsUtils.remove(rootDirPath) if fsUtils.exists(rootDirPath) describe "tree-view:add", -> addDialog = null @@ -638,16 +638,16 @@ describe "TreeView", -> dirView.directory.trigger 'contents-changed' expect(directoryChangeHandler).toHaveBeenCalled() - expect(treeView.find('.selected').text()).toBe fs.base(filePath) + expect(treeView.find('.selected').text()).toBe fsUtils.base(filePath) describe "when the path without a trailing '/' is changed and confirmed", -> describe "when no file exists at that location", -> it "add a file, closes the dialog and selects the file in the tree-view", -> - newPath = fs.join(dirPath, "new-test-file.txt") - addDialog.miniEditor.insertText(fs.base(newPath)) + newPath = fsUtils.join(dirPath, "new-test-file.txt") + addDialog.miniEditor.insertText(fsUtils.base(newPath)) addDialog.trigger 'core:confirm' - expect(fs.exists(newPath)).toBeTruthy() - expect(fs.isFile(newPath)).toBeTruthy() + expect(fsUtils.exists(newPath)).toBeTruthy() + expect(fsUtils.isFile(newPath)).toBeTruthy() expect(addDialog.parent()).not.toExist() expect(rootView.getActiveView().getPath()).toBe newPath @@ -655,13 +655,13 @@ describe "TreeView", -> dirView.entries.find("> .file").length > 1 runs -> - expect(treeView.find('.selected').text()).toBe fs.base(newPath) + expect(treeView.find('.selected').text()).toBe fsUtils.base(newPath) describe "when a file already exists at that location", -> it "shows an error message and does not close the dialog", -> - newPath = fs.join(dirPath, "new-test-file.txt") - fs.write(newPath, '') - addDialog.miniEditor.insertText(fs.base(newPath)) + newPath = fsUtils.join(dirPath, "new-test-file.txt") + fsUtils.write(newPath, '') + addDialog.miniEditor.insertText(fsUtils.base(newPath)) addDialog.trigger 'core:confirm' expect(addDialog.prompt.text()).toContain 'Error' @@ -673,11 +673,11 @@ describe "TreeView", -> describe "when no file or directory exists at the given path", -> it "adds a directory and closes the dialog", -> treeView.attachToDom() - newPath = fs.join(dirPath, "new/dir") + newPath = fsUtils.join(dirPath, "new/dir") addDialog.miniEditor.insertText("new/dir/") addDialog.trigger 'core:confirm' - expect(fs.exists(newPath)).toBeTruthy() - expect(fs.isDirectory(newPath)).toBeTruthy() + expect(fsUtils.exists(newPath)).toBeTruthy() + expect(fsUtils.isDirectory(newPath)).toBeTruthy() expect(addDialog.parent()).not.toExist() expect(rootView.getActiveView().getPath()).not.toBe newPath expect(treeView.find(".tree-view")).toMatchSelector(':focus') @@ -686,11 +686,11 @@ describe "TreeView", -> it "selects the created directory", -> treeView.attachToDom() - newPath = fs.join(dirPath, "new2/") + newPath = fsUtils.join(dirPath, "new2/") addDialog.miniEditor.insertText("new2/") addDialog.trigger 'core:confirm' - expect(fs.exists(newPath)).toBeTruthy() - expect(fs.isDirectory(newPath)).toBeTruthy() + expect(fsUtils.exists(newPath)).toBeTruthy() + expect(fsUtils.isDirectory(newPath)).toBeTruthy() expect(addDialog.parent()).not.toExist() expect(rootView.getActiveView().getPath()).not.toBe newPath expect(treeView.find(".tree-view")).toMatchSelector(':focus') @@ -699,8 +699,8 @@ describe "TreeView", -> describe "when a file or directory already exists at the given path", -> it "shows an error message and does not close the dialog", -> - newPath = fs.join(dirPath, "new-dir") - fs.makeDirectory(newPath) + newPath = fsUtils.join(dirPath, "new-dir") + fsUtils.makeDirectory(newPath) addDialog.miniEditor.insertText("new-dir/") addDialog.trigger 'core:confirm' @@ -770,24 +770,24 @@ describe "TreeView", -> waits 50 # The move specs cause too many false positives because of their async nature, so wait a little bit before we cleanup it "opens a move dialog with the file's current path (excluding extension) populated", -> - extension = fs.extension(filePath) - fileNameWithoutExtension = fs.base(filePath, extension) + extension = fsUtils.extension(filePath) + fileNameWithoutExtension = fsUtils.base(filePath, extension) expect(moveDialog).toExist() expect(moveDialog.prompt.text()).toBe "Enter the new path for the file." expect(moveDialog.miniEditor.getText()).toBe(project.relativize(filePath)) - expect(moveDialog.miniEditor.getSelectedText()).toBe fs.base(fileNameWithoutExtension) + expect(moveDialog.miniEditor.getSelectedText()).toBe fsUtils.base(fileNameWithoutExtension) expect(moveDialog.miniEditor.isFocused).toBeTruthy() describe "when the path is changed and confirmed", -> describe "when all the directories along the new path exist", -> it "moves the file, updates the tree view, and closes the dialog", -> - newPath = fs.join(rootDirPath, 'renamed-test-file.txt') + newPath = fsUtils.join(rootDirPath, 'renamed-test-file.txt') moveDialog.miniEditor.setText(newPath) moveDialog.trigger 'core:confirm' - expect(fs.exists(newPath)).toBeTruthy() - expect(fs.exists(filePath)).toBeFalsy() + expect(fsUtils.exists(newPath)).toBeTruthy() + expect(fsUtils.exists(filePath)).toBeFalsy() expect(moveDialog.parent()).not.toExist() waitsFor "tree view to update", -> @@ -800,7 +800,7 @@ describe "TreeView", -> describe "when the directories along the new path don't exist", -> it "creates the target directory before moving the file", -> - newPath = fs.join(rootDirPath, 'new/directory', 'renamed-test-file.txt') + newPath = fsUtils.join(rootDirPath, 'new/directory', 'renamed-test-file.txt') moveDialog.miniEditor.setText(newPath) moveDialog.trigger 'core:confirm' @@ -809,14 +809,14 @@ describe "TreeView", -> treeView.root.find('> .entries > .directory:contains(new)').length > 0 runs -> - expect(fs.exists(newPath)).toBeTruthy() - expect(fs.exists(filePath)).toBeFalsy() + expect(fsUtils.exists(newPath)).toBeTruthy() + expect(fsUtils.exists(filePath)).toBeFalsy() describe "when a file or directory already exists at the target path", -> it "shows an error message and does not close the dialog", -> runs -> - fs.write(fs.join(rootDirPath, 'target.txt'), '') - newPath = fs.join(rootDirPath, 'target.txt') + fsUtils.write(fsUtils.join(rootDirPath, 'target.txt'), '') + newPath = fsUtils.join(rootDirPath, 'target.txt') moveDialog.miniEditor.setText(newPath) moveDialog.trigger 'core:confirm' @@ -844,8 +844,8 @@ describe "TreeView", -> [dotFilePath, dotFileView, moveDialog] = [] beforeEach -> - dotFilePath = fs.join(dirPath, ".dotfile") - fs.write(dotFilePath, "dot") + dotFilePath = fsUtils.join(dirPath, ".dotfile") + fsUtils.write(dotFilePath, "dot") dirView.collapse() dirView.expand() dotFileView = treeView.find('.file:contains(.dotfile)').view() @@ -875,22 +875,22 @@ describe "TreeView", -> temporaryFilePath = null beforeEach -> - temporaryFilePath = fs.join(fs.resolveOnLoadPath('fixtures/tree-view'), 'temporary') - if fs.exists(temporaryFilePath) - fs.remove(temporaryFilePath) + temporaryFilePath = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), 'temporary') + if fsUtils.exists(temporaryFilePath) + fsUtils.remove(temporaryFilePath) waits(20) afterEach -> - fs.remove(temporaryFilePath) if fs.exists(temporaryFilePath) + fsUtils.remove(temporaryFilePath) if fsUtils.exists(temporaryFilePath) describe "when a file is added or removed in an expanded directory", -> it "updates the directory view to display the directory's new contents", -> entriesCountBefore = null runs -> - expect(fs.exists(temporaryFilePath)).toBeFalsy() + expect(fsUtils.exists(temporaryFilePath)).toBeFalsy() entriesCountBefore = treeView.root.entries.find('.entry').length - fs.write temporaryFilePath, 'hi' + fsUtils.write temporaryFilePath, 'hi' waitsFor "directory view contens to refresh", -> treeView.root.entries.find('.entry').length == entriesCountBefore + 1 @@ -898,7 +898,7 @@ describe "TreeView", -> runs -> expect(treeView.root.entries.find('.entry').length).toBe entriesCountBefore + 1 expect(treeView.root.entries.find('.file:contains(temporary)')).toExist() - fs.remove(temporaryFilePath) + fsUtils.remove(temporaryFilePath) waitsFor "directory view contens to refresh", -> treeView.root.entries.find('.entry').length == entriesCountBefore @@ -907,12 +907,12 @@ describe "TreeView", -> [ignoreFile] = [] beforeEach -> - ignoreFile = fs.join(fs.resolveOnLoadPath('fixtures/tree-view'), '.gitignore') - fs.write(ignoreFile, 'tree-view.js') + ignoreFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore') + fsUtils.write(ignoreFile, 'tree-view.js') config.set "core.hideGitIgnoredFiles", false afterEach -> - fs.remove(ignoreFile) if fs.exists(ignoreFile) + fsUtils.remove(ignoreFile) if fsUtils.exists(ignoreFile) it "hides git-ignored files if the option is set, but otherwise shows them", -> expect(treeView.find('.file:contains(tree-view.js)').length).toBe 1 @@ -930,30 +930,30 @@ describe "TreeView", -> beforeEach -> config.set "core.hideGitIgnoredFiles", false - ignoreFile = fs.join(fs.resolveOnLoadPath('fixtures/tree-view'), '.gitignore') - fs.write(ignoreFile, 'tree-view.js') + ignoreFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view'), '.gitignore') + fsUtils.write(ignoreFile, 'tree-view.js') git.getPathStatus(ignoreFile) - newFile = fs.join(fs.resolveOnLoadPath('fixtures/tree-view/dir2'), 'new2') - fs.write(newFile, '') + newFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir2'), 'new2') + fsUtils.write(newFile, '') git.getPathStatus(newFile) - modifiedFile = fs.join(fs.resolveOnLoadPath('fixtures/tree-view/dir1'), 'file1') - originalFileContent = fs.read(modifiedFile) - fs.write modifiedFile, 'ch ch changes' + modifiedFile = fsUtils.join(fsUtils.resolveOnLoadPath('fixtures/tree-view/dir1'), 'file1') + originalFileContent = fsUtils.read(modifiedFile) + fsUtils.write modifiedFile, 'ch ch changes' git.getPathStatus(modifiedFile) treeView.updateRoot() - treeView.root.entries.find('.directory:contains(dir1)').view().expand() treeView.root.entries.find('.directory:contains(dir2)').view().expand() afterEach -> - fs.remove(ignoreFile) if fs.exists(ignoreFile) - fs.remove(newFile) if fs.exists(newFile) - fs.write modifiedFile, originalFileContent + fsUtils.remove(ignoreFile) if fsUtils.exists(ignoreFile) + fsUtils.remove(newFile) if fsUtils.exists(newFile) + fsUtils.write modifiedFile, originalFileContent describe "when a file is modified", -> it "adds a custom style", -> + treeView.root.entries.find('.directory:contains(dir1)').view().expand() expect(treeView.find('.file:contains(file1)')).toHaveClass 'modified' describe "when a directory if modified", -> diff --git a/src/packages/whitespace/lib/whitespace.coffee b/src/packages/whitespace/lib/whitespace.coffee index 087bfabd3..f5c954ba5 100644 --- a/src/packages/whitespace/lib/whitespace.coffee +++ b/src/packages/whitespace/lib/whitespace.coffee @@ -8,7 +8,7 @@ module.exports = whitespaceBeforeSave: (buffer) -> buffer.on 'will-be-saved', -> buffer.transact -> - buffer.scan /[ \t]+$/g, (match, range, { replace }) -> replace('') + buffer.scan /[ \t]+$/g, ({replace}) -> replace('') if config.get('whitespace.ensureSingleTrailingNewline') if buffer.getLastLine() is '' diff --git a/src/packages/whitespace/spec/whitespace-spec.coffee b/src/packages/whitespace/spec/whitespace-spec.coffee index 854cf3295..1a0e54f44 100644 --- a/src/packages/whitespace/spec/whitespace-spec.coffee +++ b/src/packages/whitespace/spec/whitespace-spec.coffee @@ -1,12 +1,12 @@ RootView = require 'root-view' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' describe "Whitespace", -> [editor, path] = [] beforeEach -> path = "/tmp/atom-whitespace.txt" - fs.write(path, "") + fsUtils.write(path, "") window.rootView = new RootView rootView.open(path) @@ -16,10 +16,10 @@ describe "Whitespace", -> editor = rootView.getActiveView() afterEach -> - fs.remove(path) if fs.exists(path) + fsUtils.remove(path) if fsUtils.exists(path) it "strips trailing whitespace before an editor saves a buffer", -> - spyOn(fs, 'write') + spyOn(fsUtils, 'write') config.set("whitespace.ensureSingleTrailingNewline", false) config.update() @@ -79,4 +79,3 @@ describe "Whitespace", -> editor.insertText "no trailing newline" editor.getBuffer().save() expect(editor.getText()).toBe "no trailing newline" - diff --git a/src/packages/wrap-guide/lib/wrap-guide-view.coffee b/src/packages/wrap-guide/lib/wrap-guide-view.coffee index 491e19705..dcce9c44e 100644 --- a/src/packages/wrap-guide/lib/wrap-guide-view.coffee +++ b/src/packages/wrap-guide/lib/wrap-guide-view.coffee @@ -6,7 +6,8 @@ module.exports = class WrapGuideView extends View @activate: -> rootView.eachEditor (editor) -> - editor.underlayer.append(new WrapGuideView(editor)) if editor.attached + if editor.attached and editor.getPane() + editor.underlayer.append(new WrapGuideView(editor)) @content: -> @div class: 'wrap-guide' diff --git a/src/packages/wrap-guide/spec/wrap-guide-spec.coffee b/src/packages/wrap-guide/spec/wrap-guide-spec.coffee index cd0761881..f1aa1b22c 100644 --- a/src/packages/wrap-guide/spec/wrap-guide-spec.coffee +++ b/src/packages/wrap-guide/spec/wrap-guide-spec.coffee @@ -1,4 +1,5 @@ RootView = require 'root-view' +Editor = require 'editor' describe "WrapGuide", -> [editor, wrapGuide] = [] @@ -62,3 +63,8 @@ describe "WrapGuide", -> editor.width(10) wrapGuide.updateGuide() expect(wrapGuide).toBeHidden() + + it "only attaches to editors that are part of a pane", -> + editor2 = new Editor(mini: true) + editor.overlayer.append(editor2) + expect(editor2.find('.wrap-guide').length).toBe 0 diff --git a/src/stdlib/buffered-process.coffee b/src/stdlib/buffered-process.coffee index 04fcf3ce9..eda128601 100644 --- a/src/stdlib/buffered-process.coffee +++ b/src/stdlib/buffered-process.coffee @@ -2,32 +2,36 @@ ChildProcess = require 'child_process' module.exports = class BufferedProcess + process: null + killed: false + constructor: ({command, args, options, stdout, stderr, exit}={}) -> - process = ChildProcess.spawn(command, args, options) + @process = ChildProcess.spawn(command, args, options) stdoutClosed = true stderrClosed = true processExited = true exitCode = 0 triggerExitCallback = -> + return if @killed if stdoutClosed and stderrClosed and processExited exit?(exitCode) if stdout stdoutClosed = false - @bufferStream process.stdout, stdout, -> + @bufferStream @process.stdout, stdout, -> stdoutClosed = true triggerExitCallback() if stderr stderrClosed = false - @bufferStream process.stderr, stderr, -> + @bufferStream @process.stderr, stderr, -> stderrClosed = true triggerExitCallback() if exit processExited = false - process.on 'exit', (code) -> + @process.on 'exit', (code) -> exitCode = code processExited = true triggerExitCallback() @@ -36,7 +40,8 @@ class BufferedProcess stream.setEncoding('utf8') buffered = '' - stream.on 'data', (data) -> + stream.on 'data', (data) => + return if @killed buffered += data lastNewlineIndex = buffered.lastIndexOf('\n') if lastNewlineIndex isnt -1 @@ -44,5 +49,11 @@ class BufferedProcess buffered = buffered.substring(lastNewlineIndex + 1) stream.on 'close', => + return if @killed onLines(buffered) if buffered.length > 0 onDone() + + kill: -> + @killed = true + @process.kill() + @process = null diff --git a/src/stdlib/task.coffee b/src/stdlib/task.coffee index 8216a4f15..091362d73 100644 --- a/src/stdlib/task.coffee +++ b/src/stdlib/task.coffee @@ -1,7 +1,7 @@ _ = require 'underscore' child_process = require 'child_process' EventEmitter = require 'event-emitter' -fs = require 'fs-utils' +fsUtils = require 'fs-utils' module.exports = class Task diff --git a/vendor/ack b/vendor/ack deleted file mode 100755 index a20f9f603..000000000 --- a/vendor/ack +++ /dev/null @@ -1,2784 +0,0 @@ -#!/usr/bin/env perl -# -# This file, ack, is generated code. -# Please DO NOT EDIT or send patches for it. -# -# Please take a look at the source from -# http://github.com/petdance/ack -# and submit patches against the individual files -# that build ack. -# - -use warnings; -use strict; - -our $VERSION = '1.96'; -# Check http://betterthangrep.com/ for updates - -# These are all our globals. - - -MAIN: { - if ( $App::Ack::VERSION ne $main::VERSION ) { - App::Ack::die( "Program/library version mismatch\n\t$0 is $main::VERSION\n\t$INC{'App/Ack.pm'} is $App::Ack::VERSION" ); - } - - # Do preliminary arg checking; - my $env_is_usable = 1; - for ( @ARGV ) { - last if ( $_ eq '--' ); - - # Priorities! Get the --thpppt checking out of the way. - /^--th[pt]+t+$/ && App::Ack::_thpppt($_); - - # See if we want to ignore the environment. (Don't tell Al Gore.) - if ( /^--(no)?env$/ ) { - $env_is_usable = defined $1 ? 0 : 1; - } - } - if ( $env_is_usable ) { - unshift( @ARGV, App::Ack::read_ackrc() ); - } - else { - my @keys = ( 'ACKRC', grep { /^ACK_/ } keys %ENV ); - delete @ENV{@keys}; - } - App::Ack::load_colors(); - - if ( exists $ENV{ACK_SWITCHES} ) { - App::Ack::warn( 'ACK_SWITCHES is no longer supported. Use ACK_OPTIONS.' ); - } - - if ( !@ARGV ) { - App::Ack::show_help(); - exit 1; - } - - main(); -} - -sub main { - my $opt = App::Ack::get_command_line_options(); - - $| = 1 if $opt->{flush}; # Unbuffer the output if flush mode - - if ( App::Ack::input_from_pipe() ) { - # We're going into filter mode - for ( qw( f g l ) ) { - $opt->{$_} and App::Ack::die( "Can't use -$_ when acting as a filter." ); - } - $opt->{show_filename} = 0; - $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt ); - if ( my $nargs = @ARGV ) { - my $s = $nargs == 1 ? '' : 's'; - App::Ack::warn( "Ignoring $nargs argument$s on the command-line while acting as a filter." ); - } - - my $res = App::Ack::Resource::Basic->new( '-' ); - my $nmatches; - if ( $opt->{count} ) { - $nmatches = App::Ack::search_and_list( $res, $opt ); - } - else { - # normal searching - $nmatches = App::Ack::search_resource( $res, $opt ); - } - $res->close(); - App::Ack::exit_from_ack( $nmatches ); - } - - my $file_matching = $opt->{f} || $opt->{lines}; - if ( $file_matching ) { - App::Ack::die( "Can't specify both a regex ($opt->{regex}) and use one of --line, -f or -g." ) if $opt->{regex}; - } - else { - $opt->{regex} = App::Ack::build_regex( defined $opt->{regex} ? $opt->{regex} : shift @ARGV, $opt ); - } - - # check that all regexes do compile fine - App::Ack::check_regex( $_ ) for ( $opt->{regex}, $opt->{G} ); - - my $what = App::Ack::get_starting_points( \@ARGV, $opt ); - my $iter = App::Ack::get_iterator( $what, $opt ); - App::Ack::filetype_setup(); - - my $nmatches = 0; - - App::Ack::set_up_pager( $opt->{pager} ) if defined $opt->{pager}; - if ( $opt->{f} ) { - $nmatches = App::Ack::print_files( $iter, $opt ); - } - elsif ( $opt->{l} || $opt->{count} ) { - $nmatches = App::Ack::print_files_with_matches( $iter, $opt ); - } - else { - $nmatches = App::Ack::print_matches( $iter, $opt ); - } - close $App::Ack::fh; - App::Ack::exit_from_ack( $nmatches ); -} - -=head1 NAME - -ack - grep-like text finder - -=head1 SYNOPSIS - - ack [options] PATTERN [FILE...] - ack -f [options] [DIRECTORY...] - -=head1 DESCRIPTION - -Ack is designed as a replacement for 99% of the uses of F. - -Ack searches the named input FILEs (or standard input if no files are -named, or the file name - is given) for lines containing a match to the -given PATTERN. By default, ack prints the matching lines. - -Ack can also list files that would be searched, without actually searching -them, to let you take advantage of ack's file-type filtering capabilities. - -=head1 FILE SELECTION - -I is intelligent about the files it searches. It knows about -certain file types, based on both the extension on the file and, -in some cases, the contents of the file. These selections can be -made with the B<--type> option. - -With no file selections, I only searches files of types that -it recognizes. If you have a file called F, and I -doesn't know what a .wango file is, I won't search it. - -The B<-a> option tells I to select all files, regardless of -type. - -Some files will never be selected by I, even with B<-a>, -including: - -=over 4 - -=item * Backup files: Files matching F<#*#> or ending with F<~>. - -=item * Coredumps: Files matching F - -=back - -However, I always searches the files given on the command line, -no matter what type. Furthermore, by specifying the B<-u> option all -files will be searched. - -=head1 DIRECTORY SELECTION - -I descends through the directory tree of the starting directories -specified. However, it will ignore the shadow directories used by -many version control systems, and the build directories used by the -Perl MakeMaker system. You may add or remove a directory from this -list with the B<--[no]ignore-dir> option. The option may be repeated -to add/remove multiple directories from the ignore list. - -For a complete list of directories that do not get searched, run -F. - -=head1 WHEN TO USE GREP - -I trumps I as an everyday tool 99% of the time, but don't -throw I away, because there are times you'll still need it. - -E.g., searching through huge files looking for regexes that can be -expressed with I syntax should be quicker with I. - -If your script or parent program uses I C<--quiet> or -C<--silent> or needs exit 2 on IO error, use I. - -=head1 OPTIONS - -=over 4 - -=item B<-a>, B<--all> - -Operate on all files, regardless of type (but still skip directories -like F, F, etc.) - -=item B<-A I>, B<--after-context=I> - -Print I lines of trailing context after matching lines. - -=item B<-B I>, B<--before-context=I> - -Print I lines of leading context before matching lines. - -=item B<-C [I]>, B<--context[=I]> - -Print I lines (default 2) of context around matching lines. - -=item B<-c>, B<--count> - -Suppress normal output; instead print a count of matching lines for -each input file. If B<-l> is in effect, it will only show the -number of lines for each file that has lines matching. Without -B<-l>, some line counts may be zeroes. - -If combined with B<-h> (B<--no-filename>) ack outputs only one total count. - -=item B<--color>, B<--nocolor> - -B<--color> highlights the matching text. B<--nocolor> supresses -the color. This is on by default unless the output is redirected. - -On Windows, this option is off by default unless the -L module is installed or the C -environment variable is used. - -=item B<--color-filename=I> - -Sets the color to be used for filenames. - -=item B<--color-match=I> - -Sets the color to be used for matches. - -=item B<--color-lineno=I> - -Sets the color to be used for line numbers. - -=item B<--column> - -Show the column number of the first match. This is helpful for editors -that can place your cursor at a given position. - -=item B<--env>, B<--noenv> - -B<--noenv> disables all environment processing. No F<.ackrc> is read -and all environment variables are ignored. By default, F considers -F<.ackrc> and settings in the environment. - -=item B<--flush> - -B<--flush> flushes output immediately. This is off by default -unless ack is running interactively (when output goes to a pipe -or file). - -=item B<-f> - -Only print the files that would be searched, without actually doing -any searching. PATTERN must not be specified, or it will be taken as -a path to search. - -=item B<--follow>, B<--nofollow> - -Follow or don't follow symlinks, other than whatever starting files -or directories were specified on the command line. - -This is off by default. - -=item B<-G I> - -Only paths matching I are included in the search. The entire -path and filename are matched against I, and I is a -Perl regular expression, not a shell glob. - -The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I. - -=item B<-g I> - -Print files where the relative path + filename matches I. This option is -a convenience shortcut for B<-f> B<-G I>. - -The options B<-i>, B<-w>, B<-v>, and B<-Q> do not apply to this I. - -=item B<--group>, B<--nogroup> - -B<--group> groups matches by file name with. This is the default when -used interactively. - -B<--nogroup> prints one result per line, like grep. This is the default -when output is redirected. - -=item B<-H>, B<--with-filename> - -Print the filename for each match. - -=item B<-h>, B<--no-filename> - -Suppress the prefixing of filenames on output when multiple files are -searched. - -=item B<--help> - -Print a short help statement. - -=item B<-i>, B<--ignore-case> - -Ignore case in the search strings. - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<--[no]ignore-dir=I> - -Ignore directory (as CVS, .svn, etc are ignored). May be used multiple times -to ignore multiple directories. For example, mason users may wish to include -B<--ignore-dir=data>. The B<--noignore-dir> option allows users to search -directories which would normally be ignored (perhaps to research the contents -of F<.svn/props> directories). - -The I must always be a simple directory name. Nested directories like -F are NOT supported. You would need to specify B<--ignore-dir=foo> and -then no files from any foo directory are taken into account by ack unless given -explicitly on the command line. - -=item B<--line=I> - -Only print line I of each file. Multiple lines can be given with multiple -B<--line> options or as a comma separated list (B<--line=3,5,7>). B<--line=4-7> -also works. The lines are always output in ascending order, no matter the -order given on the command line. - -=item B<-l>, B<--files-with-matches> - -Only print the filenames of matching files, instead of the matching text. - -=item B<-L>, B<--files-without-matches> - -Only print the filenames of files that do I match. This is equivalent -to specifying B<-l> and B<-v>. - -=item B<--match I> - -Specify the I explicitly. This is helpful if you don't want to put the -regex as your first argument, e.g. when executing multiple searches over the -same set of files. - - # search for foo and bar in given files - ack file1 t/file* --match foo - ack file1 t/file* --match bar - -=item B<-m=I>, B<--max-count=I> - -Stop reading a file after I matches. - -=item B<--man> - -Print this manual page. - -=item B<-n>, B<--no-recurse> - -No descending into subdirectories. - -=item B<-o> - -Show only the part of each line matching PATTERN (turns off text -highlighting) - -=item B<--output=I> - -Output the evaluation of I for each line (turns off text -highlighting) - -=item B<--pager=I> - -Direct ack's output through I. This can also be specified -via the C and C environment variables. - -Using --pager does not suppress grouping and coloring like piping -output on the command-line does. - -=item B<--passthru> - -Prints all lines, whether or not they match the expression. Highlighting -will still work, though, so it can be used to highlight matches while -still seeing the entire file, as in: - - # Watch a log file, and highlight a certain IP address - $ tail -f ~/access.log | ack --passthru 123.45.67.89 - -=item B<--print0> - -Only works in conjunction with -f, -g, -l or -c (filename output). The filenames -are output separated with a null byte instead of the usual newline. This is -helpful when dealing with filenames that contain whitespace, e.g. - - # remove all files of type html - ack -f --html --print0 | xargs -0 rm -f - -=item B<-Q>, B<--literal> - -Quote all metacharacters in PATTERN, it is treated as a literal. - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<-r>, B<-R>, B<--recurse> - -Recurse into sub-directories. This is the default and just here for -compatibility with grep. You can also use it for turning B<--no-recurse> off. - -=item B<--smart-case>, B<--no-smart-case> - -Ignore case in the search strings if PATTERN contains no uppercase -characters. This is similar to C in vim. This option is -off by default. - -B<-i> always overrides this option. - -This applies only to the PATTERN, not to the regexes given for the -B<-g> and B<-G> options. - -=item B<--sort-files> - -Sorts the found files lexically. Use this if you want your file -listings to be deterministic between runs of I. - -=item B<--show-types> - -Outputs the filetypes that ack associates with each file. - -Works with B<-f> and B<-g> options. - -=item B<--thpppt> - -Display the all-important Bill The Cat logo. Note that the exact -spelling of B<--thpppppt> is not important. It's checked against -a regular expression. - -=item B<--type=TYPE>, B<--type=noTYPE> - -Specify the types of files to include or exclude from a search. -TYPE is a filetype, like I or I. B<--type=perl> can -also be specified as B<--perl>, and B<--type=noperl> can be done -as B<--noperl>. - -If a file is of both type "foo" and "bar", specifying --foo and ---nobar will exclude the file, because an exclusion takes precedence -over an inclusion. - -Type specifications can be repeated and are ORed together. - -See I for a list of valid types. - -=item B<--type-add I=I<.EXTENSION>[,I<.EXT2>[,...]]> - -Files with the given EXTENSION(s) are recognized as being of (the -existing) type TYPE. See also L. - - -=item B<--type-set I=I<.EXTENSION>[,I<.EXT2>[,...]]> - -Files with the given EXTENSION(s) are recognized as being of type -TYPE. This replaces an existing definition for type TYPE. See also -L. - -=item B<-u>, B<--unrestricted> - -All files and directories (including blib/, core.*, ...) are searched, -nothing is skipped. When both B<-u> and B<--ignore-dir> are used, the -B<--ignore-dir> option has no effect. - -=item B<-v>, B<--invert-match> - -Invert match: select non-matching lines - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<--version> - -Display version and copyright information. - -=item B<-w>, B<--word-regexp> - -Force PATTERN to match only whole words. The PATTERN is wrapped with -C<\b> metacharacters. - -This applies only to the PATTERN, not to the regexes given for the B<-g> -and B<-G> options. - -=item B<-1> - -Stops after reporting first match of any kind. This is different -from B<--max-count=1> or B<-m1>, where only one match per file is -shown. Also, B<-1> works with B<-f> and B<-g>, where B<-m> does -not. - -=back - -=head1 THE .ackrc FILE - -The F<.ackrc> file contains command-line options that are prepended -to the command line before processing. Multiple options may live -on multiple lines. Lines beginning with a # are ignored. A F<.ackrc> -might look like this: - - # Always sort the files - --sort-files - - # Always color, even if piping to a another program - --color - - # Use "less -r" as my pager - --pager=less -r - -Note that arguments with spaces in them do not need to be quoted, -as they are not interpreted by the shell. Basically, each I -in the F<.ackrc> file is interpreted as one element of C<@ARGV>. - -F looks in your home directory for the F<.ackrc>. You can -specify another location with the F variable, below. - -If B<--noenv> is specified on the command line, the F<.ackrc> file -is ignored. - -=head1 Defining your own types - -ack allows you to define your own types in addition to the predefined -types. This is done with command line options that are best put into -an F<.ackrc> file - then you do not have to define your types over and -over again. In the following examples the options will always be shown -on one command line so that they can be easily copy & pasted. - -I searches for foo in all perl files. I -tells you, that perl files are files ending -in .pl, .pm, .pod or .t. So what if you would like to include .xs -files as well when searching for --perl files? I -does this for you. B<--type-add> appends -additional extensions to an existing type. - -If you want to define a new type, or completely redefine an existing -type, then use B<--type-set>. I defines the type I to include files with -the extensions .e or .eiffel. So to search for all eiffel files -containing the word Bertrand use I. -As usual, you can also write B<--type=eiffel> -instead of B<--eiffel>. Negation also works, so B<--noeiffel> excludes -all eiffel files from a search. Redefining also works: I -and I<.xs> files no longer belong to the type I. - -When defining your own types in the F<.ackrc> file you have to use -the following: - - --type-set=eiffel=.e,.eiffel - -or writing on separate lines - - --type-set - eiffel=.e,.eiffel - -The following does B work in the F<.ackrc> file: - - --type-set eiffel=.e,.eiffel - - -In order to see all currently defined types, use I<--help types>, e.g. -I - -Restrictions: - -=over 4 - -=item - -The types 'skipped', 'make', 'binary' and 'text' are considered "builtin" and -cannot be altered. - -=item - -The shebang line recognition of the types 'perl', 'ruby', 'php', 'python', -'shell' and 'xml' cannot be redefined by I<--type-set>, it is always -active. However, the shebang line is only examined for files where the -extension is not recognised. Therefore it is possible to say -I and -only find your shiny new I<.perl> files (and all files with unrecognized extension -and perl on the shebang line). - -=back - -=head1 ENVIRONMENT VARIABLES - -For commonly-used ack options, environment variables can make life much easier. -These variables are ignored if B<--noenv> is specified on the command line. - -=over 4 - -=item ACKRC - -Specifies the location of the F<.ackrc> file. If this file doesn't -exist, F looks in the default location. - -=item ACK_OPTIONS - -This variable specifies default options to be placed in front of -any explicit options on the command line. - -=item ACK_COLOR_FILENAME - -Specifies the color of the filename when it's printed in B<--group> -mode. By default, it's "bold green". - -The recognized attributes are clear, reset, dark, bold, underline, -underscore, blink, reverse, concealed black, red, green, yellow, -blue, magenta, on_black, on_red, on_green, on_yellow, on_blue, -on_magenta, on_cyan, and on_white. Case is not significant. -Underline and underscore are equivalent, as are clear and reset. -The color alone sets the foreground color, and on_color sets the -background color. - -This option can also be set with B<--color-filename>. - -=item ACK_COLOR_MATCH - -Specifies the color of the matching text when printed in B<--color> -mode. By default, it's "black on_yellow". - -This option can also be set with B<--color-match>. - -See B for the color specifications. - -=item ACK_COLOR_LINENO - -Specifies the color of the line number when printed in B<--color> -mode. By default, it's "bold yellow". - -This option can also be set with B<--color-lineno>. - -See B for the color specifications. - -=item ACK_PAGER - -Specifies a pager program, such as C, C or C, to which -ack will send its output. - -Using C does not suppress grouping and coloring like -piping output on the command-line does, except that on Windows -ack will assume that C does not support color. - -C overrides C if both are specified. - -=item ACK_PAGER_COLOR - -Specifies a pager program that understands ANSI color sequences. -Using C does not suppress grouping and coloring -like piping output on the command-line does. - -If you are not on Windows, you never need to use C. - -=back - -=head1 ACK & OTHER TOOLS - -=head2 Vim integration - -F integrates easily with the Vim text editor. Set this in your -F<.vimrc> to use F instead of F: - - set grepprg=ack\ -a - -That examples uses C<-a> to search through all files, but you may -use other default flags. Now you can search with F and easily -step through the results in Vim: - - :grep Dumper perllib - -=head2 Emacs integration - -Phil Jackson put together an F extension that "provides a -simple compilation mode ... has the ability to guess what files you -want to search for based on the major-mode." - -L - -=head2 TextMate integration - -Pedro Melo is a TextMate user who writes "I spend my day mostly -inside TextMate, and the built-in find-in-project sucks with large -projects. So I hacked a TextMate command that was using find + -grep to use ack. The result is the Search in Project with ack, and -you can find it here: -L" - -=head2 Shell and Return Code - -For greater compatibility with I, I in normal use returns -shell return or exit code of 0 only if something is found and 1 if -no match is found. - -(Shell exit code 1 is C<$?=256> in perl with C or backticks.) - -The I code 2 for errors is not used. - -If C<-f> or C<-g> are specified, then 0 is returned if at least one -file is found. If no files are found, then 1 is returned. - -=cut - -=head1 DEBUGGING ACK PROBLEMS - -If ack gives you output you're not expecting, start with a few simple steps. - -=head2 Use B<--noenv> - -Your environment variables and F<.ackrc> may be doing things you're -not expecting, or forgotten you specified. Use B<--noenv> to ignore -your environment and F<.ackrc>. - -=head2 Use B<-f> to see what files you're scanning - -The reason I created B<-f> in the first place was as a debugging -tool. If ack is not finding matches you think it should find, run -F to see what files are being checked. - -=head1 TIPS - -=head2 Use the F<.ackrc> file. - -The F<.ackrc> is the place to put all your options you use most of -the time but don't want to remember. Put all your --type-add and ---type-set definitions in it. If you like --smart-case, set it -there, too. I also set --sort-files there. - -=head2 Use F<-f> for working with big codesets - -Ack does more than search files. C will create a -list of all the Perl files in a tree, ideal for sending into F. -For example: - - # Change all "this" to "that" in all Perl files in a tree. - ack -f --perl | xargs perl -p -i -e's/this/that/g' - -or if you prefer: - - perl -p -i -e's/this/thatg/' $(ack -f --perl) - -=head2 Use F<-Q> when in doubt about metacharacters - -If you're searching for something with a regular expression -metacharacter, most often a period in a filename or IP address, add -the -Q to avoid false positives without all the backslashing. See -the following example for more... - -=head2 Use ack to watch log files - -Here's one I used the other day to find trouble spots for a website -visitor. The user had a problem loading F, so I -took the access log and scanned it with ack twice. - - ack -Q aa.bb.cc.dd /path/to/access.log | ack -Q -B5 troublesome.gif - -The first ack finds only the lines in the Apache log for the given -IP. The second finds the match on my troublesome GIF, and shows -the previous five lines from the log in each case. - -=head2 Share your knowledge - -Join the ack-users mailing list. Send me your tips and I may add -them here. - -=head1 FAQ - -=head2 Why isn't ack finding a match in (some file)? - -Probably because it's of a type that ack doesn't recognize. ack's -searching behavior is driven by filetype. B - -Use the C<-f> switch to see a list of files that ack will search -for you. - -If you want ack to search files that it doesn't recognize, use the -C<-a> switch. - -If you want ack to search every file, even ones that it always -ignores like coredumps and backup files, use the C<-u> switch. - -=head2 Why does ack ignore unknown files by default? - -ack is designed by a programmer, for programmers, for searching -large trees of code. Most codebases have a lot files in them which -aren't source files (like compiled object files, source control -metadata, etc), and grep wastes a lot of time searching through all -of those as well and returning matches from those files. - -That's why ack's behavior of not searching things it doesn't recognize -is one of its greatest strengths: the speed you get from only -searching the things that you want to be looking at. - -=head2 Wouldn't it be great if F did search & replace? - -No, ack will always be read-only. Perl has a perfectly good way -to do search & replace in files, using the C<-i>, C<-p> and C<-n> -switches. - -You can certainly use ack to select your files to update. For -example, to change all "foo" to "bar" in all PHP files, you can do -this from the Unix shell: - - $ perl -i -p -e's/foo/bar/g' $(ack -f --php) - -=head2 Can you make ack recognize F<.xyz> files? - -That's an enhancement. Please see the section in the manual about -enhancements. - -=head2 There's already a program/package called ack. - -Yes, I know. - -=head2 Why is it called ack if it's called ack-grep? - -The name of the program is "ack". Some packagers have called it -"ack-grep" when creating packages because there's already a package -out there called "ack" that has nothing to do with this ack. - -I suggest you make a symlink named F that points to F -because one of the crucial benefits of ack is having a name that's -so short and simple to type. - -To do that, run this with F or as root: - - ln -s /usr/bin/ack-grep /usr/bin/ack - -=head2 What does F mean? - -Nothing. I wanted a name that was easy to type and that you could -pronounce as a single syllable. - -=head2 Can I do multi-line regexes? - -No, ack does not support regexes that match multiple lines. Doing -so would require reading in the entire file at a time. - -If you want to see lines near your match, use the C<--A>, C<--B> -and C<--C> switches for displaying context. - -=head1 AUTHOR - -Andy Lester, C<< >> - -=head1 BUGS - -Please report any bugs or feature requests to the issues list at -Github: L - -=head1 ENHANCEMENTS - -All enhancement requests MUST first be posted to the ack-users -mailing list at L. I -will not consider a request without it first getting seen by other -ack users. This includes requests for new filetypes. - -There is a list of enhancements I want to make to F in the ack -issues list at Github: L - -Patches are always welcome, but patches with tests get the most -attention. - -=head1 SUPPORT - -Support for and information about F can be found at: - -=over 4 - -=item * The ack homepage - -L - -=item * The ack issues list at Github - -L - -=item * AnnoCPAN: Annotated CPAN documentation - -L - -=item * CPAN Ratings - -L - -=item * Search CPAN - -L - -=item * Git source repository - -L - -=back - -=head1 ACKNOWLEDGEMENTS - -How appropriate to have Inowledgements! - -Thanks to everyone who has contributed to ack in any way, including -Matthew Wild, -Scott Kyle, -Nick Hooey, -Bo Borgerson, -Mark Szymanski, -Marq Schneider, -Packy Anderson, -JR Boyens, -Dan Sully, -Ryan Niebur, -Kent Fredric, -Mike Morearty, -Ingmar Vanhassel, -Eric Van Dewoestine, -Sitaram Chamarty, -Adam James, -Richard Carlsson, -Pedro Melo, -AJ Schuster, -Phil Jackson, -Michael Schwern, -Jan Dubois, -Christopher J. Madsen, -Matthew Wickline, -David Dyck, -Jason Porritt, -Jjgod Jiang, -Thomas Klausner, -Uri Guttman, -Peter Lewis, -Kevin Riggle, -Ori Avtalion, -Torsten Blix, -Nigel Metheringham, -GEbor SzabE, -Tod Hagan, -Michael Hendricks, -Evar ArnfjErE Bjarmason, -Piers Cawley, -Stephen Steneker, -Elias Lutfallah, -Mark Leighton Fisher, -Matt Diephouse, -Christian Jaeger, -Bill Sully, -Bill Ricker, -David Golden, -Nilson Santos F. Jr, -Elliot Shank, -Merijn Broeren, -Uwe Voelker, -Rick Scott, -Ask BjErn Hansen, -Jerry Gay, -Will Coleda, -Mike O'Regan, -Slaven ReziE<0x107>, -Mark Stosberg, -David Alan Pisoni, -Adriano Ferreira, -James Keenan, -Leland Johnson, -Ricardo Signes -and Pete Krawczyk. - -=head1 COPYRIGHT & LICENSE - -Copyright 2005-2011 Andy Lester. - -This program is free software; you can redistribute it and/or modify -it under the terms of the Artistic License v2.0. - -=cut -package File::Next; - -use strict; -use warnings; - - -our $VERSION = '1.06'; - - - -use File::Spec (); - - -our $name; # name of the current file -our $dir; # dir of the current file - -our %files_defaults; -our %skip_dirs; - -BEGIN { - %files_defaults = ( - file_filter => undef, - descend_filter => undef, - error_handler => sub { CORE::die @_ }, - sort_files => undef, - follow_symlinks => 1, - ); - %skip_dirs = map {($_,1)} (File::Spec->curdir, File::Spec->updir); -} - - -sub files { - ($_[0] eq __PACKAGE__) && die 'File::Next::files must not be invoked as File::Next->files'; - - my ($parms,@queue) = _setup( \%files_defaults, @_ ); - my $filter = $parms->{file_filter}; - - return sub { - while (@queue) { - my ($dir,$file,$fullpath) = splice( @queue, 0, 3 ); - if ( -f $fullpath ) { - if ( $filter ) { - local $_ = $file; - local $File::Next::dir = $dir; - local $File::Next::name = $fullpath; - next if not $filter->(); - } - return wantarray ? ($dir,$file,$fullpath) : $fullpath; - } - elsif ( -d _ ) { - unshift( @queue, _candidate_files( $parms, $fullpath ) ); - } - } # while - - return; - }; # iterator -} - - - - - - - -sub sort_standard($$) { return $_[0]->[1] cmp $_[1]->[1] } -sub sort_reverse($$) { return $_[1]->[1] cmp $_[0]->[1] } - -sub reslash { - my $path = shift; - - my @parts = split( /\//, $path ); - - return $path if @parts < 2; - - return File::Spec->catfile( @parts ); -} - - - -sub _setup { - my $defaults = shift; - my $passed_parms = ref $_[0] eq 'HASH' ? {%{+shift}} : {}; # copy parm hash - - my %passed_parms = %{$passed_parms}; - - my $parms = {}; - for my $key ( keys %{$defaults} ) { - $parms->{$key} = - exists $passed_parms{$key} - ? delete $passed_parms{$key} - : $defaults->{$key}; - } - - # Any leftover keys are bogus - for my $badkey ( keys %passed_parms ) { - my $sub = (caller(1))[3]; - $parms->{error_handler}->( "Invalid option passed to $sub(): $badkey" ); - } - - # If it's not a code ref, assume standard sort - if ( $parms->{sort_files} && ( ref($parms->{sort_files}) ne 'CODE' ) ) { - $parms->{sort_files} = \&sort_standard; - } - my @queue; - - for ( @_ ) { - my $start = reslash( $_ ); - if (-d $start) { - push @queue, ($start,undef,$start); - } - else { - push @queue, (undef,$start,$start); - } - } - - return ($parms,@queue); -} - - -sub _candidate_files { - my $parms = shift; - my $dir = shift; - - my $dh; - if ( !opendir $dh, $dir ) { - $parms->{error_handler}->( "$dir: $!" ); - return; - } - - my @newfiles; - my $descend_filter = $parms->{descend_filter}; - my $follow_symlinks = $parms->{follow_symlinks}; - my $sort_sub = $parms->{sort_files}; - - for my $file ( grep { !exists $skip_dirs{$_} } readdir $dh ) { - my $has_stat; - - # Only do directory checking if we have a descend_filter - my $fullpath = File::Spec->catdir( $dir, $file ); - if ( !$follow_symlinks ) { - next if -l $fullpath; - $has_stat = 1; - } - - if ( $descend_filter ) { - if ( $has_stat ? (-d _) : (-d $fullpath) ) { - local $File::Next::dir = $fullpath; - local $_ = $file; - next if not $descend_filter->(); - } - } - if ( $sort_sub ) { - push( @newfiles, [ $dir, $file, $fullpath ] ); - } - else { - push( @newfiles, $dir, $file, $fullpath ); - } - } - closedir $dh; - - if ( $sort_sub ) { - return map { @{$_} } sort $sort_sub @newfiles; - } - - return @newfiles; -} - - -1; # End of File::Next -package App::Ack; - -use warnings; -use strict; - - - - -our $VERSION; -our $COPYRIGHT; -BEGIN { - $VERSION = '1.96'; - $COPYRIGHT = 'Copyright 2005-2011 Andy Lester.'; -} - -our $fh; - -BEGIN { - $fh = *STDOUT; -} - - -our %types; -our %type_wanted; -our %mappings; -our %ignore_dirs; - -our $input_from_pipe; -our $output_to_pipe; - -our $dir_sep_chars; -our $is_cygwin; -our $is_windows; - -use File::Spec (); -use File::Glob ':glob'; -use Getopt::Long (); - -BEGIN { - %ignore_dirs = ( - '.bzr' => 'Bazaar', - '.cdv' => 'Codeville', - '~.dep' => 'Interface Builder', - '~.dot' => 'Interface Builder', - '~.nib' => 'Interface Builder', - '~.plst' => 'Interface Builder', - '.git' => 'Git', - '.hg' => 'Mercurial', - '.pc' => 'quilt', - '.svn' => 'Subversion', - _MTN => 'Monotone', - blib => 'Perl module building', - CVS => 'CVS', - RCS => 'RCS', - SCCS => 'SCCS', - _darcs => 'darcs', - _sgbak => 'Vault/Fortress', - 'autom4te.cache' => 'autoconf', - 'cover_db' => 'Devel::Cover', - _build => 'Module::Build', - ); - - %mappings = ( - actionscript => [qw( as mxml )], - ada => [qw( ada adb ads )], - asm => [qw( asm s )], - batch => [qw( bat cmd )], - binary => q{Binary files, as defined by Perl's -B op (default: off)}, - cc => [qw( c h xs )], - cfmx => [qw( cfc cfm cfml )], - clojure => [qw( clj )], - cpp => [qw( cpp cc cxx m hpp hh h hxx )], - csharp => [qw( cs )], - css => [qw( css )], - delphi => [qw( pas int dfm nfm dof dpk dproj groupproj bdsgroup bdsproj )], - elisp => [qw( el )], - erlang => [qw( erl hrl )], - fortran => [qw( f f77 f90 f95 f03 for ftn fpp )], - go => [qw( go )], - groovy => [qw( groovy gtmpl gpp grunit )], - haskell => [qw( hs lhs )], - hh => [qw( h )], - html => [qw( htm html shtml xhtml )], - java => [qw( java properties )], - js => [qw( js )], - jsp => [qw( jsp jspx jhtm jhtml )], - lisp => [qw( lisp lsp )], - lua => [qw( lua )], - make => q{Makefiles (including *.mk and *.mak)}, - mason => [qw( mas mhtml mpl mtxt )], - objc => [qw( m h )], - objcpp => [qw( mm h )], - ocaml => [qw( ml mli )], - parrot => [qw( pir pasm pmc ops pod pg tg )], - perl => [qw( pl pm pm6 pod t )], - php => [qw( php phpt php3 php4 php5 phtml)], - plone => [qw( pt cpt metadata cpy py )], - python => [qw( py )], - rake => q{Rakefiles}, - ruby => [qw( rb rhtml rjs rxml erb rake spec )], - scala => [qw( scala )], - scheme => [qw( scm ss )], - shell => [qw( sh bash csh tcsh ksh zsh )], - skipped => q{Files, but not directories, normally skipped by ack (default: off)}, - smalltalk => [qw( st )], - sql => [qw( sql ctl )], - tcl => [qw( tcl itcl itk )], - tex => [qw( tex cls sty )], - text => q{Text files, as defined by Perl's -T op (default: off)}, - tt => [qw( tt tt2 ttml )], - vb => [qw( bas cls frm ctl vb resx )], - verilog => [qw( v vh sv )], - vhdl => [qw( vhd vhdl )], - vim => [qw( vim )], - yaml => [qw( yaml yml )], - xml => [qw( xml dtd xsl xslt ent )], - ); - - while ( my ($type,$exts) = each %mappings ) { - if ( ref $exts ) { - for my $ext ( @{$exts} ) { - push( @{$types{$ext}}, $type ); - } - } - } - # add manually Makefile extensions - push @{$types{$_}}, 'make' for qw{ mk mak }; - - # These have to be checked before any filehandle diddling. - $output_to_pipe = not -t *STDOUT; - $input_from_pipe = -p STDIN; - - $is_cygwin = ($^O eq 'cygwin'); - $is_windows = ($^O =~ /MSWin32/); - $dir_sep_chars = $is_windows ? quotemeta( '\\/' ) : quotemeta( File::Spec->catfile( '', '' ) ); -} - - -sub read_ackrc { - my @files = ( $ENV{ACKRC} ); - my @dirs = - $is_windows - ? ( $ENV{HOME}, $ENV{USERPROFILE} ) - : ( '~', $ENV{HOME} ); - for my $dir ( grep { defined } @dirs ) { - for my $file ( '.ackrc', '_ackrc' ) { - push( @files, bsd_glob( "$dir/$file", GLOB_TILDE ) ); - } - } - for my $filename ( @files ) { - if ( defined $filename && -e $filename ) { - open( my $fh, '<', $filename ) or App::Ack::die( "$filename: $!\n" ); - my @lines = grep { /./ && !/^\s*#/ } <$fh>; - chomp @lines; - close $fh or App::Ack::die( "$filename: $!\n" ); - - # get rid of leading and trailing whitespaces - for ( @lines ) { - s/^\s+//; - s/\s+$//; - } - - return @lines; - } - } - - return; -} - - -sub get_command_line_options { - my %opt = ( - pager => $ENV{ACK_PAGER_COLOR} || $ENV{ACK_PAGER}, - ); - - my $getopt_specs = { - 1 => sub { $opt{1} = $opt{m} = 1 }, - 'A|after-context=i' => \$opt{after_context}, - 'B|before-context=i' => \$opt{before_context}, - 'C|context:i' => sub { shift; my $val = shift; $opt{before_context} = $opt{after_context} = ($val || 2) }, - 'a|all-types' => \$opt{all}, - 'break!' => \$opt{break}, - c => \$opt{count}, - 'color|colour!' => \$opt{color}, - 'color-match=s' => \$ENV{ACK_COLOR_MATCH}, - 'color-filename=s' => \$ENV{ACK_COLOR_FILENAME}, - 'color-lineno=s' => \$ENV{ACK_COLOR_LINENO}, - 'column!' => \$opt{column}, - count => \$opt{count}, - 'env!' => sub { }, # ignore this option, it is handled beforehand - f => \$opt{f}, - flush => \$opt{flush}, - 'follow!' => \$opt{follow}, - 'g=s' => sub { shift; $opt{G} = shift; $opt{f} = 1 }, - 'G=s' => \$opt{G}, - 'group!' => sub { shift; $opt{heading} = $opt{break} = shift }, - 'heading!' => \$opt{heading}, - 'h|no-filename' => \$opt{h}, - 'H|with-filename' => \$opt{H}, - 'i|ignore-case' => \$opt{i}, - 'invert-file-match' => \$opt{invert_file_match}, - 'lines=s' => sub { shift; my $val = shift; push @{$opt{lines}}, $val }, - 'l|files-with-matches' => \$opt{l}, - 'L|files-without-matches' => sub { $opt{l} = $opt{v} = 1 }, - 'm|max-count=i' => \$opt{m}, - 'match=s' => \$opt{regex}, - 'n|no-recurse' => \$opt{n}, - o => sub { $opt{output} = '$&' }, - 'output=s' => \$opt{output}, - 'pager=s' => \$opt{pager}, - 'nopager' => sub { $opt{pager} = undef }, - 'passthru' => \$opt{passthru}, - 'print0' => \$opt{print0}, - 'Q|literal' => \$opt{Q}, - 'r|R|recurse' => sub { $opt{n} = 0 }, - 'show-types' => \$opt{show_types}, - 'smart-case!' => \$opt{smart_case}, - 'sort-files' => \$opt{sort_files}, - 'u|unrestricted' => \$opt{u}, - 'v|invert-match' => \$opt{v}, - 'w|word-regexp' => \$opt{w}, - - 'ignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); $ignore_dirs{$dir} = '--ignore-dirs' }, - 'noignore-dirs=s' => sub { shift; my $dir = remove_dir_sep( shift ); delete $ignore_dirs{$dir} }, - - 'version' => sub { print_version_statement(); exit; }, - 'help|?:s' => sub { shift; show_help(@_); exit; }, - 'help-types'=> sub { show_help_types(); exit; }, - 'man' => sub { - require Pod::Usage; - Pod::Usage::pod2usage({ - -verbose => 2, - -exitval => 0, - }); - }, - - 'type=s' => sub { - # Whatever --type=xxx they specify, set it manually in the hash - my $dummy = shift; - my $type = shift; - my $wanted = ($type =~ s/^no//) ? 0 : 1; # must not be undef later - - if ( exists $type_wanted{ $type } ) { - $type_wanted{ $type } = $wanted; - } - else { - App::Ack::die( qq{Unknown --type "$type"} ); - } - }, # type sub - }; - - # Stick any default switches at the beginning, so they can be overridden - # by the command line switches. - unshift @ARGV, split( ' ', $ENV{ACK_OPTIONS} ) if defined $ENV{ACK_OPTIONS}; - - # first pass through options, looking for type definitions - def_types_from_ARGV(); - - for my $i ( filetypes_supported() ) { - $getopt_specs->{ "$i!" } = \$type_wanted{ $i }; - } - - - my $parser = Getopt::Long::Parser->new(); - $parser->configure( 'bundling', 'no_ignore_case', ); - $parser->getoptions( %{$getopt_specs} ) or - App::Ack::die( 'See ack --help, ack --help-types or ack --man for options.' ); - - my $to_screen = not output_to_pipe(); - my %defaults = ( - all => 0, - color => $to_screen, - follow => 0, - break => $to_screen, - heading => $to_screen, - before_context => 0, - after_context => 0, - ); - if ( $is_windows && $defaults{color} && not $ENV{ACK_PAGER_COLOR} ) { - if ( $ENV{ACK_PAGER} || not eval { require Win32::Console::ANSI } ) { - $defaults{color} = 0; - } - } - if ( $to_screen && $ENV{ACK_PAGER_COLOR} ) { - $defaults{color} = 1; - } - - while ( my ($key,$value) = each %defaults ) { - if ( not defined $opt{$key} ) { - $opt{$key} = $value; - } - } - - if ( defined $opt{m} && $opt{m} <= 0 ) { - App::Ack::die( '-m must be greater than zero' ); - } - - for ( qw( before_context after_context ) ) { - if ( defined $opt{$_} && $opt{$_} < 0 ) { - App::Ack::die( "--$_ may not be negative" ); - } - } - - if ( defined( my $val = $opt{output} ) ) { - $opt{output} = eval qq[ sub { "$val" } ]; - } - if ( defined( my $l = $opt{lines} ) ) { - # --line=1 --line=5 is equivalent to --line=1,5 - my @lines = split( /,/, join( ',', @{$l} ) ); - - # --line=1-3 is equivalent to --line=1,2,3 - @lines = map { - my @ret; - if ( /-/ ) { - my ($from, $to) = split /-/, $_; - if ( $from > $to ) { - App::Ack::warn( "ignoring --line=$from-$to" ); - @ret = (); - } - else { - @ret = ( $from .. $to ); - } - } - else { - @ret = ( $_ ); - }; - @ret - } @lines; - - if ( @lines ) { - my %uniq; - @uniq{ @lines } = (); - $opt{lines} = [ sort { $a <=> $b } keys %uniq ]; # numerical sort and each line occurs only once! - } - else { - # happens if there are only ignored --line directives - App::Ack::die( 'All --line options are invalid.' ); - } - } - - return \%opt; -} - - -sub def_types_from_ARGV { - my @typedef; - - my $parser = Getopt::Long::Parser->new(); - # pass_through => leave unrecognized command line arguments alone - # no_auto_abbrev => otherwise -c is expanded and not left alone - $parser->configure( 'no_ignore_case', 'pass_through', 'no_auto_abbrev' ); - $parser->getoptions( - 'type-set=s' => sub { shift; push @typedef, ['c', shift] }, - 'type-add=s' => sub { shift; push @typedef, ['a', shift] }, - ) or App::Ack::die( 'See ack --help or ack --man for options.' ); - - for my $td (@typedef) { - my ($type, $ext) = split /=/, $td->[1]; - - if ( $td->[0] eq 'c' ) { - # type-set - if ( exists $mappings{$type} ) { - # can't redefine types 'make', 'skipped', 'text' and 'binary' - App::Ack::die( qq{--type-set: Builtin type "$type" cannot be changed.} ) - if ref $mappings{$type} ne 'ARRAY'; - - delete_type($type); - } - } - else { - # type-add - - # can't append to types 'make', 'skipped', 'text' and 'binary' - App::Ack::die( qq{--type-add: Builtin type "$type" cannot be changed.} ) - if exists $mappings{$type} && ref $mappings{$type} ne 'ARRAY'; - - App::Ack::warn( qq{--type-add: Type "$type" does not exist, creating with "$ext" ...} ) - unless exists $mappings{$type}; - } - - my @exts = split /,/, $ext; - s/^\.// for @exts; - - if ( !exists $mappings{$type} || ref($mappings{$type}) eq 'ARRAY' ) { - push @{$mappings{$type}}, @exts; - for my $e ( @exts ) { - push @{$types{$e}}, $type; - } - } - else { - App::Ack::die( qq{Cannot append to type "$type".} ); - } - } - - return; -} - - -sub delete_type { - my $type = shift; - - App::Ack::die( qq{Internal error: Cannot delete builtin type "$type".} ) - unless ref $mappings{$type} eq 'ARRAY'; - - delete $mappings{$type}; - delete $type_wanted{$type}; - for my $ext ( keys %types ) { - $types{$ext} = [ grep { $_ ne $type } @{$types{$ext}} ]; - } -} - - -sub ignoredir_filter { - return !exists $ignore_dirs{$_} && !exists $ignore_dirs{$File::Next::dir}; -} - - -sub remove_dir_sep { - my $path = shift; - $path =~ s/[$dir_sep_chars]$//; - - return $path; -} - - -use constant TEXT => 'text'; - -sub filetypes { - my $filename = shift; - - my $basename = $filename; - $basename =~ s{.*[$dir_sep_chars]}{}; - - return 'skipped' unless is_searchable( $basename ); - - my $lc_basename = lc $basename; - return ('make',TEXT) if $lc_basename eq 'makefile' || $lc_basename eq 'gnumakefile'; - return ('rake','ruby',TEXT) if $lc_basename eq 'rakefile'; - - # If there's an extension, look it up - if ( $filename =~ m{\.([^\.$dir_sep_chars]+)$}o ) { - my $ref = $types{lc $1}; - return (@{$ref},TEXT) if $ref; - } - - # At this point, we can't tell from just the name. Now we have to - # open it and look inside. - - return unless -e $filename; - # From Elliot Shank: - # I can't see any reason that -r would fail on these-- the ACLs look - # fine, and no program has any of them open, so the busted Windows - # file locking model isn't getting in there. If I comment the if - # statement out, everything works fine - # So, for cygwin, don't bother trying to check for readability. - if ( !$is_cygwin ) { - if ( !-r $filename ) { - App::Ack::warn( "$filename: Permission denied" ); - return; - } - } - - return 'binary' if -B $filename; - - # If there's no extension, or we don't recognize it, check the shebang line - my $fh; - if ( !open( $fh, '<', $filename ) ) { - App::Ack::warn( "$filename: $!" ); - return; - } - my $header = <$fh>; - close $fh; - - if ( $header =~ /^#!/ ) { - return ($1,TEXT) if $header =~ /\b(ruby|lua|p(?:erl|hp|ython))-?(\d[\d.]*)?\b/; - return ('shell',TEXT) if $header =~ /\b(?:ba|t?c|k|z)?sh\b/; - } - else { - return ('xml',TEXT) if $header =~ /\Q{Q}; - if ( $opt->{w} ) { - $str = "\\b$str" if $str =~ /^\w/; - $str = "$str\\b" if $str =~ /\w$/; - } - - my $regex_is_lc = $str eq lc $str; - if ( $opt->{i} || ($opt->{smart_case} && $regex_is_lc) ) { - $str = "(?i)$str"; - } - - return $str; -} - - -sub check_regex { - my $regex = shift; - - return unless defined $regex; - - eval { qr/$regex/ }; - if ($@) { - (my $error = $@) =~ s/ at \S+ line \d+.*//; - chomp($error); - App::Ack::die( "Invalid regex '$regex':\n $error" ); - } - - return; -} - - - - -sub warn { - return CORE::warn( _my_program(), ': ', @_, "\n" ); -} - - -sub die { - return CORE::die( _my_program(), ': ', @_, "\n" ); -} - -sub _my_program { - require File::Basename; - return File::Basename::basename( $0 ); -} - - - -sub filetypes_supported { - return keys %mappings; -} - -sub _get_thpppt { - my $y = q{_ /|,\\'!.x',=(www)=, U }; - $y =~ tr/,x!w/\nOo_/; - return $y; -} - -sub _thpppt { - my $y = _get_thpppt(); - App::Ack::print( "$y ack $_[0]!\n" ); - exit 0; -} - -sub _key { - my $str = lc shift; - $str =~ s/[^a-z]//g; - - return $str; -} - - -sub show_help { - my $help_arg = shift || 0; - - return show_help_types() if $help_arg =~ /^types?/; - - my $ignore_dirs = _listify( sort { _key($a) cmp _key($b) } keys %ignore_dirs ); - - App::Ack::print( <<"END_OF_HELP" ); -Usage: ack [OPTION]... PATTERN [FILE] - -Search for PATTERN in each source file in the tree from cwd on down. -If [FILES] is specified, then only those files/directories are checked. -ack may also search STDIN, but only if no FILE are specified, or if -one of FILES is "-". - -Default switches may be specified in ACK_OPTIONS environment variable or -an .ackrc file. If you want no dependency on the environment, turn it -off with --noenv. - -Example: ack -i select - -Searching: - -i, --ignore-case Ignore case distinctions in PATTERN - --[no]smart-case Ignore case distinctions in PATTERN, - only if PATTERN contains no upper case - Ignored if -i is specified - -v, --invert-match Invert match: select non-matching lines - -w, --word-regexp Force PATTERN to match only whole words - -Q, --literal Quote all metacharacters; PATTERN is literal - -Search output: - --line=NUM Only print line(s) NUM of each file - -l, --files-with-matches - Only print filenames containing matches - -L, --files-without-matches - Only print filenames with no matches - -o Show only the part of a line matching PATTERN - (turns off text highlighting) - --passthru Print all lines, whether matching or not - --output=expr Output the evaluation of expr for each line - (turns off text highlighting) - --match PATTERN Specify PATTERN explicitly. - -m, --max-count=NUM Stop searching in each file after NUM matches - -1 Stop searching after one match of any kind - -H, --with-filename Print the filename for each match - -h, --no-filename Suppress the prefixing filename on output - -c, --count Show number of lines matching per file - --column Show the column number of the first match - - -A NUM, --after-context=NUM - Print NUM lines of trailing context after matching - lines. - -B NUM, --before-context=NUM - Print NUM lines of leading context before matching - lines. - -C [NUM], --context[=NUM] - Print NUM lines (default 2) of output context. - - --print0 Print null byte as separator between filenames, - only works with -f, -g, -l, -L or -c. - -File presentation: - --pager=COMMAND Pipes all ack output through COMMAND. For example, - --pager="less -R". Ignored if output is redirected. - --nopager Do not send output through a pager. Cancels any - setting in ~/.ackrc, ACK_PAGER or ACK_PAGER_COLOR. - --[no]heading Print a filename heading above each file's results. - (default: on when used interactively) - --[no]break Print a break between results from different files. - (default: on when used interactively) - --group Same as --heading --break - --nogroup Same as --noheading --nobreak - --[no]color Highlight the matching text (default: on unless - output is redirected, or on Windows) - --[no]colour Same as --[no]color - --color-filename=COLOR - --color-match=COLOR - --color-lineno=COLOR Set the color for filenames, matches, and line numbers. - --flush Flush output immediately, even when ack is used - non-interactively (when output goes to a pipe or - file). - -File finding: - -f Only print the files found, without searching. - The PATTERN must not be specified. - -g REGEX Same as -f, but only print files matching REGEX. - --sort-files Sort the found files lexically. - --invert-file-match Print/search handle files that do not match -g/-G. - --show-types Show which types each file has. - -File inclusion/exclusion: - -a, --all-types All file types searched; - Ignores CVS, .svn and other ignored directories - -u, --unrestricted All files and directories searched - --[no]ignore-dir=name Add/Remove directory from the list of ignored dirs - -r, -R, --recurse Recurse into subdirectories (ack's default behavior) - -n, --no-recurse No descending into subdirectories - -G REGEX Only search files that match REGEX - - --perl Include only Perl files. - --type=perl Include only Perl files. - --noperl Exclude Perl files. - --type=noperl Exclude Perl files. - See "ack --help type" for supported filetypes. - - --type-set TYPE=.EXTENSION[,.EXT2[,...]] - Files with the given EXTENSION(s) are recognized as - being of type TYPE. This replaces an existing - definition for type TYPE. - --type-add TYPE=.EXTENSION[,.EXT2[,...]] - Files with the given EXTENSION(s) are recognized as - being of (the existing) type TYPE - - --[no]follow Follow symlinks. Default is off. - - Directories ignored by default: - $ignore_dirs - - Files not checked for type: - /~\$/ - Unix backup files - /#.+#\$/ - Emacs swap files - /[._].*\\.swp\$/ - Vi(m) swap files - /core\\.\\d+\$/ - core dumps - /[.-]min\\.js\$/ - Minified javascript files - -Miscellaneous: - --noenv Ignore environment variables and ~/.ackrc - --help This help - --man Man page - --version Display version & copyright - --thpppt Bill the Cat - -Exit status is 0 if match, 1 if no match. - -This is version $VERSION of ack. -END_OF_HELP - - return; - } - - - -sub show_help_types { - App::Ack::print( <<'END_OF_HELP' ); -Usage: ack [OPTION]... PATTERN [FILES] - -The following is the list of filetypes supported by ack. You can -specify a file type with the --type=TYPE format, or the --TYPE -format. For example, both --type=perl and --perl work. - -Note that some extensions may appear in multiple types. For example, -.pod files are both Perl and Parrot. - -END_OF_HELP - - my @types = filetypes_supported(); - my $maxlen = 0; - for ( @types ) { - $maxlen = length if $maxlen < length; - } - for my $type ( sort @types ) { - next if $type =~ /^-/; # Stuff to not show - my $ext_list = $mappings{$type}; - - if ( ref $ext_list ) { - $ext_list = join( ' ', map { ".$_" } @{$ext_list} ); - } - App::Ack::print( sprintf( " --[no]%-*.*s %s\n", $maxlen, $maxlen, $type, $ext_list ) ); - } - - return; -} - -sub _listify { - my @whats = @_; - - return '' if !@whats; - - my $end = pop @whats; - my $str = @whats ? join( ', ', @whats ) . " and $end" : $end; - - no warnings 'once'; - require Text::Wrap; - $Text::Wrap::columns = 75; - return Text::Wrap::wrap( '', ' ', $str ); -} - - -sub get_version_statement { - require Config; - - my $copyright = get_copyright(); - my $this_perl = $Config::Config{perlpath}; - if ($^O ne 'VMS') { - my $ext = $Config::Config{_exe}; - $this_perl .= $ext unless $this_perl =~ m/$ext$/i; - } - my $ver = sprintf( '%vd', $^V ); - - return <<"END_OF_VERSION"; -ack $VERSION -Running under Perl $ver at $this_perl - -$copyright - -This program is free software. You may modify or distribute it -under the terms of the Artistic License v2.0. -END_OF_VERSION -} - - -sub print_version_statement { - App::Ack::print( get_version_statement() ); - - return; -} - - -sub get_copyright { - return $COPYRIGHT; -} - - -sub load_colors { - eval 'use Term::ANSIColor ()'; - - $ENV{ACK_COLOR_MATCH} ||= 'black on_yellow'; - $ENV{ACK_COLOR_FILENAME} ||= 'bold green'; - $ENV{ACK_COLOR_LINENO} ||= 'bold yellow'; - - return; -} - - -sub is_interesting { - return if /^\./; - - my $include; - - for my $type ( filetypes( $File::Next::name ) ) { - if ( defined $type_wanted{$type} ) { - if ( $type_wanted{$type} ) { - $include = 1; - } - else { - return; - } - } - } - - return $include; -} - - - -# print subs added in order to make it easy for a third party -# module (such as App::Wack) to redefine the display methods -# and show the results in a different way. -sub print { print {$fh} @_ } -sub print_first_filename { App::Ack::print( $_[0], "\n" ) } -sub print_blank_line { App::Ack::print( "\n" ) } -sub print_separator { App::Ack::print( "--\n" ) } -sub print_filename { App::Ack::print( $_[0], $_[1] ) } -sub print_line_no { App::Ack::print( $_[0], $_[1] ) } -sub print_column_no { App::Ack::print( $_[0], $_[1] ) } -sub print_count { - my $filename = shift; - my $nmatches = shift; - my $ors = shift; - my $count = shift; - my $show_filename = shift; - - if ($show_filename) { - App::Ack::print( $filename ); - App::Ack::print( ':', $nmatches ) if $count; - } - else { - App::Ack::print( $nmatches ) if $count; - } - App::Ack::print( $ors ); -} - -sub print_count0 { - my $filename = shift; - my $ors = shift; - my $show_filename = shift; - - if ($show_filename) { - App::Ack::print( $filename, ':0', $ors ); - } - else { - App::Ack::print( '0', $ors ); - } -} - - - -{ - my $filename; - my $regex; - my $display_filename; - - my $keep_context; - - my $last_output_line; # number of the last line that has been output - my $any_output; # has there been any output for the current file yet - my $context_overall_output_count; # has there been any output at all - -sub search_resource { - my $res = shift; - my $opt = shift; - - $filename = $res->name(); - - my $v = $opt->{v}; - my $passthru = $opt->{passthru}; - my $max = $opt->{m}; - my $nmatches = 0; - - $display_filename = undef; - - # for --line processing - my $has_lines = 0; - my @lines; - if ( defined $opt->{lines} ) { - $has_lines = 1; - @lines = ( @{$opt->{lines}}, -1 ); - undef $regex; # Don't match when printing matching line - } - else { - $regex = qr/$opt->{regex}/; - } - - # for context processing - $last_output_line = -1; - $any_output = 0; - my $before_context = $opt->{before_context}; - my $after_context = $opt->{after_context}; - - $keep_context = ($before_context || $after_context) && !$passthru; - - my @before; - my $before_starts_at_line; - my $after = 0; # number of lines still to print after a match - - while ( $res->next_text ) { - # XXX Optimize away the case when there are no more @lines to find. - # XXX $has_lines, $passthru and $v never change. Optimize. - if ( $has_lines - ? $. != $lines[0] # $lines[0] should be a scalar - : $v ? m/$regex/ : !m/$regex/ ) { - if ( $passthru ) { - App::Ack::print( $_ ); - next; - } - - if ( $keep_context ) { - if ( $after ) { - print_match_or_context( $opt, 0, $., $-[0], $+[0], $_ ); - $after--; - } - elsif ( $before_context ) { - if ( @before ) { - if ( @before >= $before_context ) { - shift @before; - ++$before_starts_at_line; - } - } - else { - $before_starts_at_line = $.; - } - push @before, $_; - } - last if $max && ( $nmatches >= $max ) && !$after; - } - next; - } # not a match - - ++$nmatches; - - # print an empty line as a divider before first line in each file (not before the first file) - if ( !$any_output && $opt->{show_filename} && $opt->{break} && defined( $context_overall_output_count ) ) { - App::Ack::print_blank_line(); - } - - shift @lines if $has_lines; - - if ( $res->is_binary ) { - App::Ack::print( "Binary file $filename matches\n" ); - last; - } - if ( $keep_context ) { - if ( @before ) { - print_match_or_context( $opt, 0, $before_starts_at_line, $-[0], $+[0], @before ); - @before = (); - $before_starts_at_line = 0; - } - if ( $max && $nmatches > $max ) { - --$after; - } - else { - $after = $after_context; - } - } - print_match_or_context( $opt, 1, $., $-[0], $+[0], $_ ); - - last if $max && ( $nmatches >= $max ) && !$after; - } # while - - return $nmatches; -} # search_resource() - - - -sub print_match_or_context { - my $opt = shift; # opts array - my $is_match = shift; # is there a match on the line? - my $line_no = shift; - my $match_start = shift; - my $match_end = shift; - - my $color = $opt->{color}; - my $heading = $opt->{heading}; - my $show_filename = $opt->{show_filename}; - my $show_column = $opt->{column}; - - if ( $show_filename ) { - if ( not defined $display_filename ) { - $display_filename = - $color - ? Term::ANSIColor::colored( $filename, $ENV{ACK_COLOR_FILENAME} ) - : $filename; - if ( $heading && !$any_output ) { - App::Ack::print_first_filename($display_filename); - } - } - } - - # Modified for Atom by Nathan Sobo to print a "\0" instead of a ":" as a separator - my $sep = $is_match ? "\0" : '-'; - my $output_func = $opt->{output}; - for ( @_ ) { - if ( $keep_context && !$output_func ) { - if ( ( $last_output_line != $line_no - 1 ) && - ( $any_output || ( !$heading && defined( $context_overall_output_count ) ) ) ) { - App::Ack::print_separator(); - } - # to ensure separators between different files when --noheading - - $last_output_line = $line_no; - } - - if ( $show_filename ) { - App::Ack::print_filename($display_filename, $sep) if not $heading; - my $display_line_no = - $color - ? Term::ANSIColor::colored( $line_no, $ENV{ACK_COLOR_LINENO} ) - : $line_no; - App::Ack::print_line_no($display_line_no, $sep); - } - - if ( $output_func ) { - while ( /$regex/go ) { - App::Ack::print( $output_func->() . "\n" ); - } - } - else { - if ( $color && $is_match && $regex && - s/$regex/Term::ANSIColor::colored( substr($_, $-[0], $+[0] - $-[0]), $ENV{ACK_COLOR_MATCH} )/eg ) { - # At the end of the line reset the color and remove newline - s/[\r\n]*\z/\e[0m\e[K/; - } - else { - # remove any kind of newline at the end of the line - s/[\r\n]*\z//; - } - if ( $show_column ) { - App::Ack::print_column_no( $match_start+1, $sep ); - } - App::Ack::print($_ . "\n"); - } - $any_output = 1; - ++$context_overall_output_count; - ++$line_no; - } - - return; -} # print_match_or_context() - -} # scope around search_resource() and print_match_or_context() - - -TOTAL_COUNT_SCOPE: { -my $total_count; - -sub get_total_count { - return $total_count; -} - -sub reset_total_count { - $total_count = 0; -} - - -sub search_and_list { - my $res = shift; - my $opt = shift; - - my $nmatches = 0; - my $count = $opt->{count}; - my $ors = $opt->{print0} ? "\0" : "\n"; # output record separator - my $show_filename = $opt->{show_filename}; - - my $regex = qr/$opt->{regex}/; - - if ( $opt->{v} ) { - while ( $res->next_text ) { - if ( /$regex/ ) { - return 0 unless $count; - } - else { - ++$nmatches; - } - } - } - else { - while ( $res->next_text ) { - if ( /$regex/ ) { - ++$nmatches; - last unless $count; - } - } - } - - if ( $opt->{show_total} ) { - $total_count += $nmatches; - } - else { - if ( $nmatches ) { - App::Ack::print_count( $res->name, $nmatches, $ors, $count, $show_filename ); - } - elsif ( $count && !$opt->{l} ) { - App::Ack::print_count0( $res->name, $ors, $show_filename ); - } - } - - return $nmatches ? 1 : 0; -} # search_and_list() - -} # scope around $total_count - - - -sub filetypes_supported_set { - return grep { defined $type_wanted{$_} && ($type_wanted{$_} == 1) } filetypes_supported(); -} - - - -sub print_files { - my $iter = shift; - my $opt = shift; - - my $ors = $opt->{print0} ? "\0" : "\n"; - - my $nmatches = 0; - while ( defined ( my $file = $iter->() ) ) { - App::Ack::print $file, $opt->{show_types} ? " => " . join( ',', filetypes( $file ) ) : (), $ors; - $nmatches++; - last if $opt->{1}; - } - - return $nmatches; -} - - -sub print_files_with_matches { - my $iter = shift; - my $opt = shift; - - # if we have -l and only 1 file given on command line (this means - # show_filename is set to 0), we want to see the filename nevertheless - $opt->{show_filename} = 1 if $opt->{l}; - - $opt->{show_filename} = 0 if $opt->{h}; - $opt->{show_filename} = 1 if $opt->{H}; - - # abuse options to hand in the show_total parameter to search_and_list - $opt->{show_total} = $opt->{count} && !$opt->{show_filename}; - reset_total_count(); - - my $nmatches = 0; - while ( defined ( my $filename = $iter->() ) ) { - my $repo = App::Ack::Repository::Basic->new( $filename ); - my $res; - while ( $res = $repo->next_resource() ) { - $nmatches += search_and_list( $res, $opt ); - $res->close(); - last if $nmatches && $opt->{1}; - } - $repo->close(); - } - - if ( $nmatches && $opt->{show_total} ) { - App::Ack::print_count('', get_total_count(), "\n", 1, 0 ) - } - - return $nmatches; -} - - -sub print_matches { - my $iter = shift; - my $opt = shift; - - $opt->{show_filename} = 0 if $opt->{h}; - $opt->{show_filename} = 1 if $opt->{H}; - - my $nmatches = 0; - while ( defined ( my $filename = $iter->() ) ) { - my $repo; - my $tarballs_work = 0; - if ( $tarballs_work && $filename =~ /\.tar\.gz$/ ) { - App::Ack::die( 'Not working here yet' ); - require App::Ack::Repository::Tar; # XXX Error checking - $repo = App::Ack::Repository::Tar->new( $filename ); - } - else { - $repo = App::Ack::Repository::Basic->new( $filename ); - } - $repo or next; - - while ( my $res = $repo->next_resource() ) { - my $needs_line_scan; - if ( $opt->{regex} && !$opt->{passthru} ) { - $needs_line_scan = $res->needs_line_scan( $opt ); - if ( $needs_line_scan ) { - $res->reset(); - } - } - else { - $needs_line_scan = 1; - } - if ( $needs_line_scan ) { - $nmatches += search_resource( $res, $opt ); - } - $res->close(); - } - last if $nmatches && $opt->{1}; - $repo->close(); - } - return $nmatches; -} - - -sub filetype_setup { - my $filetypes_supported_set = filetypes_supported_set(); - # If anyone says --no-whatever, we assume all other types must be on. - if ( !$filetypes_supported_set ) { - for my $i ( keys %type_wanted ) { - $type_wanted{$i} = 1 unless ( defined( $type_wanted{$i} ) || $i eq 'binary' || $i eq 'text' || $i eq 'skipped' ); - } - } - return; -} - - -EXPAND_FILENAMES_SCOPE: { - my $filter; - - sub expand_filenames { - my $argv = shift; - - my $attr; - my @files; - - foreach my $pattern ( @{$argv} ) { - my @results = bsd_glob( $pattern ); - - if (@results == 0) { - @results = $pattern; # Glob didn't match, pass it thru unchanged - } - elsif ( (@results > 1) or ($results[0] ne $pattern) ) { - if (not defined $filter) { - eval 'require Win32::File;'; - if ($@) { - $filter = 0; - } - else { - $filter = Win32::File::HIDDEN()|Win32::File::SYSTEM(); - } - } # end unless we've tried to load Win32::File - if ( $filter ) { - # Filter out hidden and system files: - @results = grep { not(Win32::File::GetAttributes($_, $attr) and $attr & $filter) } @results; - App::Ack::warn( "$pattern: Matched only hidden files" ) unless @results; - } # end if we can filter by file attributes - } # end elsif this pattern got expanded - - push @files, @results; - } # end foreach pattern - - return \@files; - } # end expand_filenames -} # EXPAND_FILENAMES_SCOPE - - - -sub get_starting_points { - my $argv = shift; - my $opt = shift; - - my @what; - - if ( @{$argv} ) { - @what = @{ $is_windows ? expand_filenames($argv) : $argv }; - $_ = File::Next::reslash( $_ ) for @what; - - # Show filenames unless we've specified one single file - $opt->{show_filename} = (@what > 1) || (!-f $what[0]); - } - else { - @what = '.'; # Assume current directory - $opt->{show_filename} = 1; - } - - for my $start_point (@what) { - App::Ack::warn( "$start_point: No such file or directory" ) unless -e $start_point; - } - return \@what; -} - -sub _match { - my ( $target, $expression, $invert_flag ) = @_; - - if ( $invert_flag ) { - return $target !~ $expression; - } - else { - return $target =~ $expression; - } -} - - -sub get_iterator { - my $what = shift; - my $opt = shift; - - # Starting points are always searched, no matter what - my %starting_point = map { ($_ => 1) } @{$what}; - - my $g_regex = defined $opt->{G} ? qr/$opt->{G}/ : undef; - my $file_filter; - - if ( $g_regex ) { - $file_filter - = $opt->{u} ? sub { _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) } # XXX Maybe this should be a 1, no? - : $opt->{all} ? sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_searchable( $_ ) ) } - : sub { $starting_point{ $File::Next::name } || ( _match( $File::Next::name, qr/$g_regex/, $opt->{invert_file_match} ) && is_interesting( @ _) ) } - ; - } - else { - $file_filter - = $opt->{u} ? sub {1} - : $opt->{all} ? sub { $starting_point{ $File::Next::name } || is_searchable( $_ ) } - : sub { $starting_point{ $File::Next::name } || is_interesting( @_ ) } - ; - } - - my $descend_filter - = $opt->{n} ? sub {0} - : $opt->{u} ? sub {1} - : \&ignoredir_filter; - - my $iter = - File::Next::files( { - file_filter => $file_filter, - descend_filter => $descend_filter, - error_handler => sub { my $msg = shift; App::Ack::warn( $msg ) }, - sort_files => $opt->{sort_files}, - follow_symlinks => $opt->{follow}, - }, @{$what} ); - return $iter; -} - - -sub set_up_pager { - my $command = shift; - - return if App::Ack::output_to_pipe(); - - my $pager; - if ( not open( $pager, '|-', $command ) ) { - App::Ack::die( qq{Unable to pipe to pager "$command": $!} ); - } - $fh = $pager; - - return; -} - - -sub input_from_pipe { - return $input_from_pipe; -} - - - -sub output_to_pipe { - return $output_to_pipe; -} - - -sub exit_from_ack { - my $nmatches = shift; - - my $rc = $nmatches ? 0 : 1; - exit $rc; -} - - - -1; # End of App::Ack -package App::Ack::Repository; - - -use warnings; -use strict; - -sub FAIL { - require Carp; - Carp::confess( 'Must be overloaded' ); -} - - -sub new { - FAIL(); -} - - -sub next_resource { - FAIL(); -} - - -sub close { - FAIL(); -} - -1; -package App::Ack::Resource; - - -use warnings; -use strict; - -sub FAIL { - require Carp; - Carp::confess( 'Must be overloaded' ); -} - - -sub new { - FAIL(); -} - - -sub name { - FAIL(); -} - - -sub is_binary { - FAIL(); -} - - - -sub needs_line_scan { - FAIL(); -} - - -sub reset { - FAIL(); -} - - -sub next_text { - FAIL(); -} - - -sub close { - FAIL(); -} - -1; -package App::Ack::Plugin::Basic; - - - -package App::Ack::Resource::Basic; - - -use warnings; -use strict; - - -our @ISA = qw( App::Ack::Resource ); - - -sub new { - my $class = shift; - my $filename = shift; - - my $self = bless { - filename => $filename, - fh => undef, - could_be_binary => undef, - opened => undef, - id => undef, - }, $class; - - if ( $self->{filename} eq '-' ) { - $self->{fh} = *STDIN; - $self->{could_be_binary} = 0; - } - else { - if ( !open( $self->{fh}, '<', $self->{filename} ) ) { - App::Ack::warn( "$self->{filename}: $!" ); - return; - } - $self->{could_be_binary} = 1; - } - - return $self; -} - - -sub name { - my $self = shift; - - return $self->{filename}; -} - - -sub is_binary { - my $self = shift; - - if ( $self->{could_be_binary} ) { - return -B $self->{filename}; - } - - return 0; -} - - - -sub needs_line_scan { - my $self = shift; - my $opt = shift; - - return 1 if $opt->{v}; - - my $size = -s $self->{fh}; - if ( $size == 0 ) { - return 0; - } - elsif ( $size > 100_000 ) { - return 1; - } - - my $buffer; - my $rc = sysread( $self->{fh}, $buffer, $size ); - if ( not defined $rc ) { - App::Ack::warn( "$self->{filename}: $!" ); - return 1; - } - return 0 unless $rc && ( $rc == $size ); - - my $regex = $opt->{regex}; - return $buffer =~ /$regex/m; -} - - -sub reset { - my $self = shift; - - seek( $self->{fh}, 0, 0 ) - or App::Ack::warn( "$self->{filename}: $!" ); - - return; -} - - -sub next_text { - if ( defined ($_ = readline $_[0]->{fh}) ) { - $. = ++$_[0]->{line}; - return 1; - } - - return; -} - - -sub close { - my $self = shift; - - if ( not close $self->{fh} ) { - App::Ack::warn( $self->name() . ": $!" ); - } - - return; -} - -package App::Ack::Repository::Basic; - - -our @ISA = qw( App::Ack::Repository ); - - -use warnings; -use strict; - -sub new { - my $class = shift; - my $filename = shift; - - my $self = bless { - filename => $filename, - nexted => 0, - }, $class; - - return $self; -} - - -sub next_resource { - my $self = shift; - - return if $self->{nexted}; - $self->{nexted} = 1; - - return App::Ack::Resource::Basic->new( $self->{filename} ); -} - - -sub close { -} - - - -1; diff --git a/vendor/ag b/vendor/ag deleted file mode 100755 index 63e16c228..000000000 Binary files a/vendor/ag and /dev/null differ