mirror of
https://github.com/atom/atom.git
synced 2026-02-05 04:05:05 -05:00
23
.gitmodules
vendored
23
.gitmodules
vendored
@@ -46,6 +46,27 @@
|
||||
[submodule "vendor/packages/python.tmbundle"]
|
||||
path = vendor/packages/python.tmbundle
|
||||
url = https://github.com/textmate/python.tmbundle
|
||||
[submodule "vendor/packages/clojure.tmbundle"]
|
||||
path = vendor/packages/clojure.tmbundle
|
||||
url = https://github.com/mmcgrana/textmate-clojure
|
||||
[submodule "prebuilt-cef"]
|
||||
path = prebuilt-cef
|
||||
url = https://github.com/github/prebuilt-cef
|
||||
url = git@github.com:github/prebuilt-cef.git
|
||||
[submodule "vendor/packages/yaml.tmbundle"]
|
||||
path = vendor/packages/yaml.tmbundle
|
||||
url = https://github.com/textmate/yaml.tmbundle.git
|
||||
[submodule "vendor/packages/java.tmbundle"]
|
||||
path = vendor/packages/java.tmbundle
|
||||
url = https://github.com/textmate/java.tmbundle.git
|
||||
[submodule "vendor/packages/php.tmbundle"]
|
||||
path = vendor/packages/php.tmbundle
|
||||
url = https://github.com/textmate/php.tmbundle.git
|
||||
[submodule "vendor/packages/perl.tmbundle"]
|
||||
path = vendor/packages/perl.tmbundle
|
||||
url = https://github.com/textmate/perl.tmbundle.git
|
||||
[submodule "vendor/packages/sass.tmbundle"]
|
||||
path = vendor/packages/sass.tmbundle
|
||||
url = https://github.com/alexsancho/SASS.tmbundle.git
|
||||
[submodule "vendor/packages/less.tmbundle"]
|
||||
path = vendor/packages/less.tmbundle
|
||||
url = https://github.com/mathewbyrne/less.tmbundle.git
|
||||
|
||||
@@ -17,4 +17,3 @@ Requirements
|
||||
1. gh-setup atom
|
||||
|
||||
2. cd ~/github/atom && `rake install`
|
||||
|
||||
|
||||
99
Rakefile
99
Rakefile
@@ -1,9 +1,6 @@
|
||||
ATOM_SRC_PATH = File.dirname(__FILE__)
|
||||
DOT_ATOM_PATH = ENV['HOME'] + "/.atom"
|
||||
BUILD_DIR = 'atom-build'
|
||||
|
||||
require 'erb'
|
||||
|
||||
desc "Build Atom via `xcodebuild`"
|
||||
task :build => "create-xcode-project" do
|
||||
command = "xcodebuild -target Atom -configuration Release SYMROOT=#{BUILD_DIR}"
|
||||
@@ -17,7 +14,7 @@ end
|
||||
desc "Create xcode project from gyp file"
|
||||
task "create-xcode-project" => "update-cef" do
|
||||
`rm -rf atom.xcodeproj`
|
||||
`gyp --depth=. atom.gyp`
|
||||
`gyp --depth=. -D CODE_SIGN="#{ENV['CODE_SIGN']}" atom.gyp`
|
||||
end
|
||||
|
||||
desc "Update CEF to the latest version specified by the prebuilt-cef submodule"
|
||||
@@ -32,50 +29,56 @@ task "bootstrap" do
|
||||
`script/bootstrap`
|
||||
end
|
||||
|
||||
desc "Creates symlink from `application_path() to /Applications/Atom and creates `atom` cli app"
|
||||
desc "Copies Atom.app to /Applications and creates `atom` cli app"
|
||||
task :install => [:clean, :build] do
|
||||
path = application_path()
|
||||
exit 1 if not path
|
||||
|
||||
# Install Atom.app
|
||||
dest = "/Applications/#{File.basename(path)}"
|
||||
`rm -rf #{dest}`
|
||||
`cp -r #{path} #{File.expand_path(dest)}`
|
||||
dest_path = "/Applications/#{File.basename(path)}"
|
||||
`rm -rf #{dest_path}`
|
||||
`cp -r #{path} #{File.expand_path(dest_path)}`
|
||||
|
||||
# Install cli atom
|
||||
usr_bin_path = "/opt/github/bin"
|
||||
cli_path = "#{usr_bin_path}/atom"
|
||||
|
||||
template = ERB.new CLI_SCRIPT
|
||||
namespace = OpenStruct.new(:application_path => dest, :resource_path => ATOM_SRC_PATH)
|
||||
File.open(cli_path, "w") do |f|
|
||||
f.write template.result(namespace.instance_eval { binding })
|
||||
f.chmod(0755)
|
||||
# Install atom cli
|
||||
if File.directory?("/opt/boxen")
|
||||
cli_path = "/opt/boxen/bin/atom"
|
||||
else
|
||||
cli_path = "/opt/github/bin/atom"
|
||||
end
|
||||
|
||||
Rake::Task["create-dot-atom"].invoke()
|
||||
FileUtils.cp("#{ATOM_SRC_PATH}/atom.sh", cli_path)
|
||||
FileUtils.chmod(0755, cli_path)
|
||||
|
||||
Rake::Task["clone-default-bundles"].invoke()
|
||||
|
||||
puts "\033[32mType `atom` to start Atom! In Atom press `cmd-,` to edit your `~/.atom` directory\033[0m"
|
||||
puts "\033[32mAtom is installed at `#{dest_path}`. Atom cli is installed at `#{cli_path}`\033[0m"
|
||||
end
|
||||
|
||||
desc "Creates .atom file if non exists"
|
||||
task "create-dot-atom" do
|
||||
dot_atom_template_path = ATOM_SRC_PATH + "/dot-atom"
|
||||
desc "Package up the app for speakeasy"
|
||||
task :package => ["setup-codesigning", "bump-patch-number", "build"] do
|
||||
path = application_path()
|
||||
exit 1 if not path
|
||||
|
||||
if File.exists?(DOT_ATOM_PATH)
|
||||
user_config = "#{DOT_ATOM_PATH}/user.coffee"
|
||||
old_user_config = "#{DOT_ATOM_PATH}/atom.coffee"
|
||||
dest_path = '/tmp/atom-for-speakeasy/Atom.tar.bz2'
|
||||
`mkdir -p $(dirname #{dest_path})`
|
||||
`rm -rf #{dest_path}`
|
||||
`tar --directory $(dirname #{path}) -jcf #{dest_path} $(basename #{path})`
|
||||
`open $(dirname #{dest_path})`
|
||||
end
|
||||
|
||||
if File.exists?(old_user_config)
|
||||
`mv #{old_user_config} #{user_config}`
|
||||
puts "\033[32mRenamed #{old_user_config} to #{user_config}\033[0m"
|
||||
end
|
||||
else
|
||||
`mkdir "#{DOT_ATOM_PATH}"`
|
||||
`cp -r "#{dot_atom_template_path}/" "#{DOT_ATOM_PATH}"/`
|
||||
`cp -r "#{ATOM_SRC_PATH}/themes/" "#{DOT_ATOM_PATH}"/themes/`
|
||||
end
|
||||
task "setup-codesigning" do
|
||||
ENV['CODE_SIGN'] = "Developer ID Application: GitHub"
|
||||
end
|
||||
|
||||
desc "Bump patch number"
|
||||
task "bump-patch-number" do
|
||||
version_number = `/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString:" ./native/mac/info.plist`
|
||||
major, minor, patch = version_number.match(/(\d+)\.(\d+)\.(\d+)/)[1..-1].map {|o| o.to_i}
|
||||
`/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString #{major}.#{minor}.#{patch + 1}" ./native/mac/info.plist`
|
||||
`/usr/libexec/PlistBuddy -c "Set :CFBundleVersion #{major}.#{minor}.#{patch + 1}" ./native/mac/info.plist`
|
||||
|
||||
new_version_number = `/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString:" ./native/mac/info.plist`
|
||||
puts "Bumped from #{version_number.strip} to #{new_version_number.strip}"
|
||||
end
|
||||
|
||||
desc "Clone default bundles into vendor/bundles directory"
|
||||
@@ -96,7 +99,6 @@ desc "Run the specs"
|
||||
task :test => ["update-cef", "clone-default-bundles", "build"] do
|
||||
`pkill Atom`
|
||||
if path = application_path()
|
||||
`rm -rf path`
|
||||
cmd = "#{path}/Contents/MacOS/Atom --test --resource-path=#{ATOM_SRC_PATH} 2> /dev/null"
|
||||
system(cmd)
|
||||
exit($?.exitstatus)
|
||||
@@ -130,30 +132,3 @@ def application_path
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
CLI_SCRIPT = <<-EOF
|
||||
#!/bin/sh
|
||||
open <%= application_path %> -n --args --resource-path="<%= resource_path %>" --executed-from="$(pwd)" --pid=$$ $@
|
||||
|
||||
# Used to exit process when atom is used as $EDITOR
|
||||
on_die() {
|
||||
exit 0
|
||||
}
|
||||
trap 'on_die' SIGQUIT SIGTERM
|
||||
|
||||
# Don't exit process if we were told to wait.
|
||||
while [ "$#" -gt "0" ]; do
|
||||
case $1 in
|
||||
-W|--wait)
|
||||
WAIT=1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $WAIT ]; then
|
||||
while true; do
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
EOF
|
||||
|
||||
3
atom.gyp
3
atom.gyp
@@ -80,6 +80,9 @@
|
||||
'OTHER_LDFLAGS': ['-Wl,-headerpad_max_install_names'], # Necessary to avoid an "install_name_tool: changing install names or rpaths can't be redone" error.
|
||||
},
|
||||
'conditions': [
|
||||
['CODE_SIGN' , {
|
||||
'xcode_settings': {'CODE_SIGN_IDENTITY': "<(CODE_SIGN)"},
|
||||
}],
|
||||
['OS=="win" and win_use_allocator_shim==1', {
|
||||
'dependencies': [
|
||||
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
|
||||
|
||||
24
atom.sh
Normal file
24
atom.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
open -a /Applications/Atom.app -n --args --executed-from="$(pwd)" --pid=$$ $@
|
||||
|
||||
# Used to exit process when atom is used as $EDITOR
|
||||
on_die() {
|
||||
exit 0
|
||||
}
|
||||
trap 'on_die' SIGQUIT SIGTERM
|
||||
|
||||
# Don't exit process if we were told to wait.
|
||||
while [ "$#" -gt "0" ]; do
|
||||
case $1 in
|
||||
-W|--wait)
|
||||
WAIT=1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
if [ $WAIT ]; then
|
||||
while true; do
|
||||
sleep 1
|
||||
done
|
||||
fi
|
||||
@@ -1,6 +1,6 @@
|
||||
# Getting Started
|
||||
|
||||
Welcome to Atom. This documentation is intented to offer a basic introduction
|
||||
Welcome to Atom. This documentation is intended to offer a basic introduction
|
||||
of how to get productive with this editor. Then we'll delve into more details
|
||||
about configuring, theming, and extending Atom.
|
||||
|
||||
@@ -36,6 +36,15 @@ bindings, but here's a list of a few useful commands.
|
||||
|
||||
## Usage Basics
|
||||
|
||||
### If You See A Rendering Bug
|
||||
|
||||
Things are pretty stable, but we think we have a couple rendering bugs lurking
|
||||
that are hard to reproduce. If you see one, please hit `meta-p` and type
|
||||
"save debug snapshot". Run that command to save a snapshot of the misbehaving
|
||||
editor and send it to us, along with a screenshot and your best description of
|
||||
how you produced the bug. Refreshing with `meta-r` should usually resolve the
|
||||
issue so you can keep working.
|
||||
|
||||
### Working With Files
|
||||
|
||||
#### Finding Files
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
class AtomCefClient;
|
||||
|
||||
@interface AtomApplication : NSApplication <CefAppProtocol, NSApplicationDelegate> {
|
||||
IBOutlet NSMenuItem *_versionMenuItem;
|
||||
NSWindowController *_backgroundWindowController;
|
||||
NSDictionary *_arguments;
|
||||
NSInvocation *_updateInvocation;
|
||||
@@ -23,8 +24,6 @@ class AtomCefClient;
|
||||
- (void)runSpecsThenExit:(BOOL)exitWhenDone;
|
||||
- (NSDictionary *)arguments;
|
||||
- (void)runBenchmarksThenExit:(BOOL)exitWhenDone;
|
||||
- (NSString *)updateStatus;
|
||||
- (void)installUpdate;
|
||||
|
||||
@property (nonatomic, retain) NSDictionary *arguments;
|
||||
|
||||
|
||||
@@ -50,20 +50,20 @@
|
||||
{ "resource-path", required_argument, NULL, 'R' },
|
||||
{ "benchmark", no_argument, NULL, 'B' },
|
||||
{ "test", no_argument, NULL, 'T' },
|
||||
{ "stable", no_argument, NULL, 'S' },
|
||||
{ "dev", no_argument, NULL, 'D' },
|
||||
{ "pid", required_argument, NULL, 'P' },
|
||||
{ "wait", no_argument, NULL, 'W' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((opt = getopt_long(cleanArgc, cleanArgv, "K:R:BYSP:Wh?", longopts, &longindex)) != -1) {
|
||||
while ((opt = getopt_long(cleanArgc, cleanArgv, "K:R:BYDP:Wh?", longopts, &longindex)) != -1) {
|
||||
NSString *key, *value;
|
||||
switch (opt) {
|
||||
case 'K':
|
||||
case 'R':
|
||||
case 'B':
|
||||
case 'T':
|
||||
case 'S':
|
||||
case 'D':
|
||||
case 'W':
|
||||
case 'P':
|
||||
key = [NSString stringWithUTF8String:longopts[longindex].name];
|
||||
@@ -123,8 +123,10 @@
|
||||
+ (CefSettings)createCefSettings {
|
||||
CefSettings settings;
|
||||
|
||||
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
|
||||
NSString *userAgent = [NSString stringWithFormat:@"GitHubAtom/%@", version];
|
||||
CefString(&settings.cache_path) = [[self supportDirectory] UTF8String];
|
||||
CefString(&settings.user_agent) = "";
|
||||
CefString(&settings.user_agent) = [userAgent UTF8String];
|
||||
CefString(&settings.log_file) = "";
|
||||
CefString(&settings.javascript_flags) = "";
|
||||
settings.remote_debugging_port = 9090;
|
||||
@@ -159,8 +161,8 @@
|
||||
[self open:path pidToKillWhenWindowCloses:nil];
|
||||
}
|
||||
|
||||
- (void)openUnstable:(NSString *)path {
|
||||
[[AtomWindowController alloc] initUnstableWithPath:path];
|
||||
- (void)openDev:(NSString *)path {
|
||||
[[AtomWindowController alloc] initDevWithPath:path];
|
||||
}
|
||||
|
||||
- (IBAction)runSpecs:(id)sender {
|
||||
@@ -213,18 +215,24 @@
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
|
||||
SUUpdater.sharedUpdater.delegate = self;
|
||||
SUUpdater.sharedUpdater.automaticallyChecksForUpdates = YES;
|
||||
SUUpdater.sharedUpdater.automaticallyDownloadsUpdates = YES;
|
||||
[SUUpdater.sharedUpdater checkForUpdatesInBackground];
|
||||
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
|
||||
_versionMenuItem.title = [NSString stringWithFormat:@"Version %@", version];
|
||||
|
||||
_backgroundWindowController = [[AtomWindowController alloc] initInBackground];
|
||||
if ([self.arguments objectForKey:@"benchmark"]) {
|
||||
[self runBenchmarksThenExit:true];
|
||||
}
|
||||
else if ([self.arguments objectForKey:@"test"]) {
|
||||
[self runSpecsThenExit:true];
|
||||
}
|
||||
else {
|
||||
_backgroundWindowController = [[AtomWindowController alloc] initInBackground];
|
||||
if (![self.arguments objectForKey:@"dev"]) {
|
||||
SUUpdater.sharedUpdater.delegate = self;
|
||||
SUUpdater.sharedUpdater.automaticallyChecksForUpdates = YES;
|
||||
SUUpdater.sharedUpdater.automaticallyDownloadsUpdates = YES;
|
||||
[SUUpdater.sharedUpdater checkForUpdatesInBackground];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationWillTerminate:(NSNotification *)notification {
|
||||
@@ -257,35 +265,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)updateStatus {
|
||||
return _updateStatus ? _updateStatus : @"idle";
|
||||
}
|
||||
|
||||
- (void)installUpdate {
|
||||
if (_updateInvocation) [_updateInvocation invoke];
|
||||
}
|
||||
|
||||
#pragma mark SUUpdaterDelegate
|
||||
|
||||
- (void)updaterDidNotFindUpdate:(SUUpdater *)update {
|
||||
_updateStatus = @"current";
|
||||
}
|
||||
|
||||
- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update {
|
||||
_updateStatus = @"downloading";
|
||||
}
|
||||
|
||||
- (void)updater:(SUUpdater *)updater willExtractUpdate:(SUAppcastItem *)update {
|
||||
_updateStatus = @"installing";
|
||||
}
|
||||
|
||||
- (void)updater:(SUUpdater *)updater willInstallUpdateOnQuit:(SUAppcastItem *)update immediateInstallationInvocation:(NSInvocation *)invocation {
|
||||
_updateInvocation = invocation;
|
||||
_updateStatus = @"ready";
|
||||
_updateInvocation = [invocation retain];
|
||||
_versionMenuItem.title = [NSString stringWithFormat:@"Update to %@", update.versionString];
|
||||
_versionMenuItem.target = _updateInvocation;
|
||||
_versionMenuItem.action = @selector(invoke);
|
||||
}
|
||||
|
||||
- (void)updater:(SUUpdater *)updater didCancelInstallUpdateOnQuit:(SUAppcastItem *)update {
|
||||
_updateStatus = @"current";
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,9 +36,9 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
bool hasArguments = argumentList->GetSize() > 1;
|
||||
hasArguments ? Open(argumentList->GetString(1)) : Open();
|
||||
}
|
||||
if (name == "openUnstable") {
|
||||
if (name == "openDev") {
|
||||
bool hasArguments = argumentList->GetSize() > 1;
|
||||
hasArguments ? OpenUnstable(argumentList->GetString(1)) : OpenUnstable();
|
||||
hasArguments ? OpenDev(argumentList->GetString(1)) : OpenDev();
|
||||
}
|
||||
else if (name == "newWindow") {
|
||||
NewWindow();
|
||||
@@ -84,11 +84,8 @@ bool AtomCefClient::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
else if (name == "toggleFullScreen") {
|
||||
ToggleFullScreen(browser);
|
||||
}
|
||||
else if (name == "update") {
|
||||
Update();
|
||||
}
|
||||
else if (name == "getUpdateStatus") {
|
||||
GetUpdateStatus(messageId, browser);
|
||||
else if (name == "getVersion") {
|
||||
GetVersion(messageId, browser);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
|
||||
@@ -109,9 +109,8 @@ class AtomCefClient : public CefClient,
|
||||
void FocusPreviousWindow();
|
||||
void Open(std::string path);
|
||||
void Open();
|
||||
void OpenUnstable(std::string path);
|
||||
|
||||
void OpenUnstable();
|
||||
void OpenDev(std::string path);
|
||||
void OpenDev();
|
||||
void NewWindow();
|
||||
void ToggleDevTools(CefRefPtr<CefBrowser> browser);
|
||||
void ShowDevTools(CefRefPtr<CefBrowser> browser);
|
||||
@@ -126,8 +125,7 @@ class AtomCefClient : public CefClient,
|
||||
void Log(const char *message);
|
||||
void Show(CefRefPtr<CefBrowser> browser);
|
||||
void ToggleFullScreen(CefRefPtr<CefBrowser> browser);
|
||||
void Update();
|
||||
void GetUpdateStatus(int replyId, CefRefPtr<CefBrowser> browser);
|
||||
void GetVersion(int replyId, CefRefPtr<CefBrowser> browser);
|
||||
|
||||
IMPLEMENT_REFCOUNTING(AtomCefClient);
|
||||
IMPLEMENT_LOCKING(AtomCefClient);
|
||||
|
||||
@@ -56,17 +56,17 @@ void AtomCefClient::Open() {
|
||||
}
|
||||
}
|
||||
|
||||
void AtomCefClient::OpenUnstable(std::string path) {
|
||||
void AtomCefClient::OpenDev(std::string path) {
|
||||
NSString *pathString = [NSString stringWithCString:path.c_str() encoding:NSUTF8StringEncoding];
|
||||
[(AtomApplication *)[AtomApplication sharedApplication] openUnstable:pathString];
|
||||
[(AtomApplication *)[AtomApplication sharedApplication] openDev:pathString];
|
||||
}
|
||||
|
||||
void AtomCefClient::OpenUnstable() {
|
||||
void AtomCefClient::OpenDev() {
|
||||
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
||||
[panel setCanChooseDirectories:YES];
|
||||
if ([panel runModal] == NSFileHandlingPanelOKButton) {
|
||||
NSURL *url = [[panel URLs] lastObject];
|
||||
OpenUnstable([[url path] UTF8String]);
|
||||
OpenDev([[url path] UTF8String]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,17 +159,13 @@ void AtomCefClient::Log(const char *message) {
|
||||
std::cout << message << "\n";
|
||||
}
|
||||
|
||||
void AtomCefClient::Update() {
|
||||
[(AtomApplication *)NSApp installUpdate];
|
||||
}
|
||||
|
||||
void AtomCefClient::GetUpdateStatus(int replyId, CefRefPtr<CefBrowser> browser) {
|
||||
void AtomCefClient::GetVersion(int replyId, CefRefPtr<CefBrowser> browser) {
|
||||
CefRefPtr<CefProcessMessage> replyMessage = CefProcessMessage::Create("reply");
|
||||
CefRefPtr<CefListValue> replyArguments = replyMessage->GetArgumentList();
|
||||
|
||||
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
|
||||
|
||||
replyArguments->SetSize(2);
|
||||
replyArguments->SetString(1, [[(AtomApplication *)NSApp updateStatus] UTF8String]);
|
||||
replyArguments->SetString(1, [version UTF8String]);
|
||||
replyArguments->SetList(0, CreateReplyDescriptor(replyId, 0));
|
||||
|
||||
browser->SendProcessMessage(PID_RENDERER, replyMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class AtomCefClient;
|
||||
@property (nonatomic, retain) NSString *pathToOpen;
|
||||
|
||||
- (id)initWithPath:(NSString *)path;
|
||||
- (id)initUnstableWithPath:(NSString *)path;
|
||||
- (id)initDevWithPath:(NSString *)path;
|
||||
- (id)initInBackground;
|
||||
- (id)initSpecsThenExit:(BOOL)exitWhenDone;
|
||||
- (id)initBenchmarksThenExit:(BOOL)exitWhenDone;
|
||||
|
||||
@@ -33,6 +33,17 @@
|
||||
AtomApplication *atomApplication = (AtomApplication *)[AtomApplication sharedApplication];
|
||||
|
||||
_resourcePath = [atomApplication.arguments objectForKey:@"resource-path"];
|
||||
if (!alwaysUseBundleResourcePath && !_resourcePath) {
|
||||
NSString *defaultRepositoryPath = @"~/github/atom";
|
||||
defaultRepositoryPath = [defaultRepositoryPath stringByStandardizingPath];
|
||||
if ([defaultRepositoryPath characterAtIndex:0] == '/') {
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:defaultRepositoryPath isDirectory:&isDir];
|
||||
if (isDir && exists)
|
||||
_resourcePath = defaultRepositoryPath;
|
||||
}
|
||||
}
|
||||
|
||||
if (alwaysUseBundleResourcePath || !_resourcePath) {
|
||||
_resourcePath = [[NSBundle mainBundle] resourcePath];
|
||||
}
|
||||
@@ -52,11 +63,11 @@
|
||||
- (id)initWithPath:(NSString *)path {
|
||||
_pathToOpen = [path retain];
|
||||
AtomApplication *atomApplication = (AtomApplication *)[AtomApplication sharedApplication];
|
||||
BOOL stable = [atomApplication.arguments objectForKey:@"stable"] != nil;
|
||||
return [self initWithBootstrapScript:@"window-bootstrap" background:NO alwaysUseBundleResourcePath:stable];
|
||||
BOOL useBundleResourcePath = [atomApplication.arguments objectForKey:@"dev"] == nil;
|
||||
return [self initWithBootstrapScript:@"window-bootstrap" background:NO alwaysUseBundleResourcePath:useBundleResourcePath];
|
||||
}
|
||||
|
||||
- (id)initUnstableWithPath:(NSString *)path {
|
||||
- (id)initDevWithPath:(NSString *)path {
|
||||
_pathToOpen = [path retain];
|
||||
AtomApplication *atomApplication = (AtomApplication *)[AtomApplication sharedApplication];
|
||||
return [self initWithBootstrapScript:@"window-bootstrap" background:NO alwaysUseBundleResourcePath:false];
|
||||
@@ -64,9 +75,9 @@
|
||||
|
||||
- (id)initInBackground {
|
||||
AtomApplication *atomApplication = (AtomApplication *)[AtomApplication sharedApplication];
|
||||
BOOL stable = [atomApplication.arguments objectForKey:@"stable"] != nil;
|
||||
BOOL useBundleResourcePath = [atomApplication.arguments objectForKey:@"dev"] == nil;
|
||||
|
||||
[self initWithBootstrapScript:@"window-bootstrap" background:YES alwaysUseBundleResourcePath:stable];
|
||||
[self initWithBootstrapScript:@"window-bootstrap" background:YES alwaysUseBundleResourcePath:useBundleResourcePath];
|
||||
[self.window setFrame:NSMakeRect(0, 0, 0, 0) display:NO];
|
||||
[self.window setExcludedFromWindowsMenu:YES];
|
||||
[self.window setCollectionBehavior:NSWindowCollectionBehaviorStationary];
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||
<data>
|
||||
<int key="IBDocument.SystemTarget">1050</int>
|
||||
<string key="IBDocument.SystemVersion">12C54</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">2840</string>
|
||||
<string key="IBDocument.SystemVersion">12C3103</string>
|
||||
<string key="IBDocument.InterfaceBuilderVersion">3084</string>
|
||||
<string key="IBDocument.AppKitVersion">1187.34</string>
|
||||
<string key="IBDocument.HIToolboxVersion">625.00</string>
|
||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="NS.object.0">2840</string>
|
||||
<string key="NS.object.0">3084</string>
|
||||
</object>
|
||||
<object class="NSArray" key="IBDocument.IntegratedClassDependencies">
|
||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||
@@ -105,6 +105,15 @@
|
||||
<reference key="NSOnImage" ref="293900348"/>
|
||||
<reference key="NSMixedImage" ref="169361956"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="781500792">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
<string key="NSTitle">Version Info</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="293900348"/>
|
||||
<reference key="NSMixedImage" ref="169361956"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="139213332">
|
||||
<reference key="NSMenu" ref="110575045"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
@@ -213,6 +222,14 @@
|
||||
</object>
|
||||
<int key="connectionID">447</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBOutletConnection" key="connection">
|
||||
<string key="label">_versionMenuItem</string>
|
||||
<reference key="source" ref="1050"/>
|
||||
<reference key="destination" ref="781500792"/>
|
||||
</object>
|
||||
<int key="connectionID">465</int>
|
||||
</object>
|
||||
<object class="IBConnectionRecord">
|
||||
<object class="IBActionConnection" key="connection">
|
||||
<string key="label">terminate:</string>
|
||||
@@ -323,6 +340,7 @@
|
||||
<reference ref="574677965"/>
|
||||
<reference ref="90109190"/>
|
||||
<reference ref="884100265"/>
|
||||
<reference ref="781500792"/>
|
||||
</object>
|
||||
<reference key="parent" ref="694149608"/>
|
||||
</object>
|
||||
@@ -411,6 +429,11 @@
|
||||
<reference key="object" ref="884100265"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">464</int>
|
||||
<reference key="object" ref="781500792"/>
|
||||
<reference key="parent" ref="110575045"/>
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -435,6 +458,7 @@
|
||||
<string>458.IBPluginDependency</string>
|
||||
<string>459.IBPluginDependency</string>
|
||||
<string>460.IBPluginDependency</string>
|
||||
<string>464.IBPluginDependency</string>
|
||||
<string>56.IBPluginDependency</string>
|
||||
<string>57.IBPluginDependency</string>
|
||||
</object>
|
||||
@@ -460,6 +484,7 @@
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="unlocalizedProperties">
|
||||
@@ -474,7 +499,7 @@
|
||||
<reference key="dict.values" ref="755588897"/>
|
||||
</object>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">463</int>
|
||||
<int key="maxID">465</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||
@@ -514,6 +539,17 @@
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="outlets">
|
||||
<string key="NS.key.0">_versionMenuItem</string>
|
||||
<string key="NS.object.0">NSMenuItem</string>
|
||||
</object>
|
||||
<object class="NSMutableDictionary" key="toOneOutletInfosByName">
|
||||
<string key="NS.key.0">_versionMenuItem</string>
|
||||
<object class="IBToOneOutletInfo" key="NS.object.0">
|
||||
<string key="name">_versionMenuItem</string>
|
||||
<string key="candidateClassName">NSMenuItem</string>
|
||||
</object>
|
||||
</object>
|
||||
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||
<string key="majorKey">IBProjectSource</string>
|
||||
<string key="minorKey">./Classes/AtomApplication.h</string>
|
||||
|
||||
Binary file not shown.
@@ -27,7 +27,8 @@ namespace v8_extensions {
|
||||
"exists", "read", "write", "absolute", "getAllFilePathsAsync", "traverseTree", "isDirectory",
|
||||
"isFile", "remove", "writeToPasteboard", "readFromPasteboard", "quit", "watchPath", "unwatchPath",
|
||||
"getWatchedPaths", "unwatchAllPaths", "makeDirectory", "move", "moveToTrash", "reload", "lastModified",
|
||||
"md5ForPath", "exec", "getPlatform", "setWindowState", "getWindowState"
|
||||
"md5ForPath", "exec", "getPlatform", "setWindowState", "getWindowState", "isMisspelled",
|
||||
"getCorrectionsForMisspelling"
|
||||
};
|
||||
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
@@ -447,41 +448,49 @@ namespace v8_extensions {
|
||||
|
||||
context->Exit();
|
||||
|
||||
stdout.fileHandleForReading.writeabilityHandler = nil;
|
||||
stderr.fileHandleForReading.writeabilityHandler = nil;
|
||||
stdout.fileHandleForReading.readabilityHandler = nil;
|
||||
stderr.fileHandleForReading.readabilityHandler = nil;
|
||||
};
|
||||
|
||||
task.terminationHandler = ^(NSTask *) {
|
||||
NSString *output = [[NSString alloc] initWithData:[[stdout fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding];
|
||||
NSString *errorOutput = [[NSString alloc] initWithData:[[stderr fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
taskTerminatedHandle(output, errorOutput);
|
||||
});
|
||||
[output release];
|
||||
[errorOutput release];
|
||||
@synchronized(task) {
|
||||
NSData *outputData = [[stdout fileHandleForReading] readDataToEndOfFile];
|
||||
NSString *output = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
|
||||
NSData *errorData = [[stderr fileHandleForReading] readDataToEndOfFile];
|
||||
NSString *errorOutput = [[NSString alloc] initWithData:errorData encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
taskTerminatedHandle(output, errorOutput);
|
||||
});
|
||||
[output release];
|
||||
[errorOutput release];
|
||||
}
|
||||
};
|
||||
|
||||
CefRefPtr<CefV8Value> stdoutFunction = options->GetValue("stdout");
|
||||
if (stdoutFunction->IsFunction()) {
|
||||
stdout.fileHandleForReading.writeabilityHandler = ^(NSFileHandle *fileHandle) {
|
||||
NSData *data = [fileHandle availableData];
|
||||
NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
outputHandle(contents, stdoutFunction);
|
||||
});
|
||||
[contents release];
|
||||
stdout.fileHandleForReading.readabilityHandler = ^(NSFileHandle *fileHandle) {
|
||||
@synchronized(task) {
|
||||
NSData *data = [fileHandle availableData];
|
||||
NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
outputHandle(contents, stdoutFunction);
|
||||
});
|
||||
[contents release];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> stderrFunction = options->GetValue("stderr");
|
||||
if (stderrFunction->IsFunction()) {
|
||||
stderr.fileHandleForReading.writeabilityHandler = ^(NSFileHandle *fileHandle) {
|
||||
NSData *data = [fileHandle availableData];
|
||||
NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
outputHandle(contents, stderrFunction);
|
||||
});
|
||||
[contents release];
|
||||
stderr.fileHandleForReading.readabilityHandler = ^(NSFileHandle *fileHandle) {
|
||||
@synchronized(task) {
|
||||
NSData *data = [fileHandle availableData];
|
||||
NSString *contents = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
dispatch_sync(dispatch_get_main_queue(), ^() {
|
||||
outputHandle(contents, stderrFunction);
|
||||
});
|
||||
[contents release];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -513,6 +522,29 @@ namespace v8_extensions {
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (name == "isMisspelled") {
|
||||
NSString *word = stringFromCefV8Value(arguments[0]);
|
||||
NSRange range = [[NSSpellChecker sharedSpellChecker] checkSpellingOfString:word startingAt:0];
|
||||
retval = CefV8Value::CreateBool(range.length > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (name == "getCorrectionsForMisspelling") {
|
||||
NSString *misspelling = stringFromCefV8Value(arguments[0]);
|
||||
NSSpellChecker *spellchecker = [NSSpellChecker sharedSpellChecker];
|
||||
NSString *language = [spellchecker language];
|
||||
NSRange range;
|
||||
range.location = 0;
|
||||
range.length = [misspelling length];
|
||||
NSArray *guesses = [spellchecker guessesForWordRange:range inString:misspelling language:language inSpellDocumentWithTag:0];
|
||||
CefRefPtr<CefV8Value> v8Guesses = CefV8Value::CreateArray([guesses count]);
|
||||
for (int i = 0; i < [guesses count]; i++) {
|
||||
v8Guesses->SetValue(i, CefV8Value::CreateString([[guesses objectAtIndex:i] UTF8String]));
|
||||
}
|
||||
retval = v8Guesses;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAzLmZ/pTYsc9Wu1+nbf2ri7HjwkJG2LlwS18t+LkSUBNWH7/2
|
||||
plHjd4govWGGZSWdAR9bS7MpNIKdgypWXXIRTZxOgl91p+vm//brYZ+1fObC+cpA
|
||||
/+AflzKICs0XMUdyJNUO9RNaqLYoH664cidVkgJdgVStvBxFZE8v7HmNW8R9/w6J
|
||||
e0epeSCW7FnzUBZJmGJ0gw+mIQvHdqSt/57T7/TIGrpKQAZ1bWuYIwP2IteqiEiS
|
||||
kmLbXbzbnQnGVD9zKfHry3XHkX550qCBtV0C4Gxnxh6QU6pa9wlgHt1iJoRWWPVS
|
||||
mDOAywkMcADgP0yM8qDusxYA7rXJd+AQO51t6QIDAQABAoIBAQCifboln5yy3L+Z
|
||||
bx2kJpBvC12cRSCYSe9AU6ZYYQSQ/BgCkUnCzwI9UJwNXIfgZk9MocfDuMs+u2Er
|
||||
x4HPH4duU17ZCc2H36x0g1ZmIO5a2Ynt20NmFEzepCPodsouued2Jol9qcPuXs5P
|
||||
/0y0hlXb0vbGfSB8SvAk4tlF12CEcXArb5ofs0ekjNiSFpfXklGEGKsi5uMr/gQB
|
||||
ZKfszw13yYiHWRP1tDBH62sH6xOHFGaI5COh4WmeN0LijqYVT8om+Xgd2dPO7imJ
|
||||
3Ylm5e1Fn/koISkGegp/i1BqmddWFVtUvvd/TdSi5gBqZDjYS/0It9cJCcmD0zmn
|
||||
tCnwII2RAoGBAPEx3uO7uEKDcMhQkXmtjsfwnVLLYWipkjUqldPz+hdnEVchf7AF
|
||||
B7/efH0x9OQtKCKIOhOsZ58NMSD0lIEnH/dsDenRBwJt9nIgzHWQ5ZaALkWFEedf
|
||||
TzdjcXj64Du7M5sPtmK+VysPQRR8fTc7hP4tEFghpBN6o7r4gXokiuPdAoGBANlK
|
||||
pTLqB8tbxnhGxhasVkbOrGAmAAjXj4p5kYjq739DYzDzZNyRZ8XVRepOWEKReuIe
|
||||
5qxr/iRI8VeZgQjHu0Uorva03jamEs2lUo6v6igcyvPthU8a5UypueQH13tBfoYY
|
||||
KZ7vkpUCmlNIKlMWmt6APx1NxBBq29vrgoFC06d9AoGBAIoYZqh3K2mRvjpCvvgu
|
||||
4egiIMFtxujY5ehg6IYBU7igf3ImsOgECUrWxOoddzxJiogy/SWUeYO8VtuqjXhh
|
||||
AVF1YYX08xF2CjuQAeByRLFl1JhjNzwE+uMYobiF02r/pO1sEp34own5Yuaq3DqK
|
||||
bnvlK016fWnVtvbvH5riX09VAoGAWmiYe6qsO4yf84NfACgMbcGoLwkgko0+CBu0
|
||||
1gcKRyU+rCtZF/zX9JRcVrTqPChTvKmmyK7WOzquUAhqi8CuxoO66KMwogRPZokW
|
||||
5I+FGdOBDiURhmxmY5Nq6NnqajpB7oE3MA32K1G97FDma1PIdDNgD00/+qS7fbFr
|
||||
x2SKs/ECgYBDZnD16pXVCJ2JEzHkxZDA17N82Jltd4ju8d/kcNKBrsSZysFy00VT
|
||||
eU5wC1uDVfWtw0TEXZXQqnzBGEbTZJ+nhWfrm5kimyUkmyhZOHJMMZNs9rpLfD2i
|
||||
xsE/qqEKdhxZmV7bUWr+v2Grtajz4zHxyqB1YWU9qma+wKppA068BQ==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
@@ -1,15 +1,5 @@
|
||||
#!/usr/bin/env ruby
|
||||
#!/bin/sh
|
||||
|
||||
sha = `git rev-parse HEAD`.chop
|
||||
key = File.expand_path('../atom.githubapp.com', __FILE__)
|
||||
system 'chmod', '600', key
|
||||
|
||||
system 'ssh',
|
||||
'-l', 'atom',
|
||||
'-i', key,
|
||||
'-o', 'StrictHostKeyChecking=no',
|
||||
'-p', '6000',
|
||||
'atom.githubapp.com',
|
||||
"rm -rf ~/.atom && cd /Users/atom/code/atom && git fetch -q origin && git reset -q --hard #{sha} && rake test"
|
||||
|
||||
exit $?.exitstatus
|
||||
set -ex
|
||||
rm -rf ~/.atom
|
||||
rake test
|
||||
|
||||
@@ -38,4 +38,4 @@ for CSON_FILE in $CSON_FILES; do
|
||||
done;
|
||||
|
||||
# Copy non-coffee files into bundle
|
||||
rsync --archive --recursive --exclude="src/**/*.coffee" --exclude="src/**/*.cson" src static vendor spec benchmark themes "$RESOUCES_PATH"
|
||||
rsync --archive --recursive --exclude="src/**/*.coffee" --exclude="src/**/*.cson" src static vendor spec benchmark themes dot-atom atom.sh "$RESOUCES_PATH"
|
||||
|
||||
@@ -131,3 +131,13 @@ describe "the `atom` global", ->
|
||||
expect(packageStates['package-with-module']).toEqual someNumber: 1
|
||||
expect(packageStates['package-with-serialize-error']).toBeUndefined()
|
||||
expect(console.error).toHaveBeenCalled()
|
||||
|
||||
describe ".getVersion(callback)", ->
|
||||
it "calls the callback with the current version number", ->
|
||||
versionHandler = jasmine.createSpy("versionHandler")
|
||||
atom.getVersion(versionHandler)
|
||||
waitsFor ->
|
||||
versionHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(versionHandler.argsForCall[0][0]).toMatch /^\d+\.\d+\.\d+$/
|
||||
|
||||
@@ -741,6 +741,7 @@ describe 'Buffer', ->
|
||||
oldTailPosition: [4, 20]
|
||||
newTailPosition: [4, 20]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -751,6 +752,7 @@ describe 'Buffer', ->
|
||||
oldHeadPosition: [6, 2]
|
||||
newHeadPosition: [6, 5]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "calls the given callback when the marker's tail position changes", ->
|
||||
@@ -762,6 +764,7 @@ describe 'Buffer', ->
|
||||
oldTailPosition: [4, 20]
|
||||
newTailPosition: [6, 2]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -773,6 +776,7 @@ describe 'Buffer', ->
|
||||
oldTailPosition: [6, 2]
|
||||
newTailPosition: [6, 5]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "calls the callback when the selection's tail is cleared", ->
|
||||
@@ -784,6 +788,7 @@ describe 'Buffer', ->
|
||||
oldTailPosition: [4, 20]
|
||||
newTailPosition: [4, 23]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "only calls the callback once when both the marker's head and tail positions change due to the same operation", ->
|
||||
@@ -795,6 +800,7 @@ describe 'Buffer', ->
|
||||
oldHeadPosition: [4, 23]
|
||||
newHeadPosition: [4, 26]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -806,6 +812,31 @@ describe 'Buffer', ->
|
||||
oldHeadPosition: [4, 26]
|
||||
newHeadPosition: [1, 1]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "calls the callback with the valid flag set to false when the marker is invalidated", ->
|
||||
buffer.deleteRow(4)
|
||||
expect(observeHandler.callCount).toBe 1
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual {
|
||||
oldTailPosition: [4, 20]
|
||||
newTailPosition: [4, 20]
|
||||
oldHeadPosition: [4, 23]
|
||||
newHeadPosition: [4, 23]
|
||||
bufferChanged: true
|
||||
valid: false
|
||||
}
|
||||
|
||||
observeHandler.reset()
|
||||
buffer.undo()
|
||||
expect(observeHandler.callCount).toBe 1
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual {
|
||||
oldTailPosition: [4, 20]
|
||||
newTailPosition: [4, 20]
|
||||
oldHeadPosition: [4, 23]
|
||||
newHeadPosition: [4, 23]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "allows the observation subscription to be cancelled", ->
|
||||
@@ -830,19 +861,20 @@ describe 'Buffer', ->
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker)).toBeUndefined()
|
||||
|
||||
# even "stayValid" markers get destroyed properly
|
||||
marker2 = buffer.markRange([[4, 20], [4, 23]], stayValid: true)
|
||||
# even "invalidationStrategy: never" markers get destroyed properly
|
||||
marker2 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'never')
|
||||
buffer.delete([[4, 15], [4, 25]])
|
||||
buffer.destroyMarker(marker2)
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker2)).toBeUndefined()
|
||||
|
||||
describe "marker updates due to buffer changes", ->
|
||||
[marker1, marker2] = []
|
||||
[marker1, marker2, marker3] = []
|
||||
|
||||
beforeEach ->
|
||||
marker1 = buffer.markRange([[4, 20], [4, 23]])
|
||||
marker2 = buffer.markRange([[4, 20], [4, 23]], stayValid: true)
|
||||
marker2 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'never')
|
||||
marker3 = buffer.markRange([[4, 20], [4, 23]], invalidationStrategy: 'between')
|
||||
|
||||
describe "when the buffer changes due to a new operation", ->
|
||||
describe "when the change precedes the marker range", ->
|
||||
@@ -874,20 +906,37 @@ describe 'Buffer', ->
|
||||
buffer.insert([4, 20], '...')
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 26]]
|
||||
|
||||
describe "when the invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.insert([4, 20], '...')
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
|
||||
describe "when the change is an insertion at the end of the marker range", ->
|
||||
it "moves the end point", ->
|
||||
buffer.insert([4, 23], '...')
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 26]]
|
||||
|
||||
describe "when the invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.insert([4, 23], '...')
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
|
||||
describe "when the change surrounds the marker range", ->
|
||||
describe "when the marker was created with stayValid: false (the default)", ->
|
||||
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 15], [4, 25]])
|
||||
expect(buffer.getMarkerRange(marker1)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker was created with stayValid: true", ->
|
||||
describe "when the marker's invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 15], [4, 25]])
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker3)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker's invalidation strategy is 'never'", ->
|
||||
it "does not invalidate the marker, but sets it to an empty range at the end of the change", ->
|
||||
buffer.change([[4, 15], [4, 25]], "...")
|
||||
expect(buffer.getMarkerRange(marker2)).toEqual [[4, 18], [4, 18]]
|
||||
@@ -895,14 +944,21 @@ describe 'Buffer', ->
|
||||
expect(buffer.getMarkerRange(marker2)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the change straddles the start of the marker range", ->
|
||||
describe "when the marker was created with stayValid: false (the default)", ->
|
||||
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 15], [4, 22]])
|
||||
expect(buffer.getMarkerRange(marker1)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker was created with stayValid: true", ->
|
||||
describe "when the marker's invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 15], [4, 22]])
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker3)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker's invalidation strategy is 'never'", ->
|
||||
it "moves the start of the marker range to the end of the change", ->
|
||||
buffer.delete([[4, 15], [4, 22]])
|
||||
expect(buffer.getMarkerRange(marker2)).toEqual [[4, 15], [4, 16]]
|
||||
@@ -910,20 +966,49 @@ describe 'Buffer', ->
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the change straddles the end of the marker range", ->
|
||||
describe "when the marker was created with stayValid: false (the default)", ->
|
||||
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 22], [4, 25]])
|
||||
expect(buffer.getMarkerRange(marker1)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker was created with stayValid: true", ->
|
||||
describe "when the marker's invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.delete([[4, 22], [4, 25]])
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker3)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker's invalidation strategy is 'never'", ->
|
||||
it "moves the end of the marker range to the start of the change", ->
|
||||
buffer.delete([[4, 22], [4, 25]])
|
||||
expect(buffer.getMarkerRange(marker2)).toEqual [[4, 20], [4, 22]]
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the change is between the start and the end of the marker range", ->
|
||||
describe "when the marker's invalidation strategy is 'contains' (the default)", ->
|
||||
it "does not invalidate the marker", ->
|
||||
buffer.insert([4, 21], 'x')
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 24]]
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker's invalidation strategy is 'between'", ->
|
||||
it "invalidates the marker", ->
|
||||
buffer.insert([4, 21], 'x')
|
||||
expect(buffer.getMarkerRange(marker3)).toBeUndefined()
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker3)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the marker's invalidation strategy is 'never'", ->
|
||||
it "moves the end of the marker range to the start of the change", ->
|
||||
buffer.insert([4, 21], 'x')
|
||||
expect(buffer.getMarkerRange(marker2)).toEqual [[4, 20], [4, 24]]
|
||||
buffer.undo()
|
||||
expect(buffer.getMarkerRange(marker1)).toEqual [[4, 20], [4, 23]]
|
||||
|
||||
describe "when the buffer changes due to the undo or redo of a previous operation", ->
|
||||
it "restores invalidated markers when undoing/redoing in the other direction", ->
|
||||
buffer.change([[4, 21], [4, 24]], "foo")
|
||||
|
||||
@@ -109,3 +109,27 @@ describe "Config", ->
|
||||
|
||||
config.set("foo.bar.baz", "i'm back")
|
||||
expect(observeHandler).toHaveBeenCalledWith("i'm back")
|
||||
|
||||
describe "initializeConfigDirectory()", ->
|
||||
beforeEach ->
|
||||
config.configDirPath = '/tmp/dot-atom-dir'
|
||||
expect(fs.exists(config.configDirPath)).toBeFalsy()
|
||||
|
||||
afterEach ->
|
||||
fs.remove('/tmp/dot-atom-dir') if fs.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()
|
||||
|
||||
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()
|
||||
|
||||
@@ -661,6 +661,7 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -676,6 +677,7 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -691,6 +693,7 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [8, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -706,6 +709,7 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "calls the callback whenever the marker tail's position changes in the buffer or on screen", ->
|
||||
@@ -721,6 +725,7 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [8, 20]
|
||||
newTailBufferPosition: [11, 20]
|
||||
bufferChanged: false
|
||||
valid: true
|
||||
}
|
||||
observeHandler.reset()
|
||||
|
||||
@@ -736,6 +741,40 @@ describe "DisplayBuffer", ->
|
||||
newTailScreenPosition: [8, 23]
|
||||
newTailBufferPosition: [11, 23]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "calls the callback whenever the marker is invalidated or revalidated", ->
|
||||
buffer.deleteRow(8)
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [5, 10]
|
||||
oldHeadBufferPosition: [8, 10]
|
||||
newHeadScreenPosition: [5, 10]
|
||||
newHeadBufferPosition: [8, 10]
|
||||
oldTailScreenPosition: [5, 4]
|
||||
oldTailBufferPosition: [8, 4]
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: true
|
||||
valid: false
|
||||
}
|
||||
|
||||
observeHandler.reset()
|
||||
buffer.undo()
|
||||
|
||||
expect(observeHandler).toHaveBeenCalled()
|
||||
expect(observeHandler.argsForCall[0][0]).toEqual {
|
||||
oldHeadScreenPosition: [5, 10]
|
||||
oldHeadBufferPosition: [8, 10]
|
||||
newHeadScreenPosition: [5, 10]
|
||||
newHeadBufferPosition: [8, 10]
|
||||
oldTailScreenPosition: [5, 4]
|
||||
oldTailBufferPosition: [8, 4]
|
||||
newTailScreenPosition: [5, 4]
|
||||
newTailBufferPosition: [8, 4]
|
||||
bufferChanged: true
|
||||
valid: true
|
||||
}
|
||||
|
||||
it "does not call the callback for screen changes that don't change the position of the marker", ->
|
||||
|
||||
@@ -308,10 +308,11 @@ describe "Editor", ->
|
||||
|
||||
spyOn(atom, "confirm")
|
||||
|
||||
contentsConflictedHandler = jasmine.createSpy("contentsConflictedHandler")
|
||||
editSession.on 'contents-conflicted', contentsConflictedHandler
|
||||
fs.write(path, "a file change")
|
||||
|
||||
waitsFor "file to trigger contents-changed event", (done) ->
|
||||
editSession.one 'contents-conflicted', done
|
||||
waitsFor ->
|
||||
contentsConflictedHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(atom.confirm).toHaveBeenCalled()
|
||||
@@ -2136,6 +2137,11 @@ describe "Editor", ->
|
||||
expect(editor.getSelection().isEmpty()).toBeTruthy()
|
||||
expect(editor.getCursorScreenPosition()).toEqual [5, 0]
|
||||
|
||||
it "keeps the gutter line and the editor line the same heights (regression)", ->
|
||||
editor.getSelection().setBufferRange(new Range([4, 29], [7, 4]))
|
||||
editor.trigger 'editor:fold-selection'
|
||||
|
||||
expect(editor.gutter.find('.line-number:eq(4)').height()).toBe editor.renderedLines.find('.line:eq(4)').height()
|
||||
|
||||
describe "when a fold placeholder line is clicked", ->
|
||||
it "removes the associated fold and places the cursor at its beginning", ->
|
||||
@@ -2859,3 +2865,17 @@ describe "Editor", ->
|
||||
editor.trigger 'editor:undo-close-session'
|
||||
expect(editor.getPath()).toBe fixturesProject.resolve('sample.js')
|
||||
expect(editor.getActiveEditSessionIndex()).toBe 0
|
||||
|
||||
describe "editor:save-debug-snapshot", ->
|
||||
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')
|
||||
|
||||
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'
|
||||
|
||||
@@ -89,7 +89,6 @@ describe "RootView", ->
|
||||
expect(rootView.getEditors().length).toBe 0
|
||||
|
||||
viewState = rootView.serialize()
|
||||
console.log viewState
|
||||
rootView.deactivate()
|
||||
window.rootView = RootView.deserialize(viewState)
|
||||
|
||||
|
||||
@@ -116,3 +116,16 @@ describe "Window", ->
|
||||
window.shutdown()
|
||||
window.shutdown()
|
||||
expect(atom.setRootViewStateForPath.callCount).toBe 1
|
||||
|
||||
describe ".installAtomCommand(commandPath)", ->
|
||||
commandPath = '/tmp/installed-atom-command/atom'
|
||||
|
||||
afterEach ->
|
||||
fs.remove(commandPath) if fs.exists(commandPath)
|
||||
|
||||
describe "when the command path doesn't exist", ->
|
||||
it "copies atom.sh to the specified path", ->
|
||||
expect(fs.exists(commandPath)).toBeFalsy()
|
||||
window.installAtomCommand(commandPath)
|
||||
expect(fs.exists(commandPath)).toBeTruthy()
|
||||
expect(fs.read(commandPath).length).toBeGreaterThan 1
|
||||
|
||||
1
spec/fixtures/gfm.md
vendored
Normal file
1
spec/fixtures/gfm.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* First list item
|
||||
@@ -114,7 +114,7 @@ describe 'Child Processes', ->
|
||||
afterEach ->
|
||||
jasmine.getEnv().defaultTimeoutInterval = originalTimeout
|
||||
|
||||
it "does not block indefinitally on stdout or stderr callbacks (regression)", ->
|
||||
it "does not block indefinitely on stdout or stderr callbacks (regression)", ->
|
||||
output = []
|
||||
|
||||
waitsForPromise ->
|
||||
|
||||
@@ -3,13 +3,13 @@ OnigRegExp = require 'onig-reg-exp'
|
||||
describe "OnigRegExp", ->
|
||||
describe ".search(string, index)", ->
|
||||
it "returns an array of the match and all capture groups", ->
|
||||
regex = new OnigRegExp("\\w(\\d+)")
|
||||
regex = OnigRegExp.create("\\w(\\d+)")
|
||||
result = regex.search("----a123----")
|
||||
expect(result).toEqual ["a123", "123"]
|
||||
expect(result.index).toBe 4
|
||||
expect(result.indices).toEqual [4, 5]
|
||||
|
||||
it "returns null if it does not match", ->
|
||||
regex = new OnigRegExp("\\w(\\d+)")
|
||||
regex = OnigRegExp.create("\\w(\\d+)")
|
||||
result = regex.search("--------")
|
||||
expect(result).toBeNull()
|
||||
|
||||
@@ -94,8 +94,8 @@ _.extend atom,
|
||||
open: (args...) ->
|
||||
@sendMessageToBrowserProcess('open', args)
|
||||
|
||||
openUnstable: (args...) ->
|
||||
@sendMessageToBrowserProcess('openUnstable', args)
|
||||
openDev: (args...) ->
|
||||
@sendMessageToBrowserProcess('openDev', args)
|
||||
|
||||
newWindow: (args...) ->
|
||||
@sendMessageToBrowserProcess('newWindow', args)
|
||||
@@ -179,3 +179,13 @@ _.extend atom,
|
||||
|
||||
getUpdateStatus: (callback) ->
|
||||
@sendMessageToBrowserProcess('getUpdateStatus', [], callback)
|
||||
|
||||
requireUserInitScript: ->
|
||||
userInitScriptPath = fs.join(config.configDirPath, "user.coffee")
|
||||
try
|
||||
require userInitScriptPath if fs.isFile(userInitScriptPath)
|
||||
catch error
|
||||
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
|
||||
|
||||
getVersion: (callback) ->
|
||||
@sendMessageToBrowserProcess('getVersion', null, callback)
|
||||
|
||||
@@ -107,5 +107,4 @@ class BufferChangeOperation
|
||||
if validMarker = @buffer.validMarkers[id]
|
||||
validMarker.setRange(previousRange)
|
||||
else if invalidMarker = @buffer.invalidMarkers[id]
|
||||
@buffer.validMarkers[id] = invalidMarker
|
||||
|
||||
invalidMarker.revalidate()
|
||||
|
||||
@@ -8,9 +8,10 @@ class BufferMarker
|
||||
headPosition: null
|
||||
tailPosition: null
|
||||
suppressObserverNotification: false
|
||||
stayValid: false
|
||||
invalidationStrategy: null
|
||||
|
||||
constructor: ({@id, @buffer, range, @stayValid, noTail, reverse}) ->
|
||||
constructor: ({@id, @buffer, range, @invalidationStrategy, noTail, reverse}) ->
|
||||
@invalidationStrategy ?= 'contains'
|
||||
@setRange(range, {noTail, reverse})
|
||||
|
||||
setRange: (range, options={}) ->
|
||||
@@ -71,23 +72,30 @@ class BufferMarker
|
||||
newTailPosition = @getTailPosition()
|
||||
@notifyObservers({oldTailPosition, newTailPosition, bufferChanged: false})
|
||||
|
||||
tryToInvalidate: (oldRange) ->
|
||||
containsStart = oldRange.containsPoint(@getStartPosition(), exclusive: true)
|
||||
containsEnd = oldRange.containsPoint(@getEndPosition(), exclusive: true)
|
||||
return unless containsEnd or containsStart
|
||||
tryToInvalidate: (changedRange) ->
|
||||
betweenStartAndEnd = @getRange().containsRange(changedRange, exclusive: false)
|
||||
containsStart = changedRange.containsPoint(@getStartPosition(), exclusive: true)
|
||||
containsEnd = changedRange.containsPoint(@getEndPosition(), exclusive: true)
|
||||
|
||||
if @stayValid
|
||||
previousRange = @getRange()
|
||||
if containsStart and containsEnd
|
||||
@setRange([oldRange.end, oldRange.end])
|
||||
else if containsStart
|
||||
@setRange([oldRange.end, @getEndPosition()])
|
||||
else
|
||||
@setRange([@getStartPosition(), oldRange.start])
|
||||
[@id, previousRange]
|
||||
else
|
||||
@invalidate()
|
||||
[@id]
|
||||
switch @invalidationStrategy
|
||||
when 'between'
|
||||
if betweenStartAndEnd or containsStart or containsEnd
|
||||
@invalidate()
|
||||
[@id]
|
||||
when 'contains'
|
||||
if containsStart or containsEnd
|
||||
@invalidate()
|
||||
[@id]
|
||||
when 'never'
|
||||
if containsStart or containsEnd
|
||||
previousRange = @getRange()
|
||||
if containsStart and containsEnd
|
||||
@setRange([changedRange.end, changedRange.end])
|
||||
else if containsStart
|
||||
@setRange([changedRange.end, @getEndPosition()])
|
||||
else
|
||||
@setRange([@getStartPosition(), changedRange.start])
|
||||
[@id, previousRange]
|
||||
|
||||
handleBufferChange: (bufferChange) ->
|
||||
@consolidateObserverNotifications true, =>
|
||||
@@ -113,23 +121,31 @@ class BufferMarker
|
||||
[newRow, newColumn]
|
||||
|
||||
observe: (callback) ->
|
||||
@on 'position-changed', callback
|
||||
@on 'changed', callback
|
||||
cancel: => @unobserve(callback)
|
||||
|
||||
unobserve: (callback) ->
|
||||
@off 'position-changed', callback
|
||||
@off 'changed', callback
|
||||
|
||||
containsPoint: (point) ->
|
||||
@getRange().containsPoint(point)
|
||||
|
||||
notifyObservers: ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged}) ->
|
||||
notifyObservers: ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged} = {}) ->
|
||||
return if @suppressObserverNotification
|
||||
return if _.isEqual(newHeadPosition, oldHeadPosition) and _.isEqual(newTailPosition, oldTailPosition)
|
||||
|
||||
if newHeadPosition? and newTailPosition?
|
||||
return if _.isEqual(newHeadPosition, oldHeadPosition) and _.isEqual(newTailPosition, oldTailPosition)
|
||||
else if newHeadPosition?
|
||||
return if _.isEqual(newHeadPosition, oldHeadPosition)
|
||||
else if newTailPosition?
|
||||
return if _.isEqual(newTailPosition, oldTailPosition)
|
||||
|
||||
oldHeadPosition ?= @getHeadPosition()
|
||||
newHeadPosition ?= @getHeadPosition()
|
||||
oldTailPosition ?= @getTailPosition()
|
||||
newTailPosition ?= @getTailPosition()
|
||||
@trigger 'position-changed', {oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged}
|
||||
valid = @buffer.validMarkers[@id]?
|
||||
@trigger 'changed', {oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged, valid}
|
||||
|
||||
consolidateObserverNotifications: (bufferChanged, fn) ->
|
||||
@suppressObserverNotification = true
|
||||
@@ -141,8 +157,14 @@ class BufferMarker
|
||||
@suppressObserverNotification = false
|
||||
@notifyObservers({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged})
|
||||
|
||||
invalidate: (preserve) ->
|
||||
invalidate: ->
|
||||
delete @buffer.validMarkers[@id]
|
||||
@buffer.invalidMarkers[@id] = this
|
||||
@notifyObservers(bufferChanged: true)
|
||||
|
||||
revalidate: ->
|
||||
delete @buffer.invalidMarkers[@id]
|
||||
@buffer.validMarkers[@id] = this
|
||||
@notifyObservers(bufferChanged: true)
|
||||
|
||||
_.extend BufferMarker.prototype, EventEmitter
|
||||
|
||||
@@ -419,11 +419,6 @@ class Buffer
|
||||
return match[0][0] != '\t'
|
||||
undefined
|
||||
|
||||
logLines: (start=0, end=@getLastRow())->
|
||||
for row in [start..end]
|
||||
line = @lineForRow(row)
|
||||
console.log row, line, line.length
|
||||
|
||||
getRepo: -> @project?.repo
|
||||
|
||||
checkoutHead: ->
|
||||
@@ -442,4 +437,15 @@ class Buffer
|
||||
fileExists: ->
|
||||
@file.exists()
|
||||
|
||||
logLines: (start=0, end=@getLastRow())->
|
||||
for row in [start..end]
|
||||
line = @lineForRow(row)
|
||||
console.log row, line, line.length
|
||||
|
||||
getDebugSnapshot: ->
|
||||
lines = ['Buffer:']
|
||||
for row in [0..@getLastRow()]
|
||||
lines.push "#{row}: #{@lineForRow(row)}"
|
||||
lines.join('\n')
|
||||
|
||||
_.extend(Buffer.prototype, EventEmitter)
|
||||
|
||||
@@ -3,7 +3,6 @@ _ = require 'underscore'
|
||||
EventEmitter = require 'event-emitter'
|
||||
|
||||
configDirPath = fs.absolute("~/.atom")
|
||||
userInitScriptPath = fs.join(configDirPath, "user.coffee")
|
||||
bundledPackagesDirPath = fs.join(resourcePath, "src/packages")
|
||||
bundledThemesDirPath = fs.join(resourcePath, "themes")
|
||||
vendoredPackagesDirPath = fs.join(resourcePath, "vendor/packages")
|
||||
@@ -30,11 +29,29 @@ class Config
|
||||
@configFilePath = fs.resolve(configDirPath, 'config', ['json', 'cson'])
|
||||
@configFilePath ?= fs.join(configDirPath, 'config.cson')
|
||||
|
||||
initializeConfigDirectory: ->
|
||||
return if fs.exists(@configDirPath)
|
||||
|
||||
fs.makeDirectory(@configDirPath)
|
||||
|
||||
templateConfigDirPath = fs.resolve(window.resourcePath, 'dot-atom')
|
||||
|
||||
onConfigDirFile = (path) =>
|
||||
templatePath = fs.join(templateConfigDirPath, path)
|
||||
configPath = fs.join(@configDirPath, path)
|
||||
fs.write(configPath, fs.read(templatePath))
|
||||
fs.traverseTree(templateConfigDirPath, onConfigDirFile, (path) -> true)
|
||||
|
||||
configThemeDirPath = fs.join(@configDirPath, 'themes')
|
||||
onThemeDirFile = (path) ->
|
||||
templatePath = fs.join(bundledThemesDirPath, path)
|
||||
configPath = fs.join(configThemeDirPath, path)
|
||||
fs.write(configPath, fs.read(templatePath))
|
||||
fs.traverseTree(bundledThemesDirPath, onThemeDirFile, (path) -> true)
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@loadUserConfig()
|
||||
@requireUserInitScript()
|
||||
|
||||
|
||||
|
||||
loadUserConfig: ->
|
||||
if fs.exists(@configFilePath)
|
||||
@@ -81,10 +98,4 @@ class Config
|
||||
save: ->
|
||||
fs.writeObject(@configFilePath, @settings)
|
||||
|
||||
requireUserInitScript: ->
|
||||
try
|
||||
require userInitScriptPath if fs.exists(userInitScriptPath)
|
||||
catch error
|
||||
console.error "Failed to load `#{userInitScriptPath}`", error.stack, error
|
||||
|
||||
_.extend Config.prototype, EventEmitter
|
||||
|
||||
@@ -7,6 +7,7 @@ class DisplayBufferMarker
|
||||
bufferMarkerSubscription: null
|
||||
headScreenPosition: null
|
||||
tailScreenPosition: null
|
||||
valid: true
|
||||
|
||||
constructor: ({@id, @displayBuffer}) ->
|
||||
@buffer = @displayBuffer.buffer
|
||||
@@ -57,11 +58,11 @@ class DisplayBufferMarker
|
||||
|
||||
observe: (callback) ->
|
||||
@observeBufferMarkerIfNeeded()
|
||||
@on 'position-changed', callback
|
||||
@on 'changed', callback
|
||||
cancel: => @unobserve(callback)
|
||||
|
||||
unobserve: (callback) ->
|
||||
@off 'position-changed', callback
|
||||
@off 'changed', callback
|
||||
@unobserveBufferMarkerIfNeeded()
|
||||
|
||||
observeBufferMarkerIfNeeded: ->
|
||||
@@ -69,13 +70,14 @@ class DisplayBufferMarker
|
||||
@getHeadScreenPosition() # memoize current value
|
||||
@getTailScreenPosition() # memoize current value
|
||||
@bufferMarkerSubscription =
|
||||
@buffer.observeMarker @id, ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged}) =>
|
||||
@buffer.observeMarker @id, ({oldHeadPosition, newHeadPosition, oldTailPosition, newTailPosition, bufferChanged, valid}) =>
|
||||
@notifyObservers
|
||||
oldHeadBufferPosition: oldHeadPosition
|
||||
newHeadBufferPosition: newHeadPosition
|
||||
oldTailBufferPosition: oldTailPosition
|
||||
newTailBufferPosition: newTailPosition
|
||||
bufferChanged: bufferChanged
|
||||
valid: valid
|
||||
@displayBuffer.markers[@id] = this
|
||||
|
||||
unobserveBufferMarkerIfNeeded: ->
|
||||
@@ -83,28 +85,37 @@ class DisplayBufferMarker
|
||||
@bufferMarkerSubscription.cancel()
|
||||
delete @displayBuffer.markers[@id]
|
||||
|
||||
notifyObservers: ({oldHeadBufferPosition, oldTailBufferPosition, bufferChanged}) ->
|
||||
notifyObservers: ({oldHeadBufferPosition, oldTailBufferPosition, bufferChanged, valid} = {}) ->
|
||||
oldHeadScreenPosition = @getHeadScreenPosition()
|
||||
@headScreenPosition = null
|
||||
newHeadScreenPosition = @getHeadScreenPosition()
|
||||
|
||||
newHeadScreenPosition = oldHeadScreenPosition
|
||||
oldTailScreenPosition = @getTailScreenPosition()
|
||||
@tailScreenPosition = null
|
||||
newTailScreenPosition = @getTailScreenPosition()
|
||||
newTailScreenPosition = oldTailScreenPosition
|
||||
valid ?= true
|
||||
|
||||
return if _.isEqual(newHeadScreenPosition, oldHeadScreenPosition) and _.isEqual(newTailScreenPosition, oldTailScreenPosition)
|
||||
if valid
|
||||
@headScreenPosition = null
|
||||
newHeadScreenPosition = @getHeadScreenPosition()
|
||||
@tailScreenPosition = null
|
||||
newTailScreenPosition = @getTailScreenPosition()
|
||||
|
||||
validChanged = valid isnt @valid
|
||||
headScreenPositionChanged = not _.isEqual(newHeadScreenPosition, oldHeadScreenPosition)
|
||||
tailScreenPositionChanged = not _.isEqual(newTailScreenPosition, oldTailScreenPosition)
|
||||
return unless validChanged or headScreenPositionChanged or tailScreenPositionChanged
|
||||
|
||||
oldHeadBufferPosition ?= @getHeadBufferPosition()
|
||||
newHeadBufferPosition = @getHeadBufferPosition()
|
||||
newHeadBufferPosition = @getHeadBufferPosition() ? oldHeadBufferPosition
|
||||
oldTailBufferPosition ?= @getTailBufferPosition()
|
||||
newTailBufferPosition = @getTailBufferPosition()
|
||||
newTailBufferPosition = @getTailBufferPosition() ? oldTailBufferPosition
|
||||
@valid = valid
|
||||
|
||||
@trigger 'position-changed', {
|
||||
@trigger 'changed', {
|
||||
oldHeadScreenPosition, newHeadScreenPosition,
|
||||
oldTailScreenPosition, newTailScreenPosition,
|
||||
oldHeadBufferPosition, newHeadBufferPosition,
|
||||
oldTailBufferPosition, newTailBufferPosition,
|
||||
bufferChanged
|
||||
valid
|
||||
}
|
||||
|
||||
_.extend DisplayBufferMarker.prototype, EventEmitter
|
||||
|
||||
@@ -332,8 +332,9 @@ class DisplayBuffer
|
||||
getMarkers: ->
|
||||
_.values(@markers)
|
||||
|
||||
markScreenRange: (screenRange) ->
|
||||
@markBufferRange(@bufferRangeForScreenRange(screenRange))
|
||||
markScreenRange: (args...) ->
|
||||
bufferRange = @bufferRangeForScreenRange(args.shift())
|
||||
@markBufferRange(bufferRange, args...)
|
||||
|
||||
markBufferRange: (args...) ->
|
||||
@buffer.markRange(args...)
|
||||
@@ -419,4 +420,10 @@ class DisplayBuffer
|
||||
logLines: (start, end) ->
|
||||
@lineMap.logLines(start, end)
|
||||
|
||||
getDebugSnapshot: ->
|
||||
lines = ["Display Buffer:"]
|
||||
for screenLine, row in @lineMap.linesForScreenRows(0, @getLastRow())
|
||||
lines.push "#{row}: #{screenLine.text}"
|
||||
lines.join('\n')
|
||||
|
||||
_.extend DisplayBuffer.prototype, EventEmitter
|
||||
|
||||
@@ -538,11 +538,11 @@ class EditSession
|
||||
_.last(@cursors)
|
||||
|
||||
addCursorAtScreenPosition: (screenPosition) ->
|
||||
marker = @markScreenPosition(screenPosition, stayValid: true)
|
||||
marker = @markScreenPosition(screenPosition, invalidationStrategy: 'never')
|
||||
@addSelection(marker).cursor
|
||||
|
||||
addCursorAtBufferPosition: (bufferPosition) ->
|
||||
marker = @markBufferPosition(bufferPosition, stayValid: true)
|
||||
marker = @markBufferPosition(bufferPosition, invalidationStrategy: 'never')
|
||||
@addSelection(marker).cursor
|
||||
|
||||
addCursor: (marker) ->
|
||||
@@ -565,7 +565,7 @@ class EditSession
|
||||
selection
|
||||
|
||||
addSelectionForBufferRange: (bufferRange, options={}) ->
|
||||
options = _.defaults({stayValid: true}, options)
|
||||
options = _.defaults({invalidationStrategy: 'never'}, options)
|
||||
marker = @markBufferRange(bufferRange, options)
|
||||
@addSelection(marker)
|
||||
|
||||
@@ -820,5 +820,11 @@ class EditSession
|
||||
@displayBuffer.tokenizedBuffer.resetScreenLines()
|
||||
grammarChanged
|
||||
|
||||
getDebugSnapshot: ->
|
||||
[
|
||||
@displayBuffer.getDebugSnapshot()
|
||||
@displayBuffer.tokenizedBuffer.getDebugSnapshot()
|
||||
].join('\n\n')
|
||||
|
||||
_.extend(EditSession.prototype, EventEmitter)
|
||||
_.extend(EditSession.prototype, Subscriber)
|
||||
|
||||
@@ -19,7 +19,7 @@ class Editor extends View
|
||||
autosave: false
|
||||
autoIndent: true
|
||||
autoIndentOnPaste: false
|
||||
nonWordCharacters: "./\\()\"':,.;<>~!@#$%^&*|+=[]{}`~?"
|
||||
nonWordCharacters: "./\\()\"':,.;<>~!@#$%^&*|+=[]{}`~?-"
|
||||
|
||||
@nextEditorId: 1
|
||||
|
||||
@@ -194,6 +194,7 @@ class Editor extends View
|
||||
'editor:duplicate-line': @duplicateLine
|
||||
'editor:undo-close-session': @undoDestroySession
|
||||
'editor:toggle-indent-guide': => config.set('editor.showIndentGuide', !config.get('editor.showIndentGuide'))
|
||||
'editor:save-debug-snapshot': @saveDebugSnapshot
|
||||
|
||||
documentation = {}
|
||||
for name, method of editorBindings
|
||||
@@ -1226,16 +1227,9 @@ class Editor extends View
|
||||
lineElementForScreenRow: (screenRow) ->
|
||||
@renderedLines.children(":eq(#{screenRow - @firstRenderedScreenRow})")
|
||||
|
||||
logScreenLines: (start, end) ->
|
||||
@activeEditSession.logScreenLines(start, end)
|
||||
|
||||
toggleLineCommentsInSelection: ->
|
||||
@activeEditSession.toggleLineCommentsInSelection()
|
||||
|
||||
logRenderedLines: ->
|
||||
@renderedLines.find('.line').each (n) ->
|
||||
console.log n, $(this).text()
|
||||
|
||||
pixelPositionForBufferPosition: (position) ->
|
||||
@pixelPositionForScreenPosition(@screenPositionForBufferPosition(position))
|
||||
|
||||
@@ -1348,3 +1342,29 @@ class Editor extends View
|
||||
copyPathToPasteboard: ->
|
||||
path = @getPath()
|
||||
pasteboard.write(path) if path?
|
||||
|
||||
saveDebugSnapshot: ->
|
||||
atom.showSaveDialog (path) =>
|
||||
fs.write(path, @getDebugSnapshot()) if path
|
||||
|
||||
getDebugSnapshot: ->
|
||||
[
|
||||
"Debug Snapshot: #{@getPath()}"
|
||||
@getRenderedLinesDebugSnapshot()
|
||||
@activeEditSession.getDebugSnapshot()
|
||||
@getBuffer().getDebugSnapshot()
|
||||
].join('\n\n')
|
||||
|
||||
getRenderedLinesDebugSnapshot: ->
|
||||
lines = ['Rendered Lines:']
|
||||
firstRenderedScreenRow = @firstRenderedScreenRow
|
||||
@renderedLines.find('.line').each (n) ->
|
||||
lines.push "#{firstRenderedScreenRow + n}: #{$(this).text()}"
|
||||
lines.join('\n')
|
||||
|
||||
logScreenLines: (start, end) ->
|
||||
@activeEditSession.logScreenLines(start, end)
|
||||
|
||||
logRenderedLines: ->
|
||||
@renderedLines.find('.line').each (n) ->
|
||||
console.log n, $(this).text()
|
||||
|
||||
@@ -24,7 +24,7 @@ class Git
|
||||
ignore: 1 << 14
|
||||
|
||||
constructor: (path, options={}) ->
|
||||
@repo = new GitRepository(path)
|
||||
@repo = GitRepository.open(path)
|
||||
refreshIndexOnFocus = options.refreshIndexOnFocus ? true
|
||||
if refreshIndexOnFocus
|
||||
$ = require 'jquery'
|
||||
|
||||
@@ -22,15 +22,26 @@ class GrammarView extends SelectList
|
||||
|
||||
itemForElement: (grammar) ->
|
||||
if grammar is @currentGrammar
|
||||
grammarClass = 'current-grammar'
|
||||
grammarClass = 'active-item'
|
||||
else
|
||||
grammarClass = 'grammar'
|
||||
grammarClass = 'inactive-item'
|
||||
|
||||
$$ ->
|
||||
@li grammar.name, class: grammarClass
|
||||
|
||||
populate: ->
|
||||
grammars = new Array(syntax.grammars...)
|
||||
grammars.sort (grammarA, grammarB) ->
|
||||
if grammarA.scopeName is 'text.plain'
|
||||
-1
|
||||
else if grammarB.scopeName is 'text.plain'
|
||||
1
|
||||
else if grammarA.name < grammarB.name
|
||||
-1
|
||||
else if grammarA.name > grammarB.name
|
||||
1
|
||||
else
|
||||
0
|
||||
grammars.unshift(@autoDetect)
|
||||
@setArray(grammars)
|
||||
|
||||
|
||||
@@ -20,14 +20,14 @@ class Keymap
|
||||
'meta-n': 'new-window'
|
||||
'meta-,': 'open-user-configuration'
|
||||
'meta-o': 'open'
|
||||
'meta-O': 'open-unstable'
|
||||
'meta-O': 'open-dev'
|
||||
'meta-w': 'core:close'
|
||||
'alt-meta-i': 'toggle-dev-tools'
|
||||
|
||||
$(document).command 'new-window', => atom.newWindow()
|
||||
$(document).command 'open-user-configuration', => atom.open(config.configDirPath)
|
||||
$(document).command 'open', => atom.open()
|
||||
$(document).command 'open-unstable', => atom.openUnstable()
|
||||
$(document).command 'open-dev', => atom.openDev()
|
||||
|
||||
loadBundledKeymaps: ->
|
||||
@loadDirectory(require.resolve('keymaps'))
|
||||
|
||||
@@ -30,13 +30,13 @@ class LanguageMode
|
||||
|
||||
buffer = @editSession.buffer
|
||||
commentStartRegexString = _.escapeRegExp(commentStartString).replace(/(\s+)$/, '($1)?')
|
||||
commentStartRegex = new OnigRegExp("^(\\s*)(#{commentStartRegexString})")
|
||||
commentStartRegex = OnigRegExp.create("^(\\s*)(#{commentStartRegexString})")
|
||||
shouldUncomment = commentStartRegex.test(buffer.lineForRow(start))
|
||||
|
||||
if commentEndString = syntax.getProperty(scopes, "editor.commentEnd")
|
||||
if shouldUncomment
|
||||
commentEndRegexString = _.escapeRegExp(commentEndString).replace(/^(\s+)/, '($1)?')
|
||||
commentEndRegex = new OnigRegExp("(#{commentEndRegexString})(\\s*)$")
|
||||
commentEndRegex = OnigRegExp.create("(#{commentEndRegexString})(\\s*)$")
|
||||
startMatch = commentStartRegex.search(buffer.lineForRow(start))
|
||||
endMatch = commentEndRegex.search(buffer.lineForRow(end))
|
||||
if startMatch and endMatch
|
||||
@@ -78,7 +78,7 @@ class LanguageMode
|
||||
continue if @editSession.isBufferRowBlank(row)
|
||||
indentation = @editSession.indentationForBufferRow(row)
|
||||
if indentation <= startIndentLevel
|
||||
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes).search(@editSession.lineForBufferRow(row))
|
||||
includeRowInFold = indentation == startIndentLevel and @foldEndRegexForScopes(scopes)?.search(@editSession.lineForBufferRow(row))
|
||||
foldEndRow = row if includeRowInFold
|
||||
break
|
||||
|
||||
@@ -152,12 +152,12 @@ class LanguageMode
|
||||
|
||||
increaseIndentRegexForScopes: (scopes) ->
|
||||
if increaseIndentPattern = syntax.getProperty(scopes, 'editor.increaseIndentPattern')
|
||||
new OnigRegExp(increaseIndentPattern)
|
||||
OnigRegExp.create(increaseIndentPattern)
|
||||
|
||||
decreaseIndentRegexForScopes: (scopes) ->
|
||||
if decreaseIndentPattern = syntax.getProperty(scopes, 'editor.decreaseIndentPattern')
|
||||
new OnigRegExp(decreaseIndentPattern)
|
||||
OnigRegExp.create(decreaseIndentPattern)
|
||||
|
||||
foldEndRegexForScopes: (scopes) ->
|
||||
if foldEndPattern = syntax.getProperty(scopes, 'editor.foldEndPattern')
|
||||
new OnigRegExp(foldEndPattern)
|
||||
OnigRegExp.create(foldEndPattern)
|
||||
|
||||
@@ -194,7 +194,7 @@ class Project
|
||||
|
||||
ChildProcess.exec command , bufferLines: true, stdout: (data) ->
|
||||
lines = data.split('\n')
|
||||
lines.pop() # the last segment is a spurios '' because data always ends in \n due to bufferLines: true
|
||||
lines.pop() # the last segment is a spurious '' because data always ends in \n due to bufferLines: true
|
||||
for line in lines
|
||||
readPath(line) if state is 'readingPath'
|
||||
readLine(line) if state is 'readingLines'
|
||||
|
||||
@@ -57,7 +57,11 @@ class Range
|
||||
else
|
||||
otherRange.intersectsWith(this)
|
||||
|
||||
containsPoint: (point, { exclusive } = {}) ->
|
||||
containsRange: (otherRange, {exclusive} = {}) ->
|
||||
{ start, end } = Range.fromObject(otherRange)
|
||||
@containsPoint(start, {exclusive}) and @containsPoint(end, {exclusive})
|
||||
|
||||
containsPoint: (point, {exclusive} = {}) ->
|
||||
point = Point.fromObject(point)
|
||||
if exclusive
|
||||
point.isGreaterThan(@start) and point.isLessThan(@end)
|
||||
|
||||
@@ -28,7 +28,7 @@ class TextMateGrammar
|
||||
constructor: ({ @name, @fileTypes, @scopeName, patterns, repository, @foldingStopMarker, firstLineMatch}) ->
|
||||
@initialRule = new Rule(this, {@scopeName, patterns})
|
||||
@repository = {}
|
||||
@firstLineRegex = new OnigRegExp(firstLineMatch) if firstLineMatch
|
||||
@firstLineRegex = OnigRegExp.create(firstLineMatch) if firstLineMatch
|
||||
@fileTypes ?= []
|
||||
|
||||
for name, data of repository
|
||||
@@ -111,7 +111,7 @@ class Rule
|
||||
regex = pattern.regexSource
|
||||
regexes.push regex if regex
|
||||
|
||||
regexScanner = new OnigScanner(regexes)
|
||||
regexScanner = OnigScanner.create(regexes)
|
||||
regexScanner.patterns = patterns
|
||||
@scannersByBaseGrammarName[baseGrammar.name] = regexScanner unless anchored
|
||||
regexScanner
|
||||
|
||||
@@ -73,15 +73,27 @@ class TextMatePackage extends Package
|
||||
|
||||
scopedProperties
|
||||
|
||||
readObjectFromPath: (path, callback) ->
|
||||
object = null
|
||||
error = null
|
||||
if fs.isObjectPath(path)
|
||||
object = fs.readObject(path)
|
||||
else
|
||||
plist.parseString fs.read(path), (e, data) ->
|
||||
error = e
|
||||
object = data[0]
|
||||
error = throw new Error("Failed to load object at path `#{path}`") unless object
|
||||
callback(error, object)
|
||||
|
||||
getTextMatePreferenceObjects: ->
|
||||
preferenceObjects = []
|
||||
if fs.exists(@preferencesPath)
|
||||
for preferencePath in fs.list(@preferencesPath)
|
||||
plist.parseString fs.read(preferencePath), (e, data) =>
|
||||
@readObjectFromPath preferencePath, (e, object) =>
|
||||
if e
|
||||
console.warn "Failed to parse preference at path '#{preferencePath}'", e.stack
|
||||
else
|
||||
preferenceObjects.push(data[0])
|
||||
preferenceObjects.push(object)
|
||||
preferenceObjects
|
||||
|
||||
propertiesFromTextMateSettings: (textMateSettings) ->
|
||||
|
||||
@@ -226,4 +226,10 @@ class TokenizedBuffer
|
||||
line = @lineForScreenRow(row).text
|
||||
console.log row, line, line.length
|
||||
|
||||
getDebugSnapshot: ->
|
||||
lines = ["Tokenized Buffer:"]
|
||||
for screenLine, row in @linesForScreenRows(0, @getLastRow())
|
||||
lines.push "#{row}: #{screenLine.text}"
|
||||
lines.join('\n')
|
||||
|
||||
_.extend(TokenizedBuffer.prototype, EventEmitter)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
fs = require 'fs'
|
||||
$ = require 'jquery'
|
||||
ChildProcess = require 'child-process'
|
||||
require 'jquery-extensions'
|
||||
require 'underscore-extensions'
|
||||
require 'space-pen-extensions'
|
||||
@@ -39,6 +40,11 @@ window.setUpEnvironment = ->
|
||||
|
||||
# This method is only called when opening a real application window
|
||||
window.startup = ->
|
||||
if fs.isDirectory('/opt/boxen')
|
||||
installAtomCommand('/opt/boxen/bin/atom')
|
||||
else
|
||||
installAtomCommand('/opt/github/bin/atom')
|
||||
|
||||
handleWindowEvents()
|
||||
config.load()
|
||||
atom.loadTextPackage()
|
||||
@@ -47,12 +53,10 @@ window.startup = ->
|
||||
atom.loadThemes()
|
||||
atom.loadPackages()
|
||||
keymap.loadUserKeymaps()
|
||||
atom.requireUserInitScript()
|
||||
$(window).on 'beforeunload', -> shutdown(); false
|
||||
$(window).focus()
|
||||
|
||||
pathToOpen = atom.getPathToOpen()
|
||||
rootView.open(pathToOpen) if !pathToOpen or fs.isFile(pathToOpen)
|
||||
|
||||
window.shutdown = ->
|
||||
return if not project and not rootView
|
||||
atom.setWindowState('pathToOpen', project.getPath())
|
||||
@@ -65,6 +69,14 @@ window.shutdown = ->
|
||||
window.rootView = null
|
||||
window.project = null
|
||||
|
||||
window.installAtomCommand = (commandPath) ->
|
||||
return if fs.exists(commandPath)
|
||||
|
||||
bundledCommandPath = fs.resolve(window.resourcePath, 'atom.sh')
|
||||
if bundledCommandPath?
|
||||
fs.write(commandPath, fs.read(bundledCommandPath))
|
||||
ChildProcess.exec("chmod u+x '#{commandPath}'")
|
||||
|
||||
window.handleWindowEvents = ->
|
||||
$(window).on 'core:close', => window.close()
|
||||
$(window).command 'window:close', => window.close()
|
||||
@@ -76,12 +88,14 @@ window.buildProjectAndRootView = ->
|
||||
RootView = require 'root-view'
|
||||
Project = require 'project'
|
||||
|
||||
windowState = atom.getRootViewStateForPath(atom.getPathToOpen())
|
||||
if windowState?.project?
|
||||
window.project = deserialize(windowState.project)
|
||||
window.rootView = deserialize(windowState.rootView)
|
||||
window.project ?= new Project(atom.getPathToOpen())
|
||||
window.rootView ?= new RootView
|
||||
pathToOpen = atom.getPathToOpen()
|
||||
windowState = atom.getRootViewStateForPath(pathToOpen) ? {}
|
||||
window.project = deserialize(windowState.project) ? new Project(pathToOpen)
|
||||
window.rootView = deserialize(windowState.rootView) ? new RootView
|
||||
|
||||
if !windowState.rootView and (!pathToOpen or fs.isFile(pathToOpen))
|
||||
rootView.open(pathToOpen)
|
||||
|
||||
$(rootViewParentSelector).append(rootView)
|
||||
|
||||
window.stylesheetElementForId = (id) ->
|
||||
@@ -126,7 +140,7 @@ window.registerDeserializer = (klass) ->
|
||||
deserializers[klass.name] = klass
|
||||
|
||||
window.deserialize = (state) ->
|
||||
deserializers[state.deserializer]?.deserialize(state)
|
||||
deserializers[state?.deserializer]?.deserialize(state)
|
||||
|
||||
window.measure = (description, fn) ->
|
||||
start = new Date().getTime()
|
||||
|
||||
@@ -7,4 +7,3 @@ module.exports =
|
||||
rootView.eachEditor (editor) =>
|
||||
if editor.attached and not editor.mini
|
||||
@autoCompleteViews.push new AutocompleteView(editor)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ module.exports =
|
||||
class CommandPanelView extends View
|
||||
@content: ->
|
||||
@div class: 'command-panel tool-panel', =>
|
||||
@div class: 'loading', outlet: 'loadingMessage'
|
||||
@div class: 'loading is-loading', outlet: 'loadingMessage', 'Searching...'
|
||||
@div class: 'header', outlet: 'previewHeader', =>
|
||||
@ul outlet: 'expandCollapse', class: 'expand-collapse', =>
|
||||
@li class: 'expand', 'Expand All'
|
||||
@@ -53,6 +53,7 @@ class CommandPanelView extends View
|
||||
@previewList.hide()
|
||||
@previewHeader.hide()
|
||||
@errorMessages.hide()
|
||||
@loadingMessage.hide()
|
||||
@prompt.iconSize(@miniEditor.getFontSize())
|
||||
|
||||
@history = state.history ? []
|
||||
@@ -88,14 +89,7 @@ class CommandPanelView extends View
|
||||
@miniEditor.focus()
|
||||
|
||||
toggleLoading: ->
|
||||
if @loadingMessage.hasClass 'is-loading'
|
||||
@loadingMessage.removeClass 'is-loading'
|
||||
@loadingMessage.html ''
|
||||
@loadingMessage.hide()
|
||||
else
|
||||
@loadingMessage.addClass 'is-loading'
|
||||
@loadingMessage.html 'Searching...'
|
||||
@loadingMessage.show()
|
||||
@loadingMessage.toggle()
|
||||
|
||||
onExpandAll: (event) =>
|
||||
@previewList.expandAllPaths()
|
||||
|
||||
@@ -3,7 +3,7 @@ CommandPanelView = require 'command-panel/lib/command-panel-view'
|
||||
_ = require 'underscore'
|
||||
|
||||
describe "CommandPanel", ->
|
||||
[editor, buffer, commandPanel, CommandPanel] = []
|
||||
[editor, buffer, commandPanel] = []
|
||||
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
|
||||
@@ -2,7 +2,7 @@ module.exports =
|
||||
class StatsTracker
|
||||
startDate: new Date
|
||||
hours: 6
|
||||
eventLog: []
|
||||
eventLog: {}
|
||||
|
||||
constructor: ->
|
||||
date = new Date(@startDate)
|
||||
@@ -16,7 +16,7 @@ class StatsTracker
|
||||
rootView.on 'mouseup', => @track()
|
||||
|
||||
clear: ->
|
||||
@eventLog = []
|
||||
@eventLog = {}
|
||||
|
||||
track: ->
|
||||
date = new Date
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
RootView = require 'root-view'
|
||||
EditorStats = require 'editor-stats/lib/editor-stats-view'
|
||||
|
||||
describe "EditorStats", ->
|
||||
[editorStats, time] = []
|
||||
[editorStats] = []
|
||||
|
||||
simulateKeyUp = (key) ->
|
||||
e = $.Event "keydown", keyCode: key.charCodeAt(0)
|
||||
@@ -16,26 +17,22 @@ describe "EditorStats", ->
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
rootView.open('sample.js')
|
||||
|
||||
date = new Date()
|
||||
mins = date.getMinutes()
|
||||
hours = date.getHours()
|
||||
|
||||
mins = if mins == 60 then '01' else mins + 1
|
||||
time = "#{hours}:#{mins}"
|
||||
|
||||
editorStats = window.loadPackage('editor-stats').packageMain.stats
|
||||
|
||||
describe "when a keyup event is triggered", ->
|
||||
beforeEach ->
|
||||
expect(_.values(editorStats.eventLog)).not.toContain 1
|
||||
expect(_.values(editorStats.eventLog)).not.toContain 2
|
||||
|
||||
it "records the number of times a keyup is triggered", ->
|
||||
simulateKeyUp('a')
|
||||
expect(editorStats.eventLog[time]).toBe 1
|
||||
expect(_.values(editorStats.eventLog)).toContain 1
|
||||
simulateKeyUp('b')
|
||||
expect(editorStats.eventLog[time]).toBe 2
|
||||
expect(_.values(editorStats.eventLog)).toContain 2
|
||||
|
||||
describe "when a mouseup event is triggered", ->
|
||||
it "records the number of times a mouseup is triggered", ->
|
||||
simulateClick()
|
||||
expect(editorStats.eventLog[time]).toBe 1
|
||||
expect(_.values(editorStats.eventLog)).toContain 1
|
||||
simulateClick()
|
||||
expect(editorStats.eventLog[time]).toBe 2
|
||||
expect(_.values(editorStats.eventLog)).toContain 2
|
||||
|
||||
4
src/packages/gfm.tmbundle/Preferences/indent.cson
Normal file
4
src/packages/gfm.tmbundle/Preferences/indent.cson
Normal file
@@ -0,0 +1,4 @@
|
||||
'name': 'Indent'
|
||||
'scope': 'source.gfm'
|
||||
'settings':
|
||||
'increaseIndentPattern': '^\\s*([\\*\\+-])[ \\t]+'
|
||||
@@ -132,3 +132,10 @@ describe "GitHub Flavored Markdown grammar", ->
|
||||
{tokens} = grammar.tokenizeLine("> Quotation")
|
||||
expect(tokens[0]).toEqual value: ">", scopes: ["source.gfm", "support.quote.gfm"]
|
||||
expect(tokens[1]).toEqual value: " Quotation", scopes: ["source.gfm", "comment.quote.gfm"]
|
||||
|
||||
describe "auto indent", ->
|
||||
it "indents newlines entered after list lines", ->
|
||||
config.set('editor.autoIndent', true)
|
||||
editSession = fixturesProject.buildEditSessionForPath('gfm.md')
|
||||
editSession.insertNewlineBelow()
|
||||
expect(editSession.buffer.lineForRow(1)).toBe ' '
|
||||
|
||||
2
src/packages/spell-check/keymaps/spell-check.cson
Normal file
2
src/packages/spell-check/keymaps/spell-check.cson
Normal file
@@ -0,0 +1,2 @@
|
||||
'.editor':
|
||||
'meta-0': 'editor:correct-misspelling'
|
||||
71
src/packages/spell-check/lib/corrections-view.coffee
Normal file
71
src/packages/spell-check/lib/corrections-view.coffee
Normal file
@@ -0,0 +1,71 @@
|
||||
{$$} = require 'space-pen'
|
||||
Range = require 'range'
|
||||
SelectList = require 'select-list'
|
||||
|
||||
module.exports =
|
||||
class CorrectionsView extends SelectList
|
||||
@viewClass: -> "corrections #{super} popover-list"
|
||||
|
||||
editor: null
|
||||
corrections: null
|
||||
misspellingRange: null
|
||||
aboveCursor: false
|
||||
|
||||
initialize: (@editor, @corrections, @misspellingRange) ->
|
||||
super
|
||||
|
||||
@attach()
|
||||
|
||||
itemForElement: (word) ->
|
||||
$$ ->
|
||||
@li word
|
||||
|
||||
selectNextItem: ->
|
||||
super
|
||||
|
||||
false
|
||||
|
||||
selectPreviousItem: ->
|
||||
super
|
||||
|
||||
false
|
||||
|
||||
confirmed: (correction) ->
|
||||
@cancel()
|
||||
return unless correction
|
||||
@editor.transact =>
|
||||
@editor.setSelectedBufferRange(@editor.bufferRangeForScreenRange(@misspellingRange))
|
||||
@editor.insertText(correction)
|
||||
|
||||
attach: ->
|
||||
@aboveCursor = false
|
||||
if @corrections.length > 0
|
||||
@setArray(@corrections)
|
||||
else
|
||||
@setError("No corrections found")
|
||||
|
||||
@editor.appendToLinesView(this)
|
||||
@setPosition()
|
||||
@miniEditor.focus()
|
||||
|
||||
detach: ->
|
||||
super
|
||||
|
||||
@editor.focus()
|
||||
|
||||
setPosition: ->
|
||||
{ left, top } = @editor.pixelPositionForScreenPosition(@misspellingRange.start)
|
||||
height = @outerHeight()
|
||||
potentialTop = top + @editor.lineHeight
|
||||
potentialBottom = potentialTop - @editor.scrollTop() + height
|
||||
|
||||
if @aboveCursor or potentialBottom > @editor.outerHeight()
|
||||
@aboveCursor = true
|
||||
@css(left: left, top: top - height, bottom: 'inherit')
|
||||
else
|
||||
@css(left: left, top: potentialTop, bottom: 'inherit')
|
||||
|
||||
populateList: ->
|
||||
super
|
||||
|
||||
@setPosition()
|
||||
61
src/packages/spell-check/lib/misspelling-view.coffee
Normal file
61
src/packages/spell-check/lib/misspelling-view.coffee
Normal file
@@ -0,0 +1,61 @@
|
||||
{View} = require 'space-pen'
|
||||
Range = require 'range'
|
||||
CorrectionsView = require './corrections-view'
|
||||
|
||||
module.exports =
|
||||
class MisspellingView extends View
|
||||
@content: ->
|
||||
@div class: 'misspelling'
|
||||
|
||||
initialize: (range, @editor) ->
|
||||
@editSession = @editor.activeEditSession
|
||||
range = @editSession.screenRangeForBufferRange(Range.fromObject(range))
|
||||
@startPosition = range.start
|
||||
@endPosition = range.end
|
||||
@misspellingValid = true
|
||||
|
||||
@marker = @editSession.markScreenRange(range, invalidationStrategy: 'between')
|
||||
@editSession.observeMarker @marker, ({newHeadScreenPosition, newTailScreenPosition, valid}) =>
|
||||
@startPosition = newTailScreenPosition
|
||||
@endPosition = newHeadScreenPosition
|
||||
@updateDisplayPosition = valid
|
||||
@misspellingValid = valid
|
||||
@hide() unless valid
|
||||
|
||||
@subscribe @editor, 'editor:display-updated', =>
|
||||
@updatePosition() if @updateDisplayPosition
|
||||
|
||||
@editor.command 'editor:correct-misspelling', =>
|
||||
return unless @misspellingValid and @containsCursor()
|
||||
|
||||
screenRange = @getScreenRange()
|
||||
misspelling = @editor.getTextInRange(@editor.bufferRangeForScreenRange(screenRange))
|
||||
corrections = $native.getCorrectionsForMisspelling(misspelling)
|
||||
@correctionsView?.remove()
|
||||
@correctionsView = new CorrectionsView(@editor, corrections, screenRange)
|
||||
|
||||
@updatePosition()
|
||||
|
||||
getScreenRange: ->
|
||||
new Range(@startPosition, @endPosition)
|
||||
|
||||
containsCursor: ->
|
||||
cursor = @editor.getCursorScreenPosition()
|
||||
@getScreenRange().containsPoint(cursor, exclusive: false)
|
||||
|
||||
updatePosition: ->
|
||||
@updateDisplayPosition = false
|
||||
startPixelPosition = @editor.pixelPositionForScreenPosition(@startPosition)
|
||||
endPixelPosition = @editor.pixelPositionForScreenPosition(@endPosition)
|
||||
@css
|
||||
top: startPixelPosition.top
|
||||
left: startPixelPosition.left
|
||||
width: endPixelPosition.left - startPixelPosition.left
|
||||
height: @editor.lineHeight
|
||||
@show()
|
||||
|
||||
destroy: ->
|
||||
@misspellingValid = false
|
||||
@editSession.destroyMarker(@marker)
|
||||
@correctionsView?.remove()
|
||||
@remove()
|
||||
14
src/packages/spell-check/lib/spell-check-handler.coffee
Normal file
14
src/packages/spell-check/lib/spell-check-handler.coffee
Normal file
@@ -0,0 +1,14 @@
|
||||
module.exports =
|
||||
findMisspellings: (text) ->
|
||||
wordRegex = /(?:^|[\s\[\]])([a-zA-Z']+)(?=[\s\.\[\]]|$)/g
|
||||
row = 0
|
||||
misspellings = []
|
||||
for line in text.split('\n')
|
||||
while matches = wordRegex.exec(line)
|
||||
word = matches[1]
|
||||
continue unless $native.isMisspelled(word)
|
||||
startColumn = matches.index + matches[0].length - word.length
|
||||
endColumn = startColumn + word.length
|
||||
misspellings.push([[row, startColumn], [row, endColumn]])
|
||||
row++
|
||||
callTaskMethod('misspellingsFound', misspellings)
|
||||
13
src/packages/spell-check/lib/spell-check-task.coffee
Normal file
13
src/packages/spell-check/lib/spell-check-task.coffee
Normal file
@@ -0,0 +1,13 @@
|
||||
Task = require 'task'
|
||||
|
||||
module.exports =
|
||||
class SpellCheckTask extends Task
|
||||
constructor: (@text, @callback) ->
|
||||
super('spell-check/lib/spell-check-handler')
|
||||
|
||||
started: ->
|
||||
@callWorkerMethod('findMisspellings', @text)
|
||||
|
||||
misspellingsFound: (misspellings) ->
|
||||
@done()
|
||||
@callback(misspellings)
|
||||
53
src/packages/spell-check/lib/spell-check-view.coffee
Normal file
53
src/packages/spell-check/lib/spell-check-view.coffee
Normal file
@@ -0,0 +1,53 @@
|
||||
{View} = require 'space-pen'
|
||||
_ = require 'underscore'
|
||||
SpellCheckTask = require './spell-check-task'
|
||||
MisspellingView = require './misspelling-view'
|
||||
|
||||
module.exports =
|
||||
class SpellCheckView extends View
|
||||
@content: ->
|
||||
@div class: 'spell-check'
|
||||
|
||||
views: []
|
||||
|
||||
initialize: (@editor) ->
|
||||
@subscribe @editor, 'editor:path-changed', => @subscribeToBuffer()
|
||||
@subscribe @editor, 'editor:grammar-changed', => @subscribeToBuffer()
|
||||
@observeConfig 'editor.fontSize', => @subscribeToBuffer()
|
||||
@observeConfig 'spell-check.grammars', => @subscribeToBuffer()
|
||||
|
||||
@subscribeToBuffer()
|
||||
|
||||
subscribeToBuffer: ->
|
||||
@destroyViews()
|
||||
@task?.abort()
|
||||
return unless @spellCheckCurrentGrammar()
|
||||
|
||||
@buffer?.off '.spell-check'
|
||||
@buffer = @editor.getBuffer()
|
||||
@buffer.on 'contents-modified.spell-check', => @updateMisspellings()
|
||||
@updateMisspellings()
|
||||
|
||||
spellCheckCurrentGrammar: ->
|
||||
grammar = @editor.getGrammar().scopeName
|
||||
_.contains config.get('spell-check.grammars'), grammar
|
||||
|
||||
destroyViews: ->
|
||||
if @views
|
||||
view.destroy() for view in @views
|
||||
@views = []
|
||||
|
||||
addViews: (misspellings) ->
|
||||
for misspelling in misspellings
|
||||
view = new MisspellingView(misspelling, @editor)
|
||||
@views.push(view)
|
||||
@append(view)
|
||||
|
||||
updateMisspellings: ->
|
||||
@task?.abort()
|
||||
|
||||
callback = (misspellings) =>
|
||||
@destroyViews()
|
||||
@addViews(misspellings)
|
||||
@task = new SpellCheckTask(@buffer.getText(), callback)
|
||||
@task.start()
|
||||
20
src/packages/spell-check/lib/spell-check.coffee
Normal file
20
src/packages/spell-check/lib/spell-check.coffee
Normal file
@@ -0,0 +1,20 @@
|
||||
SpellCheckView = require './spell-check-view'
|
||||
|
||||
module.exports =
|
||||
configDefaults:
|
||||
grammars: [
|
||||
'text.plain'
|
||||
'source.gfm'
|
||||
'text.git-commit'
|
||||
]
|
||||
|
||||
activate: ->
|
||||
if syntax.grammars.length > 1
|
||||
@subscribeToEditors()
|
||||
else
|
||||
syntax.on 'grammars-loaded', => @subscribeToEditors()
|
||||
|
||||
subscribeToEditors: ->
|
||||
rootView.eachEditor (editor) ->
|
||||
if editor.attached and not editor.mini
|
||||
editor.underlayer.append(new SpellCheckView(editor))
|
||||
1
src/packages/spell-check/package.cson
Normal file
1
src/packages/spell-check/package.cson
Normal file
@@ -0,0 +1 @@
|
||||
'main': 'lib/spell-check.coffee'
|
||||
98
src/packages/spell-check/spec/spell-check-spec.coffee
Normal file
98
src/packages/spell-check/spec/spell-check-spec.coffee
Normal file
@@ -0,0 +1,98 @@
|
||||
RootView = require 'root-view'
|
||||
|
||||
describe "Spell check", ->
|
||||
[editor] = []
|
||||
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
rootView.open('sample.js')
|
||||
config.set('spell-check.grammars', [])
|
||||
window.loadPackage('spell-check')
|
||||
rootView.attachToDom()
|
||||
editor = rootView.getActiveEditor()
|
||||
|
||||
it "decorates all misspelled words", ->
|
||||
editor.setText("This middle of thiss sentencts has issues.")
|
||||
config.set('spell-check.grammars', ['source.js'])
|
||||
|
||||
waitsFor ->
|
||||
editor.find('.misspelling').length > 0
|
||||
|
||||
runs ->
|
||||
expect(editor.find('.misspelling').length).toBe 2
|
||||
|
||||
typo1StartPosition = editor.pixelPositionForBufferPosition([0, 15])
|
||||
typo1EndPosition = editor.pixelPositionForBufferPosition([0, 20])
|
||||
expect(editor.find('.misspelling:eq(0)').position()).toEqual typo1StartPosition
|
||||
expect(editor.find('.misspelling:eq(0)').width()).toBe typo1EndPosition.left - typo1StartPosition.left
|
||||
|
||||
typo2StartPosition = editor.pixelPositionForBufferPosition([0, 21])
|
||||
typo2EndPosition = editor.pixelPositionForBufferPosition([0, 30])
|
||||
expect(editor.find('.misspelling:eq(1)').position()).toEqual typo2StartPosition
|
||||
expect(editor.find('.misspelling:eq(1)').width()).toBe typo2EndPosition.left - typo2StartPosition.left
|
||||
|
||||
it "hides decorations when a misspelled word is edited", ->
|
||||
editor.setText('notaword')
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
config.set('spell-check.grammars', ['source.js'])
|
||||
|
||||
waitsFor ->
|
||||
editor.find('.misspelling').length > 0
|
||||
|
||||
runs ->
|
||||
expect(editor.find('.misspelling').length).toBe 1
|
||||
editor.moveCursorToEndOfLine()
|
||||
editor.insertText('a')
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
expect(editor.find('.misspelling')).toBeHidden()
|
||||
|
||||
describe "when spell checking for a grammar is removed", ->
|
||||
it "removes all current decorations", ->
|
||||
editor.setText('notaword')
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
config.set('spell-check.grammars', ['source.js'])
|
||||
|
||||
waitsFor ->
|
||||
editor.find('.misspelling').length > 0
|
||||
|
||||
runs ->
|
||||
expect(editor.find('.misspelling').length).toBe 1
|
||||
config.set('spell-check.grammars', [])
|
||||
expect(editor.find('.misspelling').length).toBe 0
|
||||
|
||||
describe "when 'editor:correct-misspelling' is triggered on the editor", ->
|
||||
describe "when the cursor touches a misspelling that has corrections", ->
|
||||
it "displays the corrections for the misspelling and replaces the misspelling when a correction is selected", ->
|
||||
editor.setText('fryday')
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
config.set('spell-check.grammars', ['source.js'])
|
||||
|
||||
waitsFor ->
|
||||
editor.find('.misspelling').length > 0
|
||||
|
||||
runs ->
|
||||
editor.trigger 'editor:correct-misspelling'
|
||||
expect(editor.find('.corrections').length).toBe 1
|
||||
expect(editor.find('.corrections li').length).toBeGreaterThan 0
|
||||
expect(editor.find('.corrections li:first').text()).toBe "Friday"
|
||||
editor.find('.corrections').view().confirmSelection()
|
||||
expect(editor.getText()).toBe 'Friday'
|
||||
expect(editor.getCursorBufferPosition()).toEqual [0, 6]
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
expect(editor.find('.misspelling')).toBeHidden()
|
||||
expect(editor.find('.corrections').length).toBe 0
|
||||
|
||||
describe "when the cursor touches a misspelling that has no corrections", ->
|
||||
it "displays a message saying no corrections found", ->
|
||||
editor.setText('asdfasdf')
|
||||
advanceClock(editor.getBuffer().stoppedChangingDelay)
|
||||
config.set('spell-check.grammars', ['source.js'])
|
||||
|
||||
waitsFor ->
|
||||
editor.find('.misspelling').length > 0
|
||||
|
||||
runs ->
|
||||
editor.trigger 'editor:correct-misspelling'
|
||||
expect(editor.find('.corrections').length).toBe 1
|
||||
expect(editor.find('.corrections li').length).toBe 0
|
||||
expect(editor.find('.corrections .error').text()).toBe "No corrections found"
|
||||
4
src/packages/spell-check/stylesheets/spell-check.css
Normal file
4
src/packages/spell-check/stylesheets/spell-check.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.misspelling {
|
||||
border-bottom: 1px dashed rgba(250, 128, 114, .5);
|
||||
position: absolute;
|
||||
}
|
||||
@@ -27,12 +27,11 @@ class SymbolsView extends SelectList
|
||||
$$ ->
|
||||
@li =>
|
||||
@div name, class: 'label'
|
||||
@div class: 'right', =>
|
||||
if position
|
||||
text = "Line #{position.row + 1}"
|
||||
else
|
||||
text = fs.base(file)
|
||||
@div text, class: 'function-details'
|
||||
if position
|
||||
text = "Line #{position.row + 1}"
|
||||
else
|
||||
text = fs.base(file)
|
||||
@div text, class: 'right function-details'
|
||||
|
||||
toggleFileSymbols: ->
|
||||
if @hasParent()
|
||||
|
||||
@@ -104,28 +104,34 @@ describe "SymbolsView", ->
|
||||
|
||||
describe "TagGenerator", ->
|
||||
it "generates tags for all JavaScript functions", ->
|
||||
tags = []
|
||||
|
||||
waitsForPromise ->
|
||||
tags = []
|
||||
path = require.resolve('fixtures/sample.js')
|
||||
callback = (tag) ->
|
||||
tags.push tag
|
||||
generator = new TagGenerator(path, callback)
|
||||
generator.generate().done ->
|
||||
expect(tags.length).toBe 2
|
||||
expect(tags[0].name).toBe "quicksort"
|
||||
expect(tags[0].position.row).toBe 0
|
||||
expect(tags[1].name).toBe "quicksort.sort"
|
||||
expect(tags[1].position.row).toBe 1
|
||||
generator.generate()
|
||||
|
||||
runs ->
|
||||
expect(tags.length).toBe 2
|
||||
expect(tags[0].name).toBe "quicksort"
|
||||
expect(tags[0].position.row).toBe 0
|
||||
expect(tags[1].name).toBe "quicksort.sort"
|
||||
expect(tags[1].position.row).toBe 1
|
||||
|
||||
it "generates no tags for text file", ->
|
||||
tags = []
|
||||
|
||||
waitsForPromise ->
|
||||
tags = []
|
||||
path = require.resolve('fixtures/sample.txt')
|
||||
callback = (tag) ->
|
||||
tags.push tag
|
||||
generator = new TagGenerator(path, callback)
|
||||
generator.generate().done ->
|
||||
expect(tags.length).toBe 0
|
||||
generator.generate()
|
||||
|
||||
runs ->
|
||||
expect(tags.length).toBe 0
|
||||
|
||||
describe "go to declaration", ->
|
||||
it "doesn't move the cursor when no declaration is found", ->
|
||||
@@ -155,11 +161,15 @@ describe "SymbolsView", ->
|
||||
expect(rootView.getActiveEditor().getCursorBufferPosition()).toEqual [0,4]
|
||||
|
||||
describe "when the tag is in a file that doesn't exist", ->
|
||||
renamedPath = null
|
||||
|
||||
beforeEach ->
|
||||
fs.move(project.resolve("tagged-duplicate.js"), project.resolve("tagged-duplicate-renamed.js"))
|
||||
renamedPath = project.resolve("tagged-duplicate-renamed.js")
|
||||
fs.remove(renamedPath) if fs.exists(renamedPath)
|
||||
fs.move(project.resolve("tagged-duplicate.js"), renamedPath)
|
||||
|
||||
afterEach ->
|
||||
fs.move(project.resolve("tagged-duplicate-renamed.js"), project.resolve("tagged-duplicate.js"))
|
||||
fs.move(renamedPath, project.resolve("tagged-duplicate.js"))
|
||||
|
||||
it "doesn't display the tag", ->
|
||||
rootView.open("tagged.js")
|
||||
|
||||
50
src/packages/toml.tmbundle/Syntaxes/toml.cson
Normal file
50
src/packages/toml.tmbundle/Syntaxes/toml.cson
Normal file
@@ -0,0 +1,50 @@
|
||||
'name': 'TOML'
|
||||
'scopeName': 'source.toml'
|
||||
'fileTypes': ['toml']
|
||||
'patterns': [
|
||||
{
|
||||
'match': '(?:^\\s*)(\\[([^\\]]+)\\])'
|
||||
'captures':
|
||||
'2': 'name': 'variable.keygroup.toml'
|
||||
'name': 'keygroup.toml'
|
||||
}
|
||||
{
|
||||
'match': '(?:^\\s*)(\\S+)\\s*='
|
||||
'captures':
|
||||
'1': 'name': 'entity.key.toml'
|
||||
'name': 'key.toml'
|
||||
}
|
||||
{
|
||||
'begin': '"'
|
||||
'beginCaptures':
|
||||
'0': 'name': 'string.begin.toml'
|
||||
'end': '"'
|
||||
'endCaptures':
|
||||
'0': 'name': 'string.end.toml'
|
||||
'name': 'string.toml'
|
||||
'patterns': [
|
||||
'match': '\\\\[nt0r"\\\\]'
|
||||
'name' : 'constant.character.escape.toml'
|
||||
]
|
||||
}
|
||||
{
|
||||
'match': '#.*$'
|
||||
'name': 'comment.toml'
|
||||
}
|
||||
{
|
||||
'match': 'true'
|
||||
'name': 'constant.language.boolean.true.toml'
|
||||
}
|
||||
{
|
||||
'match': 'false'
|
||||
'name': 'constant.language.boolean.false.toml'
|
||||
}
|
||||
{
|
||||
'match': '\\d{4}-\\d{2}-\\d{2}(T)\\d{2}:\\d{2}:\\d{2}(Z)'
|
||||
'name': 'support.date.toml'
|
||||
}
|
||||
{
|
||||
'match': '-?\\d+(\\.?\\d+)?'
|
||||
'name': 'constant.numeric.toml'
|
||||
}
|
||||
]
|
||||
65
src/packages/toml.tmbundle/spec/toml-spec.coffee
Normal file
65
src/packages/toml.tmbundle/spec/toml-spec.coffee
Normal file
@@ -0,0 +1,65 @@
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
describe "TOML grammar", ->
|
||||
grammar = null
|
||||
|
||||
beforeEach ->
|
||||
spyOn(syntax, "addGrammar")
|
||||
pack = new TextMatePackage(require.resolve("toml.tmbundle"))
|
||||
pack.load()
|
||||
grammar = pack.grammars[0]
|
||||
|
||||
it "parses the grammar", ->
|
||||
expect(grammar).toBeTruthy()
|
||||
expect(grammar.scopeName).toBe "source.toml"
|
||||
|
||||
it "tokenizes comments", ->
|
||||
{tokens} = grammar.tokenizeLine("# I am a comment")
|
||||
expect(tokens[0]).toEqual value: "# I am a comment", scopes: ["source.toml", "comment.toml"]
|
||||
|
||||
it "tokenizes strings", ->
|
||||
{tokens} = grammar.tokenizeLine('"I am a string"')
|
||||
expect(tokens[0]).toEqual value: '"', scopes: ["source.toml", "string.toml", "string.begin.toml"]
|
||||
expect(tokens[1]).toEqual value: 'I am a string', scopes: ["source.toml", "string.toml"]
|
||||
expect(tokens[2]).toEqual value: '"', scopes: ["source.toml", "string.toml","string.end.toml"]
|
||||
|
||||
{tokens} = grammar.tokenizeLine('"I\'m \\n escaped"')
|
||||
expect(tokens[0]).toEqual value: '"', scopes: ["source.toml", "string.toml", "string.begin.toml"]
|
||||
expect(tokens[1]).toEqual value: "I'm ", scopes: ["source.toml", "string.toml"]
|
||||
expect(tokens[2]).toEqual value: "\\n", scopes: ["source.toml", "string.toml", "constant.character.escape.toml"]
|
||||
expect(tokens[3]).toEqual value: " escaped", scopes: ["source.toml", "string.toml"]
|
||||
expect(tokens[4]).toEqual value: '"', scopes: ["source.toml", "string.toml", "string.end.toml"]
|
||||
|
||||
it "tokenizes booleans", ->
|
||||
{tokens} = grammar.tokenizeLine("true")
|
||||
expect(tokens[0]).toEqual value: "true", scopes: ["source.toml", "constant.language.boolean.true.toml"]
|
||||
{tokens} = grammar.tokenizeLine("false")
|
||||
expect(tokens[0]).toEqual value: "false", scopes: ["source.toml", "constant.language.boolean.false.toml"]
|
||||
|
||||
it "tokenizes numbers", ->
|
||||
{tokens} = grammar.tokenizeLine("123")
|
||||
expect(tokens[0]).toEqual value: "123", scopes: ["source.toml", "constant.numeric.toml"]
|
||||
|
||||
{tokens} = grammar.tokenizeLine("-1")
|
||||
expect(tokens[0]).toEqual value: "-1", scopes: ["source.toml", "constant.numeric.toml"]
|
||||
|
||||
{tokens} = grammar.tokenizeLine("3.14")
|
||||
expect(tokens[0]).toEqual value: "3.14", scopes: ["source.toml", "constant.numeric.toml"]
|
||||
|
||||
{tokens} = grammar.tokenizeLine("-123.456")
|
||||
expect(tokens[0]).toEqual value: "-123.456", scopes: ["source.toml", "constant.numeric.toml"]
|
||||
|
||||
it "tokenizes dates", ->
|
||||
{tokens} = grammar.tokenizeLine("1979-05-27T07:32:00Z")
|
||||
expect(tokens[0]).toEqual value: "1979-05-27T07:32:00Z", scopes: ["source.toml", "support.date.toml"]
|
||||
|
||||
it "tokenizes keygroups", ->
|
||||
{tokens} = grammar.tokenizeLine("[keygroup]")
|
||||
expect(tokens[0]).toEqual value: "[", scopes: ["source.toml", "keygroup.toml"]
|
||||
expect(tokens[1]).toEqual value: "keygroup", scopes: ["source.toml", "keygroup.toml", "variable.keygroup.toml"]
|
||||
expect(tokens[2]).toEqual value: "]", scopes: ["source.toml", "keygroup.toml"]
|
||||
|
||||
it "tokenizes keys", ->
|
||||
{tokens} = grammar.tokenizeLine("key =")
|
||||
expect(tokens[0]).toEqual value: "key", scopes: ["source.toml", "key.toml", "entity.key.toml"]
|
||||
expect(tokens[1]).toEqual value: " =", scopes: ["source.toml", "key.toml"]
|
||||
@@ -72,15 +72,12 @@ class TreeView extends ScrollView
|
||||
if @hasFocus()
|
||||
@detach()
|
||||
else
|
||||
if @hasParent()
|
||||
@focus()
|
||||
else
|
||||
@attach()
|
||||
@attach() unless @hasParent()
|
||||
@focus()
|
||||
|
||||
attach: ->
|
||||
return unless project.getPath()
|
||||
rootView.horizontal.prepend(this)
|
||||
@focus()
|
||||
|
||||
detach: ->
|
||||
@scrollTopAfterAttach = @scrollTop()
|
||||
@@ -134,6 +131,7 @@ class TreeView extends ScrollView
|
||||
|
||||
revealActiveFile: ->
|
||||
@attach()
|
||||
@focus()
|
||||
|
||||
return unless activeFilePath = rootView.getActiveEditor()?.getPath()
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module.exports =
|
||||
class GitRepository
|
||||
constructor: (path) ->
|
||||
@open: (path) ->
|
||||
unless repo = $git.getRepository(path)
|
||||
throw new Error("No Git repository found searching path: " + path)
|
||||
throw new Error("No Git repository found searching path: #{path}")
|
||||
repo.constructor = GitRepository
|
||||
repo.__proto__ = GitRepository.prototype
|
||||
return repo
|
||||
repo
|
||||
|
||||
getHead: $git.getHead
|
||||
getPath: $git.getPath
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module.exports =
|
||||
class OnigRegExp
|
||||
constructor: (source) ->
|
||||
@create: (source) ->
|
||||
regexp = $onigRegExp.buildOnigRegExp(source);
|
||||
regexp.constructor = OnigRegExp
|
||||
regexp.__proto__ = OnigRegExp.prototype
|
||||
regexp.source = source
|
||||
return regexp
|
||||
regexp
|
||||
|
||||
search: $onigRegExp.search
|
||||
test: $onigRegExp.test
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module.exports =
|
||||
class OnigScanner
|
||||
constructor: (sources) ->
|
||||
@create: (sources) ->
|
||||
scanner = $onigScanner.buildScanner(sources)
|
||||
scanner.constructor = OnigScanner
|
||||
scanner.__proto__ = OnigScanner.prototype
|
||||
scanner.sources = sources
|
||||
return scanner
|
||||
scanner
|
||||
|
||||
findNextMatch: $onigScanner.findNextMatch
|
||||
|
||||
@@ -53,7 +53,7 @@ exts =
|
||||
code or= __read file
|
||||
eval("define(function(require, exports, module) { 'use strict';#{code}})\n//@ sourceURL=#{file}")
|
||||
__defines.pop()?.call()
|
||||
coffee: (file, retry=true) ->
|
||||
coffee: (file) ->
|
||||
cacheFilePath = getCacheFilePath(file)
|
||||
if __exists(cacheFilePath)
|
||||
compiled = __read(cacheFilePath)
|
||||
|
||||
@@ -61,22 +61,20 @@
|
||||
content: '\f078';
|
||||
font-family: 'Octicons Regular';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: #fba0e3;
|
||||
opacity: .8;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.editor .fold-marker:after {
|
||||
font-size: .8em;
|
||||
content: '\f09a';
|
||||
opacity: .8;
|
||||
color: #fba0e3;
|
||||
padding-left: .2em;
|
||||
font-family: 'Octicons Regular';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.editor .line.cursor-line .fold-marker {
|
||||
.editor .line.cursor-line .fold-marker:after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
overflow-y: auto;
|
||||
max-height: 312px;
|
||||
margin: 0;
|
||||
background: red;
|
||||
padding: 0;
|
||||
line-height: 100%;
|
||||
-webkit-user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.select-list ol:empty {
|
||||
@@ -42,4 +43,19 @@
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-shadow: 0 1px 0 #4E0000;
|
||||
}
|
||||
}
|
||||
|
||||
.select-list li.active-item:before {
|
||||
font-family: 'Octicons Regular';
|
||||
font-size: 14px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 5px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: #9d9d9d;
|
||||
content: '\f03a';
|
||||
}
|
||||
|
||||
.select-list li.inactive-item {
|
||||
padding-left: 29px;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
color: #c5c8c6;
|
||||
}
|
||||
|
||||
.editor .gutter .line-number.fold,
|
||||
.editor .gutter .line-number:after,
|
||||
.editor .fold-marker:after {
|
||||
color: #fba0e3;
|
||||
}
|
||||
|
||||
.editor .invisible {
|
||||
color: #c5c8c6;
|
||||
}
|
||||
|
||||
@@ -18,8 +18,3 @@
|
||||
-webkit-animation-duration: 1s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
.editor .gutter .line-number.fold {
|
||||
color: #fba0e3;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
@@ -7,12 +7,6 @@
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.select-list li .right {
|
||||
color: #999;
|
||||
display: inline-block;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.select-list .key-binding {
|
||||
background: -webkit-linear-gradient(
|
||||
rgba(100, 100, 100, 0.5),
|
||||
@@ -24,13 +18,14 @@
|
||||
}
|
||||
|
||||
.select-list li:hover {
|
||||
background-color: #555;
|
||||
background-color: #2c2c2c;
|
||||
}
|
||||
|
||||
.select-list ol .selected {
|
||||
background-image: -webkit-linear-gradient(#7e7e7e, #737373);
|
||||
}
|
||||
|
||||
.select-list .right,
|
||||
.select-list .directory {
|
||||
color: #777;
|
||||
}
|
||||
@@ -39,6 +34,7 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.select-list ol .selected .right,
|
||||
.select-list ol .selected .directory {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.editor .gutter .line-number.fold,
|
||||
.editor .gutter .line-number:after,
|
||||
.editor .fold-marker:after {
|
||||
color: #e87b00;
|
||||
}
|
||||
|
||||
.editor .invisible {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
@@ -103,3 +103,11 @@
|
||||
.command-panel li.operation.selected .preview {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.error-messages {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.error .error-messages {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@@ -24,8 +24,3 @@
|
||||
-webkit-animation-duration: 1s;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
.editor .gutter .line-number.fold {
|
||||
color: #fba0e3;
|
||||
opacity: .8;
|
||||
}
|
||||
|
||||
6
themes/atom-light-ui/overlay.css
Normal file
6
themes/atom-light-ui/overlay.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.overlay {
|
||||
background-color: #e5e5e5;
|
||||
border-top: 1px solid #979797;
|
||||
color: #333;
|
||||
padding: 10px;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
'stylesheets': [
|
||||
'atom.css'
|
||||
'editor.css'
|
||||
'overlay.css'
|
||||
'select-list.css'
|
||||
'tree-view.css'
|
||||
'tabs.css'
|
||||
|
||||
@@ -20,4 +20,14 @@
|
||||
|
||||
.select-list ol .selected {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-list .right,
|
||||
.select-list .directory {
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.select-list ol .selected .right,
|
||||
.select-list ol .selected .directory {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
@@ -12,4 +12,10 @@
|
||||
.status-bar .git-status.octicons.new-status-icon {
|
||||
color: #5293d8;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.status-bar .grammar-name:hover {
|
||||
color: #000;
|
||||
border: 1px solid rgba(50, 50, 50, 0.2);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
1
vendor/packages/clojure.tmbundle
vendored
Submodule
1
vendor/packages/clojure.tmbundle
vendored
Submodule
Submodule vendor/packages/clojure.tmbundle added at 546b39c972
1
vendor/packages/java.tmbundle
vendored
Submodule
1
vendor/packages/java.tmbundle
vendored
Submodule
Submodule vendor/packages/java.tmbundle added at 1c315ed461
1
vendor/packages/less.tmbundle
vendored
Submodule
1
vendor/packages/less.tmbundle
vendored
Submodule
Submodule vendor/packages/less.tmbundle added at a202dd9942
1
vendor/packages/perl.tmbundle
vendored
Submodule
1
vendor/packages/perl.tmbundle
vendored
Submodule
Submodule vendor/packages/perl.tmbundle added at fccaee006d
1
vendor/packages/php.tmbundle
vendored
Submodule
1
vendor/packages/php.tmbundle
vendored
Submodule
Submodule vendor/packages/php.tmbundle added at bb576b5575
1
vendor/packages/sass.tmbundle
vendored
Submodule
1
vendor/packages/sass.tmbundle
vendored
Submodule
Submodule vendor/packages/sass.tmbundle added at e2bef05afa
1
vendor/packages/yaml.tmbundle
vendored
Submodule
1
vendor/packages/yaml.tmbundle
vendored
Submodule
Submodule vendor/packages/yaml.tmbundle added at 173808ba47
Reference in New Issue
Block a user