Merge branch 'master' of github.com:github/atom

This commit is contained in:
Nathan Sobo
2012-08-27 11:02:39 -05:00
27 changed files with 562 additions and 179 deletions

1
.pairs
View File

@@ -2,6 +2,7 @@ pairs:
ns: Nathan Sobo; nathan
cj: Corey Johnson; cj
dg: David Graham; dgraham
ks: Kevin Sawicki; kevin
email:
domain: github.com
#global: true

View File

@@ -1,2 +1,2 @@
bin/
/atom
*.o

View File

@@ -1,3 +1,5 @@
INSTALLDIR=/usr/share/atom
CXXFLAGS := -Werror \
-pthread \
-fno-exceptions \
@@ -36,6 +38,7 @@ LDFLAGS := -pthread \
-Wl,-O1 \
-Wl,--as-needed \
-Wl,--gc-sections \
-Wl,-rpath=$(INSTALLDIR)
LIBS := -lX11 \
-lgtk-x11-2.0 \
@@ -56,32 +59,34 @@ LIBS := -lX11 \
-lssl \
-lcrypto \
-lcef \
-lcef_dll_wrapper
-lcef_dll_wrapper \
-lonig
SOURCES=atom.cpp native_handler.cpp client_handler.cpp
SOURCES=atom.cpp native_handler.cpp client_handler.cpp onig_regexp_extension.cpp io_utils.cpp
OBJECTS=$(SOURCES:.cpp=.o)
INSTALLDIR=/usr/local/atom
all:
g++ $(CXXFLAGS) -c $(SOURCES)
mkdir -p bin
cp chrome.pak bin/
cp -R locales bin/
cp atom.png bin/
g++ -o bin/atom $(OBJECTS) $(LDFLAGS) $(LIBS)
g++ -o atom $(OBJECTS) $(LDFLAGS) $(LIBS)
clean:
rm -rf bin *.o
rm -rf atom *.o
install:
mkdir -p $(INSTALLDIR)
cp -R bin $(INSTALLDIR)
cp -R lib $(INSTALLDIR)
cp atom $(INSTALLDIR)
cp chrome.pak $(INSTALLDIR)
cp -R locales $(INSTALLDIR)
cp atom.png $(INSTALLDIR)
cp lib/libcef.so $(INSTALLDIR)
cp lib/libcef_dll_wrapper.a $(INSTALLDIR)
cp -R ../src $(INSTALLDIR)
cp -R ../static $(INSTALLDIR)
cp -R ../vendor $(INSTALLDIR)
cp -R ../bundles $(INSTALLDIR)
cp -R ../themes $(INSTALLDIR)
cp ../index.html $(INSTALLDIR)
coffee -c -o $(INSTALLDIR)/src/stdlib ../src/stdlib/require.coffee
ln -sf $(INSTALLDIR)/atom /usr/local/bin/atom
spec-install: install

View File

@@ -1,11 +0,0 @@
#!/bin/sh
case $0 in
/* )
root=${0%atom}
;;
* )
root=`pwd`/${0%atom}
;;
esac
export LD_LIBRARY_PATH=$root'../atom/lib':$LD_LIBRARY_PATH
$root'../atom/bin/atom' $@

View File

@@ -3,8 +3,6 @@
// can be found in the LICENSE file.
#include <gtk/gtk.h>
#include <stdlib.h>
#include <iostream>
#include <unistd.h>
#include <string>
#include "atom.h"
@@ -13,6 +11,8 @@
#include "include/cef_frame.h"
#include "include/cef_runnable.h"
#include "client_handler.h"
#include "onig_regexp_extension.h"
#include "io_utils.h"
char* szWorkingDir; // The current working directory
@@ -58,9 +58,11 @@ int main(int argc, char *argv[]) {
if (szWorkingDir == NULL)
return -1;
std::string fullPath = argv[0];
fullPath = fullPath.substr(0, fullPath.length() - 5);
szPath = fullPath.c_str();
std::string appDir = io_util_app_directory();
if (appDir.empty())
return -1;
szPath = appDir.c_str();
std::string pathToOpen;
if (argc >= 2) {
@@ -102,23 +104,20 @@ int main(int argc, char *argv[]) {
g_handler->SetMainHwnd(vbox);
g_handler->SetWindow(window);
new OnigRegexpExtension();
// Create the browser view.
CefWindowInfo window_info;
CefBrowserSettings browserSettings;
window_info.SetAsChild(vbox);
std::string path;
path.append(szPath);
path.append("/../index.html");
char* realPath;
realPath = realpath(path.c_str(), NULL);
if (realPath == NULL)
std::string path = io_utils_real_app_path("/index.html");
if (path.empty())
return -1;
std::string resolved("file://");
resolved.append(realPath);
free(realPath);
resolved.append(path);
CefBrowser::CreateBrowserSync(window_info,
static_cast<CefRefPtr<CefClient> >(g_handler), resolved, browserSettings);
@@ -159,4 +158,3 @@ std::string AppPath() {
std::string PathToOpen() {
return szPathToOpen;
}

View File

@@ -1,9 +1,5 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_CEFCLIENT_H_
#define CEF_TESTS_CEFCLIENT_CEFCLIENT_H_
#ifndef ATOM_H_
#define ATOM_H_
#pragma once
#include <string>
@@ -31,4 +27,4 @@ std::string PathToOpen();
// Returns the application settings
void AppGetSettings(CefSettings& settings, CefRefPtr<CefApp>& app);
#endif // CEF_TESTS_CEFCLIENT_CEFCLIENT_H_
#endif

View File

@@ -11,11 +11,13 @@
#include "include/cef_frame.h"
#include "atom.h"
#include "native_handler.h"
#include "atom.h"
#include <stdlib.h>
#include <gtk/gtk.h>
ClientHandler::ClientHandler() :
m_MainHwnd(NULL), m_BrowserHwnd(NULL) {
m_nativeHandler = new NativeHandler();
}
ClientHandler::~ClientHandler() {
@@ -73,7 +75,7 @@ void ClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
global->SetValue("$windowNumber", windowNumber, V8_PROPERTY_ATTRIBUTE_NONE);
std::string path;
if (m_nativeHandler)
if (m_nativeHandler && !m_nativeHandler->path.empty())
path = m_nativeHandler->path;
else
path.append(PathToOpen());
@@ -81,28 +83,14 @@ void ClientHandler::OnLoadStart(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefV8Value> pathToOpen = CefV8Value::CreateString(path);
global->SetValue("$pathToOpen", pathToOpen, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<NativeHandler> nativeHandler = new NativeHandler();
nativeHandler->window = window;
nativeHandler->path = path;
global->SetValue("$native", nativeHandler->object,
V8_PROPERTY_ATTRIBUTE_NONE);
m_nativeHandler = nativeHandler;
m_nativeHandler->window = window;
m_nativeHandler->path = path;
CefRefPtr<CefV8Value> atom = CefV8Value::CreateObject(NULL, NULL);
global->SetValue("atom", atom, V8_PROPERTY_ATTRIBUTE_NONE);
std::string relativePath(AppPath());
relativePath.append("/..");
char* realLoadPath;
realLoadPath = realpath(relativePath.c_str(), NULL);
if (realLoadPath != NULL) {
std::string resolvedLoadPath(realLoadPath);
free(realLoadPath);
CefRefPtr<CefV8Value> loadPath = CefV8Value::CreateString(
resolvedLoadPath);
atom->SetValue("loadPath", loadPath, V8_PROPERTY_ATTRIBUTE_NONE);
}
CefRefPtr<CefV8Value> loadPath = CefV8Value::CreateString(AppPath());
atom->SetValue("loadPath", loadPath, V8_PROPERTY_ATTRIBUTE_NONE);
CefRefPtr<CefV8Value> bootstrapScript = CefV8Value::CreateString(
"single-window-bootstrap");

View File

@@ -1,9 +1,5 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_
#define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_
#ifndef CLIENT_HANDLER_H_
#define CLIENT_HANDLER_H_
#pragma once
#include <map>
@@ -156,4 +152,4 @@ IMPLEMENT_LOCKING(ClientHandler)
;
};
#endif // CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_H_
#endif

49
Atom-Linux/io_utils.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "io_utils.h"
#include "atom.h"
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUFFER_SIZE 8192
using namespace std;
int io_utils_read(string path, string* output) {
int fd = open(path.c_str(), O_RDONLY);
if (fd <= 0)
return 0;
char buffer[BUFFER_SIZE];
unsigned int bytesRead = 0;
unsigned int totalRead = 0;
while ((bytesRead = read(fd, buffer, BUFFER_SIZE)) > 0) {
output->append(buffer, 0, bytesRead);
totalRead += bytesRead;
}
close(fd);
return totalRead;
}
string io_utils_real_app_path(string relativePath) {
string path = AppPath() + relativePath;
char* realPath = realpath(path.c_str(), NULL);
if (realPath != NULL) {
string realAppPath(realPath);
free(realPath);
return realAppPath;
} else
return "";
}
string io_util_app_directory() {
char path[BUFFER_SIZE];
if (readlink("/proc/self/exe", path, BUFFER_SIZE) < 2)
return "";
string appPath(path);
unsigned int lastSlash = appPath.rfind("/");
if (lastSlash != string::npos)
return appPath.substr(0, lastSlash);
else
return appPath;
}

22
Atom-Linux/io_utils.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef IO_UTILS_H_
#define IO_UTILS_H_
#pragma once
#include <string>
/**
* Read file at path and append to output string
*/
int io_utils_read(std::string path, std::string* output);
/**
* Get realpath for given path that is relative to the app path
*/
std::string io_utils_real_app_path(std::string relativePath);
/**
* Get path to directory where atom app resides
*/
std::string io_util_app_directory();
#endif

View File

@@ -2,6 +2,7 @@
#include "include/cef_base.h"
#include "include/cef_runnable.h"
#include "client_handler.h"
#include "io_utils.h"
#include <iostream>
#include <fstream>
#include <sstream>
@@ -50,19 +51,11 @@ void ExecuteWatchCallback(NotifyContext notifyContext) {
NativeHandler::NativeHandler() :
CefV8Handler() {
object = CefV8Value::CreateObject(NULL, NULL);
const char *functionNames[] = { "exists", "alert", "read", "write",
"absolute", "list", "isFile", "isDirectory", "remove", "asyncList",
"open", "openDialog", "quit", "writeToPasteboard", "readFromPasteboard",
"showDevTools", "newWindow", "saveDialog", "exit", "watchPath",
"unwatchPath", "makeDirectory", "move", "moveToTrash", "md5ForPath" };
int arrayLength = sizeof(functionNames) / sizeof(const char *);
for (int i = 0; i < arrayLength; i++) {
const char *functionName = functionNames[i];
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName,
this);
object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
string nativePath = io_utils_real_app_path("/src/stdlib/native-handler.js");
if (!nativePath.empty()) {
string extensionCode;
if (io_utils_read(nativePath, &extensionCode) > 0)
CefRegisterExtension("v8/native-handler", extensionCode, this);
}
notifyFd = inotify_init();
@@ -109,16 +102,8 @@ void NativeHandler::Read(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
int fd = open(path.c_str(), O_RDONLY);
if (fd < 0)
return;
char buffer[8192];
int r;
string value;
while ((r = read(fd, buffer, sizeof buffer)) > 0)
value.append(buffer, 0, r);
close(fd);
io_utils_read(path, &value);
retval = CefV8Value::CreateString(value);
}
@@ -276,10 +261,10 @@ void NativeHandler::Write(const CefString& name, CefRefPtr<CefV8Value> object,
string path = arguments[0]->GetStringValue().ToString();
string content = arguments[1]->GetStringValue().ToString();
ofstream myfile;
myfile.open(path.c_str());
myfile << content;
myfile.close();
ofstream file;
file.open(path.c_str());
file << content;
file.close();
}
void NativeHandler::WriteToPasteboard(const CefString& name,
@@ -457,7 +442,7 @@ void NativeHandler::Digest(const CefString& name, CefRefPtr<CefV8Value> object,
EVP_MD_CTX_init(&context);
EVP_DigestInit_ex(&context, md, NULL);
char buffer[8192];
char buffer[BUFFER_SIZE];
int r;
while ((r = read(fd, buffer, sizeof buffer)) > 0)
EVP_DigestUpdate(&context, buffer, r);
@@ -477,6 +462,17 @@ void NativeHandler::Digest(const CefString& name, CefRefPtr<CefV8Value> object,
retval = CefV8Value::CreateString(md5.str());
}
void NativeHandler::LastModified(const CefString& name,
CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
struct stat statInfo;
if (stat(path.c_str(), &statInfo) == 0) {
CefTime time(statInfo.st_mtime);
retval = CefV8Value::CreateDate(time);
}
}
bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
@@ -520,6 +516,10 @@ bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
UnwatchPath(name, object, arguments, retval, exception);
else if (name == "md5ForPath")
Digest(name, object, arguments, retval, exception);
else if (name == "getPlatform")
retval = CefV8Value::CreateString("linux");
else if (name == "lastModified")
LastModified(name, object, arguments, retval, exception);
else
cout << "Unhandled -> " + name.ToString() << " : "
<< arguments[0]->GetStringValue().ToString() << endl;

View File

@@ -1,5 +1,5 @@
#ifndef CEF_TESTS_CEFCLIENT_NATIVE_HANDLER_H_
#define CEF_TESTS_CEFCLIENT_NATIVE_HANDLER_H_
#ifndef NATIVE_HANDLER_H_
#define NATIVE_HANDLER_H_
#include "include/cef_base.h"
#include "include/cef_v8.h"
@@ -21,8 +21,6 @@ class NativeHandler: public CefV8Handler {
public:
NativeHandler();
CefRefPtr<CefV8Value> object;
GtkWidget* window;
std::string path;
@@ -121,6 +119,10 @@ private:
void Digest(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
void LastModified(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
};
#endif

View File

@@ -0,0 +1,185 @@
#include "onig_regexp_extension.h"
#include "include/cef_base.h"
#include "include/cef_runnable.h"
#include <oniguruma.h>
#include <iostream>
#include <stdlib.h>
#include "io_utils.h"
using namespace std;
class OnigRegexpUserData: public CefBase {
public:
OnigRegexpUserData(CefRefPtr<CefV8Value> source) {
OnigErrorInfo error;
string input = source->GetStringValue().ToString();
int length = input.length();
UChar* pattern = (UChar*) input.c_str();
int code = onig_new(&regex, pattern, pattern + length,
ONIG_OPTION_SINGLELINE, ONIG_ENCODING_UTF8, ONIG_SYNTAX_DEFAULT,
&error);
if (code != ONIG_NORMAL) {
char errorText[ONIG_MAX_ERROR_MESSAGE_LEN];
onig_error_code_to_str((OnigUChar*) errorText, code, &error);
cout << errorText << " for pattern: " << input << endl;
}
}
~OnigRegexpUserData() {
onig_free(regex);
}
OnigRegion* SearchRegion(string input, int index) {
if (!regex)
return NULL;
OnigRegion* region = onig_region_new();
UChar* search = (UChar*) input.c_str();
unsigned char* start = search + index;
unsigned char* end = search + input.length();
int code = onig_search(regex, search, end, start, end, region,
ONIG_OPTION_NONE);
if (code >= 0)
return region;
else {
onig_region_free(region, 1);
return NULL;
}
}
CefRefPtr<CefV8Value> Search(CefRefPtr<CefV8Value> argument,
CefRefPtr<CefV8Value> index) {
string input = argument->GetStringValue().ToString();
OnigRegion* region = SearchRegion(input, index->GetIntValue());
if (!region)
return CefV8Value::CreateNull();
CefRefPtr<CefV8Value> indices;
CefRefPtr<CefV8Value> resultArray = CefV8Value::CreateArray();
CefRefPtr<CefV8Value> indicesArray = CefV8Value::CreateArray();
for (int i = 0; i < region->num_regs; i++) {
int begin = region->beg[i];
int end = region->end[i];
resultArray->SetValue(i,
CefV8Value::CreateString(input.substr(begin, end - begin)));
indicesArray->SetValue(i, CefV8Value::CreateInt(begin));
}
resultArray->SetValue("index", CefV8Value::CreateInt(region->beg[0]),
V8_PROPERTY_ATTRIBUTE_NONE);
resultArray->SetValue("indices", indicesArray, V8_PROPERTY_ATTRIBUTE_NONE);
onig_region_free(region, 1);
return resultArray;
}
CefRefPtr<CefV8Value> Test(CefRefPtr<CefV8Value> argument,
CefRefPtr<CefV8Value> index) {
OnigRegion* region = SearchRegion(argument->GetStringValue().ToString(),
index->GetIntValue());
CefRefPtr<CefV8Value> text = CefV8Value::CreateBool(region != NULL);
if (region)
onig_region_free(region, 1);
return text;
}
CefRefPtr<CefV8Value> GetCaptureIndices(CefRefPtr<CefV8Value> argument,
CefRefPtr<CefV8Value> index) {
OnigRegion* region = SearchRegion(argument->GetStringValue().ToString(),
index->GetIntValue());
CefRefPtr<CefV8Value> indices;
if (region) {
indices = BuildCaptureIndices(region);
onig_region_free(region, 1);
} else
indices = CefV8Value::CreateNull();
return indices;
}
CefRefPtr<CefV8Value> BuildCaptureIndices(OnigRegion *region) {
CefRefPtr<CefV8Value> array = CefV8Value::CreateArray();
int i = 0;
for (int index = 0; index < region->num_regs; index++) {
int begin = region->beg[index];
int end = region->end[index];
if (end - begin <= 0)
continue;
array->SetValue(i++, CefV8Value::CreateInt(index));
array->SetValue(i++, CefV8Value::CreateInt(begin));
array->SetValue(i++, CefV8Value::CreateInt(end));
}
return array;
}
CefRefPtr<CefV8Value> CaptureCount() {
if (regex)
return CefV8Value::CreateInt(onig_number_of_captures(regex));
else
return CefV8Value::CreateInt(0);
}
regex_t* regex;
IMPLEMENT_REFCOUNTING(OnigRegexpUserData)
;
}
;
OnigRegexpExtension::OnigRegexpExtension() :
CefV8Handler() {
string realFilePath = io_utils_real_app_path(
"/src/stdlib/onig-reg-exp-extension.js");
if (!realFilePath.empty()) {
string extensionCode;
if (io_utils_read(realFilePath, &extensionCode) > 0)
CefRegisterExtension("v8/oniguruma", extensionCode, this);
}
}
bool OnigRegexpExtension::Execute(const CefString& name,
CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) {
if (name == "getCaptureIndices") {
CefRefPtr<CefV8Value> string = arguments[0];
CefRefPtr<CefV8Value> index =
arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0);
OnigRegexpUserData *userData =
(OnigRegexpUserData *) object->GetUserData().get();
retval = userData->GetCaptureIndices(string, index);
return true;
}
if (name == "search") {
CefRefPtr<CefV8Value> string = arguments[0];
CefRefPtr<CefV8Value> index =
arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0);
OnigRegexpUserData *userData =
(OnigRegexpUserData *) object->GetUserData().get();
retval = userData->Search(string, index);
return true;
}
if (name == "test") {
CefRefPtr<CefV8Value> string = arguments[0];
CefRefPtr<CefV8Value> index =
arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0);
OnigRegexpUserData *userData =
(OnigRegexpUserData *) object->GetUserData().get();
retval = userData->Test(string, index);
return true;
}
if (name == "buildOnigRegExp") {
CefRefPtr<CefBase> userData = new OnigRegexpUserData(arguments[0]);
retval = CefV8Value::CreateObject(userData, NULL);
return true;
}
if (name == "getCaptureCount") {
OnigRegexpUserData *userData =
(OnigRegexpUserData *) object->GetUserData().get();
retval = userData->CaptureCount();
return true;
}
return false;
}

View File

@@ -0,0 +1,21 @@
#ifndef ONIG_REGEXP_EXTENSION_H_
#define ONIG_REGEXP_EXTENSION_H_
#include "include/cef_base.h"
#include "include/cef_v8.h"
class OnigRegexpExtension: public CefV8Handler {
public:
OnigRegexpExtension();
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
IMPLEMENT_REFCOUNTING(OnigRegexpExtension)
;
};
#endif

View File

@@ -2,8 +2,8 @@
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFCLIENT_UTIL_H_
#define CEF_TESTS_CEFCLIENT_UTIL_H_
#ifndef UTIL_H_
#define UTIL_H_
#pragma once
#include "include/cef_task.h"
@@ -19,4 +19,4 @@
#define REQUIRE_IO_THREAD() ASSERT(CefCurrentlyOn(TID_IO));
#define REQUIRE_FILE_THREAD() ASSERT(CefCurrentlyOn(TID_FILE));
#endif // CEF_TESTS_CEFCLIENT_UTIL_H_
#endif

View File

@@ -1,8 +1,8 @@
#import "PathWatcher.h"
#import <sys/event.h>
#import <sys/time.h>
#import <sys/param.h>
#import <sys/time.h>
#import <sys/param.h>
#import <fcntl.h>
static NSMutableArray *gPathWatchers;
@@ -13,7 +13,7 @@ static NSMutableArray *gPathWatchers;
- (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback callbackId:(NSString *)callbackId;
- (void)stopWatching;
- (void)reassignFileDescriptor:(NSNumber *)fdNumber from:(NSString *)path to:(NSString *)newPath;
- (bool)isAtomicWrite:(struct kevent)event;
- (bool)isAtomicWrite:(struct kevent)event path:(NSString *)path;
@end
@implementation PathWatcher
@@ -28,12 +28,12 @@ static NSMutableArray *gPathWatchers;
break;
}
}
if (!pathWatcher) {
pathWatcher = [[[PathWatcher alloc] initWithContext:context] autorelease];
[gPathWatchers addObject:pathWatcher];
}
return pathWatcher;
}
@@ -45,7 +45,7 @@ static NSMutableArray *gPathWatchers;
break;
}
}
if (pathWatcher) {
[pathWatcher stopWatching];
[gPathWatchers removeObject:pathWatcher];
@@ -65,17 +65,17 @@ static NSMutableArray *gPathWatchers;
- (id)initWithContext:(CefRefPtr<CefV8Context>)context {
self = [super init];
_keepWatching = YES;
_callbacksByFileDescriptor = [[NSMutableDictionary alloc] init];
_fileDescriptorsByPath = [[NSMutableDictionary alloc] init];
_kq = kqueue();
_context = context;
if (_kq == -1) {
[NSException raise:@"PathWatcher" format:@"Could not create kqueue"];
}
[self performSelectorInBackground:@selector(watch) withObject:NULL];
return self;
}
@@ -96,27 +96,27 @@ static NSMutableArray *gPathWatchers;
- (NSString *)watchPath:(NSString *)path callback:(WatchCallback)callback callbackId:(NSString *)callbackId {
path = [path stringByStandardizingPath];
@synchronized(self) {
NSNumber *fdNumber = [_fileDescriptorsByPath objectForKey:path];
NSNumber *fdNumber = [_fileDescriptorsByPath objectForKey:path];
if (!fdNumber) {
int fd = open([path fileSystemRepresentation], O_EVTONLY, 0);
int fd = open([path fileSystemRepresentation], O_EVTONLY, 0);
if (fd < 0) return nil;
[self watchFileDescriptor:fd];
fdNumber = [NSNumber numberWithInt:fd];
[_fileDescriptorsByPath setObject:fdNumber forKey:path];
}
NSMutableDictionary *callbacks = [_callbacksByFileDescriptor objectForKey:fdNumber];
if (!callbacks) {
if (!callbacks) {
callbacks = [NSMutableDictionary dictionary];
[_callbacksByFileDescriptor setObject:callbacks forKey:fdNumber];
[_callbacksByFileDescriptor setObject:callbacks forKey:fdNumber];
}
[callbacks setObject:callback forKey:callbackId];
}
return callbackId;
}
@@ -132,22 +132,22 @@ static NSMutableArray *gPathWatchers;
NSError *e = [NSError errorWithDomain:@"PathWatcher" code:0 userInfo:userInfo];
*error = e;
}
return;
return;
}
NSMutableDictionary *callbacks = [_callbacksByFileDescriptor objectForKey:fdNumber];
if (!callbacks) return;
if (!callbacks) return;
if (callbackId) {
[callbacks removeObjectForKey:callbackId];
}
else {
[callbacks removeAllObjects];
}
if (callbacks.count == 0) {
close([fdNumber intValue]);
[_callbacksByFileDescriptor removeObjectForKey:fdNumber];
[_callbacksByFileDescriptor removeObjectForKey:fdNumber];
[_fileDescriptorsByPath removeObjectForKey:path];
}
}
@@ -159,7 +159,7 @@ static NSMutableArray *gPathWatchers;
for (NSString *path in paths) {
[self unwatchPath:path callbackId:nil error:nil];
}
}
}
}
- (void)watchFileDescriptor:(int)fd {
@@ -180,24 +180,15 @@ static NSMutableArray *gPathWatchers;
}
}
}
return nil;
}
- (bool)isAtomicWrite:(struct kevent)event {
- (bool)isAtomicWrite:(struct kevent)event path:(NSString *)path {
if (!event.fflags & NOTE_DELETE) return NO;
[NSThread sleepForTimeInterval:0.01]; // HACK: Git deletes files only to create them again later. This is the cheap way of dealing with that
NSFileManager *fm = [NSFileManager defaultManager];
NSString *path = nil;
@synchronized(self) {
for (path in [_fileDescriptorsByPath allKeys]) {
if ([[_fileDescriptorsByPath objectForKey:path] unsignedLongValue] == event.ident) {
return [fm fileExistsAtPath:path];
}
}
}
return NO;
return [fm fileExistsAtPath:path];
}
- (void)reassignFileDescriptor:(NSNumber *)fdNumber from:(NSString *)path to:(NSString *)newPath {
@@ -211,25 +202,25 @@ static NSMutableArray *gPathWatchers;
}
- (void)updatePath:(NSString *)path forFileDescriptor:(NSNumber *)fdNumber {
// The path associated with the fd been updated. Remove references to old fd
// The path associated with the fd been updated. Remove references to old fd
// and make sure the path and callbacks are linked with new fd.
@synchronized(self) {
NSDictionary *callbacks = [NSDictionary dictionaryWithDictionary:[_callbacksByFileDescriptor objectForKey:fdNumber]];
NSDictionary *callbacks = [NSDictionary dictionaryWithDictionary:[_callbacksByFileDescriptor objectForKey:fdNumber]];
[self unwatchPath:path callbackId:nil error:nil];
for (NSString *callbackId in [callbacks allKeys]) {
[self watchPath:path callback:[callbacks objectForKey:callbackId] callbackId:callbackId];
}
}
}
}
- (void)watch {
struct kevent event;
- (void)watch {
struct kevent event;
struct timespec timeout = { 5, 0 }; // 5 seconds timeout.
while (_keepWatching) {
@autoreleasepool {
int numberOfEvents = kevent(_kq, NULL, 0, &event, 1, &timeout);
if (numberOfEvents < 0) {
NSLog(@"PathWatcher: error %d", numberOfEvents);
}
@@ -240,12 +231,12 @@ static NSMutableArray *gPathWatchers;
NSNumber *fdNumber = [NSNumber numberWithInt:event.ident];
NSString *eventFlag = nil;
NSString *path = [[[self pathForFileDescriptor:fdNumber] retain] autorelease];
NSString *newPath = nil;
NSString *newPath = nil;
if (event.fflags & NOTE_WRITE) {
eventFlag = @"contents-change";
}
else if ([self isAtomicWrite:event]) {
else if ([self isAtomicWrite:event path:path]) {
eventFlag = @"contents-change";
[self updatePath:path forFileDescriptor:fdNumber];
}
@@ -258,7 +249,7 @@ static NSMutableArray *gPathWatchers;
fcntl((int)event.ident, F_GETPATH, &pathBuffer);
newPath = [NSString stringWithUTF8String:pathBuffer];
}
NSDictionary *callbacks;
@synchronized(self) {
callbacks = [NSDictionary dictionaryWithDictionary:[_callbacksByFileDescriptor objectForKey:fdNumber]];
@@ -266,7 +257,7 @@ static NSMutableArray *gPathWatchers;
dispatch_sync(dispatch_get_main_queue(), ^{
for (NSString *key in callbacks) {
WatchCallback callback = [callbacks objectForKey:key];
WatchCallback callback = [callbacks objectForKey:key];
callback(eventFlag, newPath ? newPath : path);
}
});

View File

@@ -31,19 +31,9 @@ void throwException(const CefRefPtr<CefV8Value>& global, CefRefPtr<CefV8Exceptio
}
NativeHandler::NativeHandler() : CefV8Handler() {
std::string extensionCode = "var $native = {}; (function() {";
const char *functionNames[] = {"exists", "alert", "read", "write", "absolute", "list", "isFile", "isDirectory", "remove", "asyncList", "open", "openDialog", "quit", "writeToPasteboard", "readFromPasteboard", "showDevTools", "toggleDevTools", "newWindow", "saveDialog", "exit", "watchPath", "unwatchPath", "makeDirectory", "move", "moveToTrash", "reload", "lastModified", "md5ForPath", "exec"};
NSUInteger arrayLength = sizeof(functionNames) / sizeof(const char *);
for (NSUInteger i = 0; i < arrayLength; i++) {
std::string functionName = std::string(functionNames[i]);
extensionCode += "native function " + functionName + "(); $native." + functionName + " = " + functionName + ";";
}
extensionCode += "})();";
// Register the extension.
CefRegisterExtension("v8/test", extensionCode, this);
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"src/stdlib/native-handler.js"];
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
CefRegisterExtension("v8/native-handler", [extensionCode UTF8String], this);
}
bool NativeHandler::Execute(const CefString& name,
@@ -525,5 +515,9 @@ bool NativeHandler::Execute(const CefString& name,
return true;
}
else if (name == "getPlatform") {
retval = CefV8Value::CreateString("mac");
return true;
}
return false;
};

View File

@@ -9,7 +9,7 @@
2. Install CoffeeScript http://coffeescript.org/
```
brew install nodejs
curl http://npmjs.org/install.sh | sh
curl https://npmjs.org/install.sh | sh
npm i -g coffee-script
```

View File

@@ -68,9 +68,11 @@ task :"copy-files-to-bundle" => :"verify-prerequisites" do
cp_r dir, File.join(dest, dir)
end
sh "coffee -c -o #{dest}/src/stdlib src/stdlib/require.coffee"
cp "src/stdlib/onig-reg-exp-extension.js", "#{dest}/src/stdlib"
unless ENV['LOAD_RESOURCES_FROM_DIR']
if ENV['LOAD_RESOURCES_FROM_DIR']
sh "coffee -c -o #{dest}/src/stdlib src/stdlib/require.coffee"
cp "src/stdlib/onig-reg-exp-extension.js", "#{dest}/src/stdlib"
cp "src/stdlib/native-handler.js", "#{dest}/src/stdlib"
else
%w(src static vendor spec benchmark bundles themes).each do |dir|
rm_rf File.join(dest, dir)
cp_r dir, File.join(dest, dir)

18
docs/file-modification Normal file
View File

@@ -0,0 +1,18 @@
Buffers
modify
- if dirty alert user (immediately if focused, or on next focus)
- if clean update contents
remove
- mark file as unsaved (but maintains previous path)
- only unsubscribe from KQueue
- attempt to resubscribe after timeout (because of git weirdness)
move file
- update path
move ancestor directory
- update path on focus and save
recreated after remove (at same path)
- resubscribe on focus or save

View File

@@ -48,7 +48,9 @@ describe 'File', ->
newPath = fs.join(fs.directory(path), "atom-file-was-moved-test.txt")
afterEach ->
fs.remove(newPath) if fs.exists(newPath)
if fs.exists(newPath)
fs.remove(newPath)
waitsFor "remove event", (done) -> file.on 'remove', done
it "it updates its path", ->
moveHandler = null

View File

@@ -0,0 +1,6 @@
describe 'Native', ->
describe '$native.getPlatform()', ->
it 'returns a non-empty value', ->
platform = $native.getPlatform()
expect(platform).not.toBe ''
expect(platform.length).toBeGreaterThan(0)

View File

@@ -13,6 +13,7 @@ windowAdditions =
rootViewParentSelector: 'body'
rootView: null
keymap: null
platform: $native.getPlatform()
setUpKeymap: ->
Keymap = require 'keymap'
@@ -55,7 +56,8 @@ windowAdditions =
$(@rootViewParentSelector).append @rootView
requireStylesheet: (path) ->
fullPath = require.resolve(path)
unless fullPath = require.resolve(path)
throw new Error("requireStylesheet could not find a file at path '#{path}'")
window.applyStylesheet(fullPath, fs.read(fullPath))
applyStylesheet: (id, text) ->
@@ -106,3 +108,6 @@ require 'underscore-extensions'
requireStylesheet 'reset.css'
requireStylesheet 'atom.css'
if nativeStylesheetPath = require.resolve("#{platform}.css")
requireStylesheet(nativeStylesheetPath)

View File

@@ -0,0 +1,94 @@
var $native = {};
(function() {
native function exists(path);
$native.exists = exists;
native function alert(message, detailedMessage, buttonNamesAndCallbacks);
$native.alert = alert;
native function read(path);
$native.read = read;
native function write(path, content);
$native.write = write;
native function absolute(path);
$native.absolute = absolute;
native function list(path, recursive);
$native.list = list;
native function isFile(path);
$native.isFile = isFile;
native function isDirectory(path);
$native.isDirectory = isDirectory;
native function remove(path);
$native.remove = remove;
native function asyncList(path, recursive, callback);
$native.asyncList = asyncList;
native function open(path);
$native.open = open;
native function openDialog();
$native.openDialog = openDialog;
native function quit();
$native.quit = quit;
native function writeToPasteboard(text);
$native.writeToPasteboard = writeToPasteboard;
native function readFromPasteboard();
$native.readFromPasteboard = readFromPasteboard;
native function showDevTools();
$native.showDevTools = showDevTools;
native function toggleDevTools();
$native.toggleDevTools = toggleDevTools;
native function newWindow();
$native.newWindow = newWindow;
native function saveDialog();
$native.saveDialog = saveDialog;
native function exit(status);
$native.exit = exit;
native function watchPath(path);
$native.watchPath = watchPath;
native function unwatchPath(path, callbackId);
$native.unwatchPath = unwatchPath;
native function makeDirectory(path);
$native.makeDirectory = makeDirectory;
native function move(sourcePath, targetPath);
$native.move = move;
native function moveToTrash(path);
$native.moveToTrash = moveToTrash;
native function reload();
$native.reload = reload;
native function lastModified(path);
$native.lastModified = lastModified;
native function md5ForPath(path);
$native.md5ForPath = md5ForPath;
native function exec(command, options, callback);
$native.exec = exec;
native function getPlatform();
$native.getPlatform = getPlatform;
})();

View File

@@ -19,10 +19,12 @@ nakedLoad = (file) ->
code = __read file
window.eval(code + "\n//@ sourceURL=" + file)
require = (file, cb) ->
return cb require file if cb?
require = (path, cb) ->
return cb require path if cb?
unless file = resolve(path)
throw new Error("Require can't find file at path '#{path}'")
file = resolve file
parts = file.split '.'
ext = parts[parts.length-1]
@@ -88,10 +90,10 @@ resolve = (file) ->
else
file = __expand(file) or file
if file[0] isnt '/'
throw "require: Can't find '#{file}'"
return file
if file[0] == '/'
file
else
null
__expand = (path) ->
return path if __isFile path

View File

@@ -122,4 +122,8 @@
.editor .fold {
background-color: #444;
}
.editor .fold.selected {
background-color: #244;
}

13
static/linux.css Normal file
View File

@@ -0,0 +1,13 @@
::-webkit-scrollbar-corner {
background-color: transparent;
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb {
-webkit-border-radius: 2px;
background: rgba(150, 150, 150, .33);
}