mirror of
https://github.com/pulsar-edit/pulsar.git
synced 2024-12-28 17:13:45 +03:00
Merge branch 'web-workers' into dev
This commit is contained in:
commit
493ed5f006
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -36,13 +36,13 @@
|
||||
#define CEF_INCLUDE_CEF_VERSION_H_
|
||||
|
||||
#define CEF_VERSION_MAJOR 3
|
||||
#define CEF_REVISION 1050
|
||||
#define CEF_REVISION 1065
|
||||
#define COPYRIGHT_YEAR 2013
|
||||
|
||||
#define CHROME_VERSION_MAJOR 25
|
||||
#define CHROME_VERSION_MINOR 0
|
||||
#define CHROME_VERSION_BUILD 1364
|
||||
#define CHROME_VERSION_PATCH 29
|
||||
#define CHROME_VERSION_PATCH 45
|
||||
|
||||
#define DO_MAKE_STRING(p) #p
|
||||
#define MAKE_STRING(p) DO_MAKE_STRING(p)
|
||||
|
@ -16,10 +16,22 @@ class AtomCefRenderProcessHandler : public CefRenderProcessHandler {
|
||||
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) OVERRIDE;
|
||||
|
||||
virtual void OnWorkerContextCreated(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE;
|
||||
virtual void OnWorkerContextReleased(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context) OVERRIDE;
|
||||
virtual void OnWorkerUncaughtException(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Exception> exception,
|
||||
CefRefPtr<CefV8StackTrace> stackTrace) OVERRIDE;
|
||||
|
||||
void Reload(CefRefPtr<CefBrowser> browser);
|
||||
void Shutdown(CefRefPtr<CefBrowser> browser);
|
||||
bool CallMessageReceivedHandler(CefRefPtr<CefV8Context> context, CefRefPtr<CefProcessMessage> message);
|
||||
void InjectExtensionsIntoV8Context(CefRefPtr<CefV8Context> context);
|
||||
|
||||
IMPLEMENT_REFCOUNTING(AtomCefRenderProcessHandler);
|
||||
};
|
||||
|
@ -9,26 +9,44 @@
|
||||
#import "path_watcher.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
void AtomCefRenderProcessHandler::OnWebKitInitialized() {
|
||||
new v8_extensions::Atom();
|
||||
new v8_extensions::Native();
|
||||
new v8_extensions::OnigRegExp();
|
||||
new v8_extensions::OnigScanner();
|
||||
new v8_extensions::Git();
|
||||
new v8_extensions::Tags();
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::OnContextCreated(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
InjectExtensionsIntoV8Context(context);
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::OnContextReleased(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
[PathWatcher removePathWatcherForContext:context];
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::OnWorkerContextCreated(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
InjectExtensionsIntoV8Context(context);
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::OnWorkerContextReleased(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context) {
|
||||
NSLog(@"Web worker context released");
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::OnWorkerUncaughtException(int worker_id,
|
||||
const CefString& url,
|
||||
CefRefPtr<CefV8Context> context,
|
||||
CefRefPtr<CefV8Exception> exception,
|
||||
CefRefPtr<CefV8StackTrace> stackTrace) {
|
||||
|
||||
std::string message = exception->GetMessage().ToString();
|
||||
NSLog(@"Exception throw in worker thread %s", message.c_str());
|
||||
}
|
||||
|
||||
bool AtomCefRenderProcessHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
|
||||
CefProcessId source_process,
|
||||
CefRefPtr<CefProcessMessage> message) {
|
||||
@ -100,3 +118,13 @@ bool AtomCefRenderProcessHandler::CallMessageReceivedHandler(CefRefPtr<CefV8Cont
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void AtomCefRenderProcessHandler::InjectExtensionsIntoV8Context(CefRefPtr<CefV8Context> context) {
|
||||
// these objects are deleted when the context removes all references to them
|
||||
(new v8_extensions::Atom())->CreateContextBinding(context);
|
||||
(new v8_extensions::Native())->CreateContextBinding(context);
|
||||
(new v8_extensions::Git())->CreateContextBinding(context);
|
||||
(new v8_extensions::OnigRegExp())->CreateContextBinding(context);
|
||||
(new v8_extensions::OnigScanner())->CreateContextBinding(context);
|
||||
(new v8_extensions::Tags())->CreateContextBinding(context);
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace v8_extensions {
|
||||
class Atom : public CefV8Handler {
|
||||
public:
|
||||
Atom();
|
||||
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
@ -14,5 +14,9 @@ namespace v8_extensions {
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Atom);
|
||||
|
||||
private:
|
||||
Atom(Atom const&);
|
||||
void operator=(Atom const&);
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +0,0 @@
|
||||
(function () {
|
||||
|
||||
native function sendMessageToBrowserProcess(name, array);
|
||||
|
||||
this.atom = {
|
||||
sendMessageToBrowserProcess: sendMessageToBrowserProcess
|
||||
};
|
||||
|
||||
})();
|
@ -7,9 +7,14 @@
|
||||
|
||||
namespace v8_extensions {
|
||||
Atom::Atom() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/atom.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
CefRegisterExtension("v8/atom", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
void Atom::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction("sendMessageToBrowserProcess", this);
|
||||
CefRefPtr<CefV8Value> atomObject = CefV8Value::CreateObject(NULL);
|
||||
atomObject->SetValue("sendMessageToBrowserProcess", function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("atom", atomObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
bool Atom::Execute(const CefString& name,
|
||||
|
@ -2,19 +2,21 @@
|
||||
#include "include/cef_v8.h"
|
||||
|
||||
namespace v8_extensions {
|
||||
class Git : public CefV8Handler {
|
||||
public:
|
||||
Git();
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
class Git : public CefV8Handler {
|
||||
public:
|
||||
Git();
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Git);
|
||||
};
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Git);
|
||||
|
||||
private:
|
||||
Git(Git const&);
|
||||
void operator=(Git const&);
|
||||
};
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
var $git = {};
|
||||
(function() {
|
||||
|
||||
native function getRepository(pathInRepo);
|
||||
native function getHead();
|
||||
native function getPath();
|
||||
native function getStatus(path);
|
||||
native function isIgnored(path);
|
||||
native function checkoutHead(path);
|
||||
native function getDiffStats(path);
|
||||
native function isSubmodule(path);
|
||||
native function refreshIndex();
|
||||
native function destroy();
|
||||
|
||||
function GitRepository(path) {
|
||||
var repo = getRepository(path);
|
||||
if (!repo)
|
||||
throw new Error("No Git repository found searching path: " + path);
|
||||
|
||||
repo.constructor = GitRepository;
|
||||
repo.__proto__ = GitRepository.prototype;
|
||||
return repo;
|
||||
}
|
||||
|
||||
GitRepository.prototype.getHead = getHead;
|
||||
GitRepository.prototype.getPath = getPath;
|
||||
GitRepository.prototype.getStatus = getStatus;
|
||||
GitRepository.prototype.isIgnored = isIgnored;
|
||||
GitRepository.prototype.checkoutHead = checkoutHead;
|
||||
GitRepository.prototype.getDiffStats = getDiffStats;
|
||||
GitRepository.prototype.isSubmodule = isSubmodule;
|
||||
GitRepository.prototype.refreshIndex = refreshIndex;
|
||||
GitRepository.prototype.destroy = destroy;
|
||||
this.GitRepository = GitRepository;
|
||||
})();
|
@ -4,264 +4,278 @@
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
class GitRepository : public CefBase {
|
||||
private:
|
||||
git_repository *repo;
|
||||
class GitRepository : public CefBase {
|
||||
private:
|
||||
git_repository *repo;
|
||||
|
||||
public:
|
||||
GitRepository(const char *pathInRepo) {
|
||||
if (git_repository_open_ext(&repo, pathInRepo, 0, NULL) != GIT_OK) {
|
||||
repo = NULL;
|
||||
public:
|
||||
GitRepository(const char *pathInRepo) {
|
||||
if (git_repository_open_ext(&repo, pathInRepo, 0, NULL) != GIT_OK) {
|
||||
repo = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~GitRepository() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
if (Exists()) {
|
||||
git_repository_free(repo);
|
||||
repo = NULL;
|
||||
~GitRepository() {
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Exists() {
|
||||
return repo != NULL;
|
||||
}
|
||||
void Destroy() {
|
||||
if (Exists()) {
|
||||
git_repository_free(repo);
|
||||
repo = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetPath() {
|
||||
return CefV8Value::CreateString(git_repository_path(repo));
|
||||
}
|
||||
BOOL Exists() {
|
||||
return repo != NULL;
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetHead() {
|
||||
git_reference *head;
|
||||
if (git_repository_head(&head, repo) == GIT_OK) {
|
||||
if (git_repository_head_detached(repo) == 1) {
|
||||
const git_oid* sha = git_reference_target(head);
|
||||
if (sha) {
|
||||
char oid[GIT_OID_HEXSZ + 1];
|
||||
git_oid_tostr(oid, GIT_OID_HEXSZ + 1, sha);
|
||||
git_reference_free(head);
|
||||
return CefV8Value::CreateString(oid);
|
||||
CefRefPtr<CefV8Value> GetPath() {
|
||||
return CefV8Value::CreateString(git_repository_path(repo));
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetHead() {
|
||||
git_reference *head;
|
||||
if (git_repository_head(&head, repo) == GIT_OK) {
|
||||
if (git_repository_head_detached(repo) == 1) {
|
||||
const git_oid* sha = git_reference_target(head);
|
||||
if (sha) {
|
||||
char oid[GIT_OID_HEXSZ + 1];
|
||||
git_oid_tostr(oid, GIT_OID_HEXSZ + 1, sha);
|
||||
git_reference_free(head);
|
||||
return CefV8Value::CreateString(oid);
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> result = CefV8Value::CreateString(git_reference_name(head));
|
||||
git_reference_free(head);
|
||||
return result;
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> result = CefV8Value::CreateString(git_reference_name(head));
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> IsIgnored(const char *path) {
|
||||
int ignored;
|
||||
if (git_ignore_path_is_ignored(&ignored, repo, path) == GIT_OK) {
|
||||
return CefV8Value::CreateBool(ignored == 1);
|
||||
}
|
||||
else {
|
||||
return CefV8Value::CreateBool(false);
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetStatus(const char *path) {
|
||||
unsigned int status = 0;
|
||||
if (git_status_file(&status, repo, path) == GIT_OK) {
|
||||
return CefV8Value::CreateInt(status);
|
||||
}
|
||||
else {
|
||||
return CefV8Value::CreateInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> CheckoutHead(const char *path) {
|
||||
char *copiedPath = (char *)malloc(sizeof(char) * (strlen(path) + 1));
|
||||
strcpy(copiedPath, path);
|
||||
git_checkout_opts options = GIT_CHECKOUT_OPTS_INIT;
|
||||
options.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
git_strarray paths;
|
||||
paths.count = 1;
|
||||
paths.strings = &copiedPath;
|
||||
options.paths = paths;
|
||||
|
||||
int result = git_checkout_head(repo, &options);
|
||||
free(copiedPath);
|
||||
return CefV8Value::CreateBool(result == GIT_OK);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetDiffStats(const char *path) {
|
||||
git_reference *head;
|
||||
if (git_repository_head(&head, repo) != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
const git_oid* sha = git_reference_target(head);
|
||||
git_commit *commit;
|
||||
int commitStatus = git_commit_lookup(&commit, repo, sha);
|
||||
git_reference_free(head);
|
||||
return result;
|
||||
}
|
||||
if (commitStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
git_tree *tree;
|
||||
int treeStatus = git_commit_tree(&tree, commit);
|
||||
git_commit_free(commit);
|
||||
if (treeStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> IsIgnored(const char *path) {
|
||||
int ignored;
|
||||
if (git_ignore_path_is_ignored(&ignored, repo, path) == GIT_OK) {
|
||||
return CefV8Value::CreateBool(ignored == 1);
|
||||
}
|
||||
else {
|
||||
return CefV8Value::CreateBool(false);
|
||||
}
|
||||
}
|
||||
char *copiedPath = (char *)malloc(sizeof(char) * (strlen(path) + 1));
|
||||
strcpy(copiedPath, path);
|
||||
git_diff_options options = GIT_DIFF_OPTIONS_INIT;
|
||||
git_strarray paths;
|
||||
paths.count = 1;
|
||||
paths.strings = &copiedPath;
|
||||
options.pathspec = paths;
|
||||
options.context_lines = 1;
|
||||
options.flags = GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
||||
|
||||
CefRefPtr<CefV8Value> GetStatus(const char *path) {
|
||||
unsigned int status = 0;
|
||||
if (git_status_file(&status, repo, path) == GIT_OK) {
|
||||
return CefV8Value::CreateInt(status);
|
||||
}
|
||||
else {
|
||||
return CefV8Value::CreateInt(0);
|
||||
}
|
||||
}
|
||||
git_diff_list *diffs;
|
||||
int diffStatus = git_diff_tree_to_workdir(&diffs, repo, tree, &options);
|
||||
free(copiedPath);
|
||||
if (diffStatus != GIT_OK || git_diff_num_deltas(diffs) != 1) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> CheckoutHead(const char *path) {
|
||||
char *copiedPath = (char *)malloc(sizeof(char) * (strlen(path) + 1));
|
||||
strcpy(copiedPath, path);
|
||||
git_checkout_opts options = GIT_CHECKOUT_OPTS_INIT;
|
||||
options.checkout_strategy = GIT_CHECKOUT_FORCE;
|
||||
git_strarray paths;
|
||||
paths.count = 1;
|
||||
paths.strings = &copiedPath;
|
||||
options.paths = paths;
|
||||
git_diff_patch *patch;
|
||||
int patchStatus = git_diff_get_patch(&patch, NULL, diffs, 0);
|
||||
git_diff_list_free(diffs);
|
||||
if (patchStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
int result = git_checkout_head(repo, &options);
|
||||
free(copiedPath);
|
||||
return CefV8Value::CreateBool(result == GIT_OK);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> GetDiffStats(const char *path) {
|
||||
git_reference *head;
|
||||
if (git_repository_head(&head, repo) != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
const git_oid* sha = git_reference_target(head);
|
||||
git_commit *commit;
|
||||
int commitStatus = git_commit_lookup(&commit, repo, sha);
|
||||
git_reference_free(head);
|
||||
if (commitStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
git_tree *tree;
|
||||
int treeStatus = git_commit_tree(&tree, commit);
|
||||
git_commit_free(commit);
|
||||
if (treeStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
char *copiedPath = (char *)malloc(sizeof(char) * (strlen(path) + 1));
|
||||
strcpy(copiedPath, path);
|
||||
git_diff_options options = GIT_DIFF_OPTIONS_INIT;
|
||||
git_strarray paths;
|
||||
paths.count = 1;
|
||||
paths.strings = &copiedPath;
|
||||
options.pathspec = paths;
|
||||
options.context_lines = 1;
|
||||
options.flags = GIT_DIFF_DISABLE_PATHSPEC_MATCH;
|
||||
|
||||
git_diff_list *diffs;
|
||||
int diffStatus = git_diff_tree_to_workdir(&diffs, repo, tree, &options);
|
||||
free(copiedPath);
|
||||
if (diffStatus != GIT_OK || git_diff_num_deltas(diffs) != 1) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
git_diff_patch *patch;
|
||||
int patchStatus = git_diff_get_patch(&patch, NULL, diffs, 0);
|
||||
git_diff_list_free(diffs);
|
||||
if (patchStatus != GIT_OK) {
|
||||
return CefV8Value::CreateNull();
|
||||
}
|
||||
|
||||
int added = 0;
|
||||
int deleted = 0;
|
||||
int hunks = git_diff_patch_num_hunks(patch);
|
||||
for (int i = 0; i < hunks; i++) {
|
||||
int lines = git_diff_patch_num_lines_in_hunk(patch, i);
|
||||
for (int j = 0; j < lines; j++) {
|
||||
char lineType;
|
||||
if (git_diff_patch_get_line_in_hunk(&lineType, NULL, NULL, NULL, NULL, patch, i, j) == GIT_OK) {
|
||||
switch (lineType) {
|
||||
case GIT_DIFF_LINE_ADDITION:
|
||||
added++;
|
||||
break;
|
||||
case GIT_DIFF_LINE_DELETION:
|
||||
deleted++;
|
||||
break;
|
||||
int added = 0;
|
||||
int deleted = 0;
|
||||
int hunks = git_diff_patch_num_hunks(patch);
|
||||
for (int i = 0; i < hunks; i++) {
|
||||
int lines = git_diff_patch_num_lines_in_hunk(patch, i);
|
||||
for (int j = 0; j < lines; j++) {
|
||||
char lineType;
|
||||
if (git_diff_patch_get_line_in_hunk(&lineType, NULL, NULL, NULL, NULL, patch, i, j) == GIT_OK) {
|
||||
switch (lineType) {
|
||||
case GIT_DIFF_LINE_ADDITION:
|
||||
added++;
|
||||
break;
|
||||
case GIT_DIFF_LINE_DELETION:
|
||||
deleted++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
git_diff_patch_free(patch);
|
||||
git_diff_patch_free(patch);
|
||||
|
||||
CefRefPtr<CefV8Value> result = CefV8Value::CreateObject(NULL);
|
||||
result->SetValue("added", CefV8Value::CreateInt(added), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
result->SetValue("deleted", CefV8Value::CreateInt(deleted), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
return result;
|
||||
CefRefPtr<CefV8Value> result = CefV8Value::CreateObject(NULL);
|
||||
result->SetValue("added", CefV8Value::CreateInt(added), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
result->SetValue("deleted", CefV8Value::CreateInt(deleted), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
return result;
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> IsSubmodule(const char *path) {
|
||||
BOOL isSubmodule = false;
|
||||
git_index* index;
|
||||
if (git_repository_index(&index, repo) == GIT_OK) {
|
||||
const git_index_entry *entry = git_index_get_bypath(index, path, 0);
|
||||
isSubmodule = entry != NULL && (entry->mode & S_IFMT) == GIT_FILEMODE_COMMIT;
|
||||
git_index_free(index);
|
||||
}
|
||||
return CefV8Value::CreateBool(isSubmodule);
|
||||
}
|
||||
|
||||
void RefreshIndex() {
|
||||
git_index* index;
|
||||
if (git_repository_index(&index, repo) == GIT_OK) {
|
||||
git_index_read(index);
|
||||
git_index_free(index);
|
||||
}
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(GitRepository);
|
||||
};
|
||||
|
||||
Git::Git() : CefV8Handler() {
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> IsSubmodule(const char *path) {
|
||||
BOOL isSubmodule = false;
|
||||
git_index* index;
|
||||
if (git_repository_index(&index, repo) == GIT_OK) {
|
||||
const git_index_entry *entry = git_index_get_bypath(index, path, 0);
|
||||
isSubmodule = entry != NULL && (entry->mode & S_IFMT) == GIT_FILEMODE_COMMIT;
|
||||
git_index_free(index);
|
||||
void Git::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
const char* methodNames[] = {
|
||||
"getRepository", "getHead", "getPath", "isIgnored", "getStatus", "checkoutHead",
|
||||
"getDiffStats", "isSubmodule", "refreshIndex", "destroy"
|
||||
};
|
||||
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
int arrayLength = sizeof(methodNames) / sizeof(const char *);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = methodNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
return CefV8Value::CreateBool(isSubmodule);
|
||||
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("$git", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
void RefreshIndex() {
|
||||
git_index* index;
|
||||
if (git_repository_index(&index, repo) == GIT_OK) {
|
||||
git_index_read(index);
|
||||
git_index_free(index);
|
||||
bool Git::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
if (name == "getRepository") {
|
||||
GitRepository *repository = new GitRepository(arguments[0]->GetStringValue().ToString().c_str());
|
||||
if (repository->Exists()) {
|
||||
CefRefPtr<CefBase> userData = repository;
|
||||
retval = CefV8Value::CreateObject(NULL);
|
||||
retval->SetUserData(userData);
|
||||
} else {
|
||||
retval = CefV8Value::CreateNull();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getHead") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetHead();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getPath") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetPath();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "isIgnored") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->IsIgnored(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getStatus") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetStatus(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "checkoutHead") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->CheckoutHead(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getDiffStats") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetDiffStats(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "isSubmodule") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->IsSubmodule(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "refreshIndex") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
userData->RefreshIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "destroy") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
userData->Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IMPLEMENT_REFCOUNTING(GitRepository);
|
||||
};
|
||||
|
||||
Git::Git() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/git.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
CefRegisterExtension("v8/git", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
bool Git::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
if (name == "getRepository") {
|
||||
GitRepository *repository = new GitRepository(arguments[0]->GetStringValue().ToString().c_str());
|
||||
if (repository->Exists()) {
|
||||
CefRefPtr<CefBase> userData = repository;
|
||||
retval = CefV8Value::CreateObject(NULL);
|
||||
retval->SetUserData(userData);
|
||||
} else {
|
||||
retval = CefV8Value::CreateNull();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getHead") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetHead();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getPath") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetPath();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "isIgnored") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->IsIgnored(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getStatus") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetStatus(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "checkoutHead") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->CheckoutHead(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "getDiffStats") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->GetDiffStats(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "isSubmodule") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
retval = userData->IsSubmodule(arguments[0]->GetStringValue().ToString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "refreshIndex") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
userData->RefreshIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name == "destroy") {
|
||||
GitRepository *userData = (GitRepository *)object->GetUserData().get();
|
||||
userData->Destroy();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,23 @@
|
||||
#include "include/cef_base.h"
|
||||
#include "include/cef_v8.h"
|
||||
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
class Native : public CefV8Handler {
|
||||
public:
|
||||
Native();
|
||||
class Native : public CefV8Handler {
|
||||
public:
|
||||
Native();
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Native);
|
||||
|
||||
private:
|
||||
std::string windowState;
|
||||
};
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Native);
|
||||
|
||||
private:
|
||||
Native(Native const&);
|
||||
void operator=(Native const&);
|
||||
};
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
var $native = {};
|
||||
(function() {
|
||||
|
||||
native function exists(path);
|
||||
$native.exists = exists;
|
||||
|
||||
native function read(path);
|
||||
$native.read = read;
|
||||
|
||||
native function write(path, content);
|
||||
$native.write = write;
|
||||
|
||||
native function absolute(path);
|
||||
$native.absolute = absolute;
|
||||
|
||||
native function traverseTree(path, onFile, onDirectory);
|
||||
$native.traverseTree = traverseTree;
|
||||
|
||||
native function getAllFilePathsAsync(path, callback);
|
||||
$native.getAllFilePathsAsync = getAllFilePathsAsync;
|
||||
|
||||
native function isFile(path);
|
||||
$native.isFile = isFile;
|
||||
|
||||
native function isDirectory(path);
|
||||
$native.isDirectory = isDirectory;
|
||||
|
||||
native function remove(path);
|
||||
$native.remove = remove;
|
||||
|
||||
native function open(path);
|
||||
$native.open = open;
|
||||
|
||||
native function quit();
|
||||
$native.quit = quit;
|
||||
|
||||
native function writeToPasteboard(text);
|
||||
$native.writeToPasteboard = writeToPasteboard;
|
||||
|
||||
native function readFromPasteboard();
|
||||
$native.readFromPasteboard = readFromPasteboard;
|
||||
|
||||
native function watchPath(path);
|
||||
$native.watchPath = watchPath;
|
||||
|
||||
native function unwatchPath(path, callbackId);
|
||||
$native.unwatchPath = unwatchPath;
|
||||
|
||||
native function getWatchedPaths();
|
||||
$native.getWatchedPaths = getWatchedPaths;
|
||||
|
||||
native function unwatchAllPaths();
|
||||
$native.unwatchAllPaths = unwatchAllPaths;
|
||||
|
||||
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;
|
||||
|
||||
native function setWindowState(state);
|
||||
$native.setWindowState = setWindowState;
|
||||
|
||||
native function getWindowState();
|
||||
$native.getWindowState = getWindowState;
|
||||
|
||||
})();
|
@ -8,496 +8,522 @@
|
||||
#import "path_watcher.h"
|
||||
|
||||
#import <iostream>
|
||||
|
||||
#include <fts.h>
|
||||
|
||||
static std::string windowState = "{}";
|
||||
static NSLock *windowStateLock = [[NSLock alloc] init];
|
||||
|
||||
namespace v8_extensions {
|
||||
using namespace std;
|
||||
|
||||
NSString *stringFromCefV8Value(const CefRefPtr<CefV8Value>& value) {
|
||||
std::string cc_value = value->GetStringValue().ToString();
|
||||
return [NSString stringWithUTF8String:cc_value.c_str()];
|
||||
}
|
||||
NSString *stringFromCefV8Value(const CefRefPtr<CefV8Value>& value);
|
||||
void throwException(const CefRefPtr<CefV8Value>& global, CefRefPtr<CefV8Exception> exception, NSString *message);
|
||||
|
||||
void throwException(const CefRefPtr<CefV8Value>& global, CefRefPtr<CefV8Exception> exception, NSString *message) {
|
||||
CefV8ValueList arguments;
|
||||
|
||||
message = [message stringByAppendingFormat:@"\n%s", exception->GetMessage().ToString().c_str()];
|
||||
arguments.push_back(CefV8Value::CreateString(std::string([message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
|
||||
CefRefPtr<CefV8Value> console = global->GetValue("console");
|
||||
console->GetValue("error")->ExecuteFunction(console, arguments);
|
||||
}
|
||||
|
||||
Native::Native() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/native.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
windowState = "{}";
|
||||
CefRegisterExtension("v8/native", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
bool Native::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
if (name == "exists") {
|
||||
std::string cc_value = arguments[0]->GetStringValue().ToString();
|
||||
const char *path = cc_value.c_str();
|
||||
retval = CefV8Value::CreateBool(access(path, F_OK) == 0);
|
||||
|
||||
return true;
|
||||
Native::Native() : CefV8Handler() {
|
||||
}
|
||||
else if (name == "read") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
NSStringEncoding *encoding = nil;
|
||||
NSString *contents = [NSString stringWithContentsOfFile:path usedEncoding:encoding error:&error];
|
||||
void Native::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
const char* methodNames[] = {
|
||||
"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"
|
||||
};
|
||||
|
||||
NSError *binaryFileError = nil;
|
||||
if (error) {
|
||||
contents = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:&binaryFileError];
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
int arrayLength = sizeof(methodNames) / sizeof(const char *);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = methodNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
if (binaryFileError) {
|
||||
exception = [[binaryFileError localizedDescription] UTF8String];
|
||||
}
|
||||
else {
|
||||
retval = CefV8Value::CreateString([contents UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("$native", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
else if (name == "write") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *content = stringFromCefV8Value(arguments[1]);
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
bool Native::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
if (name == "exists") {
|
||||
std::string cc_value = arguments[0]->GetStringValue().ToString();
|
||||
const char *path = cc_value.c_str();
|
||||
retval = CefV8Value::CreateBool(access(path, F_OK) == 0);
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
BOOL exists = [fm fileExistsAtPath:[path stringByDeletingLastPathComponent] isDirectory:nil];
|
||||
if (!exists) {
|
||||
[fm createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
return true;
|
||||
}
|
||||
else if (name == "read") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL success = [content writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
|
||||
NSError *error = nil;
|
||||
NSStringEncoding *encoding = nil;
|
||||
NSString *contents = [NSString stringWithContentsOfFile:path usedEncoding:encoding error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
NSError *binaryFileError = nil;
|
||||
if (error) {
|
||||
contents = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:&binaryFileError];
|
||||
}
|
||||
|
||||
if (binaryFileError) {
|
||||
exception = [[binaryFileError localizedDescription] UTF8String];
|
||||
}
|
||||
else {
|
||||
retval = CefV8Value::CreateString([contents UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (!success) {
|
||||
std::string exception = "Cannot write to '";
|
||||
exception += [path UTF8String];
|
||||
exception += "'";
|
||||
else if (name == "write") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *content = stringFromCefV8Value(arguments[1]);
|
||||
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
BOOL exists = [fm fileExistsAtPath:[path stringByDeletingLastPathComponent] isDirectory:nil];
|
||||
if (!exists) {
|
||||
[fm createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
|
||||
}
|
||||
|
||||
NSError *error = nil;
|
||||
BOOL success = [content writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
else if (!success) {
|
||||
std::string exception = "Cannot write to '";
|
||||
exception += [path UTF8String];
|
||||
exception += "'";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "absolute") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "absolute") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
path = [path stringByStandardizingPath];
|
||||
if ([path characterAtIndex:0] == '/') {
|
||||
retval = CefV8Value::CreateString([path UTF8String]);
|
||||
}
|
||||
|
||||
path = [path stringByStandardizingPath];
|
||||
if ([path characterAtIndex:0] == '/') {
|
||||
retval = CefV8Value::CreateString([path UTF8String]);
|
||||
return true;
|
||||
}
|
||||
else if (name == "getAllFilePathsAsync") {
|
||||
std::string argument = arguments[0]->GetStringValue().ToString();
|
||||
CefRefPtr<CefV8Value> callback = arguments[1];
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "getAllFilePathsAsync") {
|
||||
std::string argument = arguments[0]->GetStringValue().ToString();
|
||||
CefRefPtr<CefV8Value> callback = arguments[1];
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(queue, ^{
|
||||
int rootPathLength = argument.size() + 1;
|
||||
char rootPath[rootPathLength];
|
||||
strcpy(rootPath, argument.c_str());
|
||||
char * const treePaths[] = {rootPath, NULL};
|
||||
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(queue, ^{
|
||||
FTS *tree = fts_open(treePaths, FTS_COMFOLLOW | FTS_PHYSICAL| FTS_NOCHDIR | FTS_NOSTAT, NULL);
|
||||
std::vector<std::string> paths;
|
||||
|
||||
if (tree != NULL) {
|
||||
FTSENT *entry;
|
||||
int arrayIndex = 0;
|
||||
while ((entry = fts_read(tree)) != NULL) {
|
||||
if (entry->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isFile = entry->fts_info == FTS_NSOK;
|
||||
if (!isFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pathLength = entry->fts_pathlen - rootPathLength;
|
||||
char relative[pathLength + 1];
|
||||
relative[pathLength] = '\0';
|
||||
strncpy(relative, entry->fts_path + rootPathLength, pathLength);
|
||||
paths.push_back(relative);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
||||
dispatch_async(mainQueue, ^{
|
||||
context->Enter();
|
||||
CefRefPtr<CefV8Value> v8Paths = CefV8Value::CreateArray(paths.size());
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
v8Paths->SetValue(i, CefV8Value::CreateString(paths[i]));
|
||||
}
|
||||
CefV8ValueList callbackArgs;
|
||||
callbackArgs.push_back(v8Paths);
|
||||
callback->ExecuteFunction(callback, callbackArgs);
|
||||
context->Exit();
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
else if (name == "traverseTree") {
|
||||
std::string argument = arguments[0]->GetStringValue().ToString();
|
||||
int rootPathLength = argument.size() + 1;
|
||||
char rootPath[rootPathLength];
|
||||
strcpy(rootPath, argument.c_str());
|
||||
char * const treePaths[] = {rootPath, NULL};
|
||||
char * const paths[] = {rootPath, NULL};
|
||||
|
||||
FTS *tree = fts_open(treePaths, FTS_COMFOLLOW | FTS_PHYSICAL| FTS_NOCHDIR | FTS_NOSTAT, NULL);
|
||||
std::vector<std::string> paths;
|
||||
FTS *tree = fts_open(paths, FTS_COMFOLLOW | FTS_PHYSICAL| FTS_NOCHDIR | FTS_NOSTAT, NULL);
|
||||
if (tree == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tree != NULL) {
|
||||
FTSENT *entry;
|
||||
int arrayIndex = 0;
|
||||
while ((entry = fts_read(tree)) != NULL) {
|
||||
if (entry->fts_level == 0) {
|
||||
continue;
|
||||
CefRefPtr<CefV8Value> onFile = arguments[1];
|
||||
CefRefPtr<CefV8Value> onDir = arguments[2];
|
||||
CefV8ValueList args;
|
||||
FTSENT *entry;
|
||||
while ((entry = fts_read(tree)) != NULL) {
|
||||
if (entry->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isFile = entry->fts_info == FTS_NSOK;
|
||||
bool isDir = entry->fts_info == FTS_D;
|
||||
if (!isFile && !isDir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pathLength = entry->fts_pathlen - rootPathLength;
|
||||
char relative[pathLength + 1];
|
||||
relative[pathLength] = '\0';
|
||||
strncpy(relative, entry->fts_path + rootPathLength, pathLength);
|
||||
args.clear();
|
||||
args.push_back(CefV8Value::CreateString(relative));
|
||||
if (isFile) {
|
||||
onFile->ExecuteFunction(onFile, args);
|
||||
}
|
||||
else {
|
||||
CefRefPtr<CefV8Value> enterDir = onDir->ExecuteFunction(onDir, args);
|
||||
if(enterDir != NULL && !enterDir->GetBoolValue()) {
|
||||
fts_set(tree, entry, FTS_SKIP);
|
||||
}
|
||||
|
||||
bool isFile = entry->fts_info == FTS_NSOK;
|
||||
if (!isFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pathLength = entry->fts_pathlen - rootPathLength;
|
||||
char relative[pathLength + 1];
|
||||
relative[pathLength] = '\0';
|
||||
strncpy(relative, entry->fts_path + rootPathLength, pathLength);
|
||||
paths.push_back(relative);
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
||||
dispatch_async(mainQueue, ^{
|
||||
context->Enter();
|
||||
CefRefPtr<CefV8Value> v8Paths = CefV8Value::CreateArray(paths.size());
|
||||
for (int i = 0; i < paths.size(); i++) {
|
||||
v8Paths->SetValue(i, CefV8Value::CreateString(paths[i]));
|
||||
}
|
||||
CefV8ValueList callbackArgs;
|
||||
callbackArgs.push_back(v8Paths);
|
||||
callback->ExecuteFunction(callback, callbackArgs);
|
||||
context->Exit();
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
else if (name == "traverseTree") {
|
||||
std::string argument = arguments[0]->GetStringValue().ToString();
|
||||
int rootPathLength = argument.size() + 1;
|
||||
char rootPath[rootPathLength];
|
||||
strcpy(rootPath, argument.c_str());
|
||||
char * const paths[] = {rootPath, NULL};
|
||||
return true;
|
||||
}
|
||||
else if (name == "isDirectory") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
FTS *tree = fts_open(paths, FTS_COMFOLLOW | FTS_PHYSICAL| FTS_NOCHDIR | FTS_NOSTAT, NULL);
|
||||
if (tree == NULL) {
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
retval = CefV8Value::CreateBool(exists && isDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "isFile") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
retval = CefV8Value::CreateBool(exists && !isDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "remove") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "writeToPasteboard") {
|
||||
NSString *text = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||
[pb declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
|
||||
[pb setString:text forType:NSStringPboardType];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "readFromPasteboard") {
|
||||
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||
NSArray *results = [pb readObjectsForClasses:[NSArray arrayWithObjects:[NSString class], nil] options:nil];
|
||||
if (results) {
|
||||
retval = CefV8Value::CreateString([[results objectAtIndex:0] UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "quit") {
|
||||
[NSApp terminate:nil];
|
||||
return true;
|
||||
}
|
||||
else if (name == "watchPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
CefRefPtr<CefV8Value> function = arguments[1];
|
||||
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
|
||||
WatchCallback callback = ^(NSString *eventType, NSString *path) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
|
||||
args.push_back(CefV8Value::CreateString(std::string([eventType UTF8String], [eventType lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
args.push_back(CefV8Value::CreateString(std::string([path UTF8String], [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
function->ExecuteFunction(function, args);
|
||||
|
||||
context->Exit();
|
||||
};
|
||||
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
NSString *watchId = [pathWatcher watchPath:path callback:[[callback copy] autorelease]];
|
||||
if (watchId) {
|
||||
retval = CefV8Value::CreateString([watchId UTF8String]);
|
||||
}
|
||||
else {
|
||||
exception = std::string("Failed to watch path '") + std::string([path UTF8String]) + std::string("' (it may not exist)");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "unwatchPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *callbackId = stringFromCefV8Value(arguments[1]);
|
||||
NSError *error = nil;
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
[pathWatcher unwatchPath:path callbackId:callbackId error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "getWatchedPaths") {
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
NSArray *paths = [pathWatcher watchedPaths];
|
||||
|
||||
CefRefPtr<CefV8Value> pathsArray = CefV8Value::CreateArray([paths count]);
|
||||
|
||||
for (int i = 0; i < [paths count]; i++) {
|
||||
CefRefPtr<CefV8Value> path = CefV8Value::CreateString([[paths objectAtIndex:i] UTF8String]);
|
||||
pathsArray->SetValue(i, path);
|
||||
}
|
||||
retval = pathsArray;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "unwatchAllPaths") {
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
[pathWatcher unwatchAllPaths];
|
||||
return true;
|
||||
}
|
||||
else if (name == "makeDirectory") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSError *error = nil;
|
||||
[fm createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "move") {
|
||||
NSString *sourcePath = stringFromCefV8Value(arguments[0]);
|
||||
NSString *targetPath = stringFromCefV8Value(arguments[1]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
[fm moveItemAtPath:sourcePath toPath:targetPath error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "moveToTrash") {
|
||||
NSString *sourcePath = stringFromCefV8Value(arguments[0]);
|
||||
bool success = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
||||
source:[sourcePath stringByDeletingLastPathComponent]
|
||||
destination:@""
|
||||
files:[NSArray arrayWithObject:[sourcePath lastPathComponent]]
|
||||
tag:nil];
|
||||
|
||||
if (!success) {
|
||||
std::string exception = "Can not move ";
|
||||
exception += [sourcePath UTF8String];
|
||||
exception += " to trash.";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "reload") {
|
||||
CefV8Context::GetCurrentContext()->GetBrowser()->ReloadIgnoreCache();
|
||||
}
|
||||
else if (name == "lastModified") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
NSDictionary *attributes = [fm attributesOfItemAtPath:path error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
NSDate *lastModified = [attributes objectForKey:NSFileModificationDate];
|
||||
retval = CefV8Value::CreateDate(CefTime([lastModified timeIntervalSince1970]));
|
||||
return true;
|
||||
}
|
||||
else if (name == "md5ForPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
unsigned char outputData[CC_MD5_DIGEST_LENGTH];
|
||||
|
||||
NSData *inputData = [[NSData alloc] initWithContentsOfFile:path];
|
||||
CC_MD5([inputData bytes], [inputData length], outputData);
|
||||
[inputData release];
|
||||
|
||||
NSMutableString *hash = [[NSMutableString alloc] init];
|
||||
|
||||
for (NSUInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", outputData[i]];
|
||||
}
|
||||
|
||||
retval = CefV8Value::CreateString([hash UTF8String]);
|
||||
return true;
|
||||
}
|
||||
else if (name == "exec") {
|
||||
NSString *command = stringFromCefV8Value(arguments[0]);
|
||||
CefRefPtr<CefV8Value> options = arguments[1];
|
||||
CefRefPtr<CefV8Value> callback = arguments[2];
|
||||
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/bin/sh"];
|
||||
[task setStandardInput:[NSFileHandle fileHandleWithNullDevice]];
|
||||
[task setArguments:[NSArray arrayWithObjects:@"-l", @"-c", command, nil]];
|
||||
|
||||
NSPipe *stdout = [NSPipe pipe];
|
||||
NSPipe *stderr = [NSPipe pipe];
|
||||
[task setStandardOutput:stdout];
|
||||
[task setStandardError:stderr];
|
||||
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
void (^outputHandle)(NSString *contents, CefRefPtr<CefV8Value> function) = nil;
|
||||
void (^taskTerminatedHandle)(NSString *output, NSString *errorOutput) = nil;
|
||||
|
||||
outputHandle = ^(NSString *contents, CefRefPtr<CefV8Value> function) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
args.push_back(CefV8Value::CreateString(std::string([contents UTF8String], [contents lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
CefRefPtr<CefV8Value> retval = function->ExecuteFunction(function, args);
|
||||
|
||||
if (function->HasException()) {
|
||||
throwException(context->GetGlobal(), function->GetException(), @"Error thrown in OutputHandle");
|
||||
}
|
||||
|
||||
context->Exit();
|
||||
};
|
||||
|
||||
taskTerminatedHandle = ^(NSString *output, NSString *errorOutput) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
args.push_back(CefV8Value::CreateInt([task terminationStatus]));
|
||||
args.push_back(CefV8Value::CreateString([output UTF8String]));
|
||||
args.push_back(CefV8Value::CreateString([errorOutput UTF8String]));
|
||||
|
||||
callback->ExecuteFunction(callback, args);
|
||||
|
||||
if (callback->HasException()) {
|
||||
throwException(context->GetGlobal(), callback->GetException(), @"Error thrown in TaskTerminatedHandle");
|
||||
}
|
||||
|
||||
context->Exit();
|
||||
|
||||
stdout.fileHandleForReading.writeabilityHandler = nil;
|
||||
stderr.fileHandleForReading.writeabilityHandler = 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];
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
}
|
||||
|
||||
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];
|
||||
};
|
||||
}
|
||||
|
||||
[task launch];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "getPlatform") {
|
||||
retval = CefV8Value::CreateString("mac");
|
||||
return true;
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> onFile = arguments[1];
|
||||
CefRefPtr<CefV8Value> onDir = arguments[2];
|
||||
CefV8ValueList args;
|
||||
FTSENT *entry;
|
||||
while ((entry = fts_read(tree)) != NULL) {
|
||||
if (entry->fts_level == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool isFile = entry->fts_info == FTS_NSOK;
|
||||
bool isDir = entry->fts_info == FTS_D;
|
||||
if (!isFile && !isDir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int pathLength = entry->fts_pathlen - rootPathLength;
|
||||
char relative[pathLength + 1];
|
||||
relative[pathLength] = '\0';
|
||||
strncpy(relative, entry->fts_path + rootPathLength, pathLength);
|
||||
args.clear();
|
||||
args.push_back(CefV8Value::CreateString(relative));
|
||||
if (isFile) {
|
||||
onFile->ExecuteFunction(onFile, args);
|
||||
}
|
||||
else {
|
||||
CefRefPtr<CefV8Value> enterDir = onDir->ExecuteFunction(onDir, args);
|
||||
if(enterDir != NULL && !enterDir->GetBoolValue()) {
|
||||
fts_set(tree, entry, FTS_SKIP);
|
||||
}
|
||||
}
|
||||
else if (name == "setWindowState") {
|
||||
[windowStateLock lock];
|
||||
windowState = arguments[0]->GetStringValue().ToString();
|
||||
[windowStateLock unlock];
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "isDirectory") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
retval = CefV8Value::CreateBool(exists && isDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "isFile") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
BOOL isDir = false;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
|
||||
retval = CefV8Value::CreateBool(exists && !isDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "remove") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] removeItemAtPath:path error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
else if (name == "getWindowState") {
|
||||
[windowStateLock lock];
|
||||
retval = CefV8Value::CreateString(windowState);
|
||||
[windowStateLock unlock];
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "writeToPasteboard") {
|
||||
NSString *text = stringFromCefV8Value(arguments[0]);
|
||||
return false;
|
||||
};
|
||||
|
||||
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||
[pb declareTypes:[NSArray arrayWithObjects:NSStringPboardType, nil] owner:nil];
|
||||
[pb setString:text forType:NSStringPboardType];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "readFromPasteboard") {
|
||||
NSPasteboard *pb = [NSPasteboard generalPasteboard];
|
||||
NSArray *results = [pb readObjectsForClasses:[NSArray arrayWithObjects:[NSString class], nil] options:nil];
|
||||
if (results) {
|
||||
retval = CefV8Value::CreateString([[results objectAtIndex:0] UTF8String]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "quit") {
|
||||
[NSApp terminate:nil];
|
||||
return true;
|
||||
}
|
||||
else if (name == "watchPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
CefRefPtr<CefV8Value> function = arguments[1];
|
||||
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
|
||||
WatchCallback callback = ^(NSString *eventType, NSString *path) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
|
||||
args.push_back(CefV8Value::CreateString(std::string([eventType UTF8String], [eventType lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
args.push_back(CefV8Value::CreateString(std::string([path UTF8String], [path lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
function->ExecuteFunction(function, args);
|
||||
|
||||
context->Exit();
|
||||
};
|
||||
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
NSString *watchId = [pathWatcher watchPath:path callback:[[callback copy] autorelease]];
|
||||
if (watchId) {
|
||||
retval = CefV8Value::CreateString([watchId UTF8String]);
|
||||
}
|
||||
else {
|
||||
exception = std::string("Failed to watch path '") + std::string([path UTF8String]) + std::string("' (it may not exist)");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "unwatchPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSString *callbackId = stringFromCefV8Value(arguments[1]);
|
||||
NSError *error = nil;
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
[pathWatcher unwatchPath:path callbackId:callbackId error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "getWatchedPaths") {
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
NSArray *paths = [pathWatcher watchedPaths];
|
||||
|
||||
CefRefPtr<CefV8Value> pathsArray = CefV8Value::CreateArray([paths count]);
|
||||
|
||||
for (int i = 0; i < [paths count]; i++) {
|
||||
CefRefPtr<CefV8Value> path = CefV8Value::CreateString([[paths objectAtIndex:i] UTF8String]);
|
||||
pathsArray->SetValue(i, path);
|
||||
}
|
||||
retval = pathsArray;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "unwatchAllPaths") {
|
||||
PathWatcher *pathWatcher = [PathWatcher pathWatcherForContext:CefV8Context::GetCurrentContext()];
|
||||
[pathWatcher unwatchAllPaths];
|
||||
return true;
|
||||
}
|
||||
else if (name == "makeDirectory") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
NSError *error = nil;
|
||||
[fm createDirectoryAtPath:path withIntermediateDirectories:NO attributes:nil error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "move") {
|
||||
NSString *sourcePath = stringFromCefV8Value(arguments[0]);
|
||||
NSString *targetPath = stringFromCefV8Value(arguments[1]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
[fm moveItemAtPath:sourcePath toPath:targetPath error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "moveToTrash") {
|
||||
NSString *sourcePath = stringFromCefV8Value(arguments[0]);
|
||||
bool success = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
|
||||
source:[sourcePath stringByDeletingLastPathComponent]
|
||||
destination:@""
|
||||
files:[NSArray arrayWithObject:[sourcePath lastPathComponent]]
|
||||
tag:nil];
|
||||
|
||||
if (!success) {
|
||||
std::string exception = "Can not move ";
|
||||
exception += [sourcePath UTF8String];
|
||||
exception += " to trash.";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "reload") {
|
||||
CefV8Context::GetCurrentContext()->GetBrowser()->ReloadIgnoreCache();
|
||||
}
|
||||
else if (name == "lastModified") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
NSFileManager *fm = [NSFileManager defaultManager];
|
||||
|
||||
NSError *error = nil;
|
||||
NSDictionary *attributes = [fm attributesOfItemAtPath:path error:&error];
|
||||
|
||||
if (error) {
|
||||
exception = [[error localizedDescription] UTF8String];
|
||||
}
|
||||
|
||||
NSDate *lastModified = [attributes objectForKey:NSFileModificationDate];
|
||||
retval = CefV8Value::CreateDate(CefTime([lastModified timeIntervalSince1970]));
|
||||
return true;
|
||||
}
|
||||
else if (name == "md5ForPath") {
|
||||
NSString *path = stringFromCefV8Value(arguments[0]);
|
||||
unsigned char outputData[CC_MD5_DIGEST_LENGTH];
|
||||
|
||||
NSData *inputData = [[NSData alloc] initWithContentsOfFile:path];
|
||||
CC_MD5([inputData bytes], [inputData length], outputData);
|
||||
[inputData release];
|
||||
|
||||
NSMutableString *hash = [[NSMutableString alloc] init];
|
||||
|
||||
for (NSUInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
|
||||
[hash appendFormat:@"%02x", outputData[i]];
|
||||
}
|
||||
|
||||
retval = CefV8Value::CreateString([hash UTF8String]);
|
||||
return true;
|
||||
}
|
||||
else if (name == "exec") {
|
||||
NSString *command = stringFromCefV8Value(arguments[0]);
|
||||
CefRefPtr<CefV8Value> options = arguments[1];
|
||||
CefRefPtr<CefV8Value> callback = arguments[2];
|
||||
|
||||
NSTask *task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/bin/sh"];
|
||||
[task setStandardInput:[NSFileHandle fileHandleWithNullDevice]];
|
||||
[task setArguments:[NSArray arrayWithObjects:@"-l", @"-c", command, nil]];
|
||||
|
||||
NSPipe *stdout = [NSPipe pipe];
|
||||
NSPipe *stderr = [NSPipe pipe];
|
||||
[task setStandardOutput:stdout];
|
||||
[task setStandardError:stderr];
|
||||
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
void (^outputHandle)(NSString *contents, CefRefPtr<CefV8Value> function) = nil;
|
||||
void (^taskTerminatedHandle)(NSString *output, NSString *errorOutput) = nil;
|
||||
|
||||
outputHandle = ^(NSString *contents, CefRefPtr<CefV8Value> function) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
args.push_back(CefV8Value::CreateString(std::string([contents UTF8String], [contents lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
CefRefPtr<CefV8Value> retval = function->ExecuteFunction(function, args);
|
||||
|
||||
if (function->HasException()) {
|
||||
throwException(context->GetGlobal(), function->GetException(), @"Error thrown in OutputHandle");
|
||||
}
|
||||
|
||||
context->Exit();
|
||||
};
|
||||
|
||||
taskTerminatedHandle = ^(NSString *output, NSString *errorOutput) {
|
||||
context->Enter();
|
||||
|
||||
CefV8ValueList args;
|
||||
args.push_back(CefV8Value::CreateInt([task terminationStatus]));
|
||||
args.push_back(CefV8Value::CreateString([output UTF8String]));
|
||||
args.push_back(CefV8Value::CreateString([errorOutput UTF8String]));
|
||||
|
||||
callback->ExecuteFunction(callback, args);
|
||||
|
||||
if (callback->HasException()) {
|
||||
throwException(context->GetGlobal(), callback->GetException(), @"Error thrown in TaskTerminatedHandle");
|
||||
}
|
||||
|
||||
context->Exit();
|
||||
|
||||
stdout.fileHandleForReading.writeabilityHandler = nil;
|
||||
stderr.fileHandleForReading.writeabilityHandler = 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];
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
}
|
||||
|
||||
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];
|
||||
};
|
||||
}
|
||||
|
||||
[task launch];
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (name == "getPlatform") {
|
||||
retval = CefV8Value::CreateString("mac");
|
||||
return true;
|
||||
NSString *stringFromCefV8Value(const CefRefPtr<CefV8Value>& value) {
|
||||
std::string cc_value = value->GetStringValue().ToString();
|
||||
return [NSString stringWithUTF8String:cc_value.c_str()];
|
||||
}
|
||||
|
||||
else if (name == "setWindowState") {
|
||||
windowState = arguments[0]->GetStringValue().ToString();
|
||||
return true;
|
||||
}
|
||||
void throwException(const CefRefPtr<CefV8Value>& global, CefRefPtr<CefV8Exception> exception, NSString *message) {
|
||||
CefV8ValueList arguments;
|
||||
|
||||
else if (name == "getWindowState") {
|
||||
retval = CefV8Value::CreateString(windowState);
|
||||
return true;
|
||||
}
|
||||
message = [message stringByAppendingFormat:@"\n%s", exception->GetMessage().ToString().c_str()];
|
||||
arguments.push_back(CefV8Value::CreateString(std::string([message UTF8String], [message lengthOfBytesUsingEncoding:NSUTF8StringEncoding])));
|
||||
|
||||
return false;
|
||||
};
|
||||
CefRefPtr<CefV8Value> console = global->GetValue("console");
|
||||
console->GetValue("error")->ExecuteFunction(console, arguments);
|
||||
}
|
||||
|
||||
} // namespace v8_extensions
|
||||
|
@ -3,18 +3,22 @@
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
class OnigRegExp : public CefV8Handler {
|
||||
public:
|
||||
OnigRegExp();
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(OnigRegExp);
|
||||
};
|
||||
class OnigRegExp : public CefV8Handler {
|
||||
public:
|
||||
OnigRegExp();
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(OnigRegExp);
|
||||
|
||||
private:
|
||||
OnigRegExp(OnigRegExp const&);
|
||||
void operator=(OnigRegExp const&);
|
||||
};
|
||||
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
(function() {
|
||||
native function buildOnigRegExp(source);
|
||||
native function search(string, index);
|
||||
native function test(string);
|
||||
|
||||
function OnigRegExp(source) {
|
||||
var regexp = buildOnigRegExp(source);
|
||||
regexp.constructor = OnigRegExp;
|
||||
regexp.__proto__ = OnigRegExp.prototype;
|
||||
regexp.source = source;
|
||||
return regexp;
|
||||
}
|
||||
|
||||
OnigRegExp.prototype.search = search;
|
||||
OnigRegExp.prototype.test = test;
|
||||
|
||||
this.OnigRegExp = OnigRegExp;
|
||||
})();
|
||||
|
@ -38,21 +38,33 @@ public:
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
|
||||
CefRefPtr<CefV8Value> Test(CefRefPtr<CefV8Value> string, CefRefPtr<CefV8Value> index) {
|
||||
OnigResult *result = [m_regex search:stringFromCefV8Value(string) start:index->GetIntValue()];
|
||||
return CefV8Value::CreateBool(result);
|
||||
}
|
||||
|
||||
|
||||
OnigRegexp *m_regex;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(OnigRegexpUserData);
|
||||
};
|
||||
|
||||
OnigRegExp::OnigRegExp() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/onig_reg_exp.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
CefRegisterExtension("v8/onig-reg-exp", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
void OnigRegExp::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
const char* methodNames[] = { "search", "test", "buildOnigRegExp" };
|
||||
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
int arrayLength = sizeof(methodNames) / sizeof(const char *);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = methodNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("$onigRegExp", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
bool OnigRegExp::Execute(const CefString& name,
|
||||
@ -73,7 +85,7 @@ bool OnigRegExp::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> index = arguments.size() > 1 ? arguments[1] : CefV8Value::CreateInt(0);
|
||||
OnigRegExpUserData *userData = (OnigRegExpUserData *)object->GetUserData().get();
|
||||
retval = userData->Test(string, index);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
else if (name == "buildOnigRegExp") {
|
||||
CefRefPtr<CefV8Value> pattern = arguments[0];
|
||||
|
@ -2,19 +2,23 @@
|
||||
#include "include/cef_v8.h"
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
|
||||
class OnigScanner : public CefV8Handler {
|
||||
public:
|
||||
OnigScanner();
|
||||
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(OnigRegExp);
|
||||
|
||||
private:
|
||||
OnigScanner(OnigScanner const&);
|
||||
void operator=(OnigScanner const&);
|
||||
};
|
||||
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
(function() {
|
||||
native function buildScanner(sources);
|
||||
native function findNextMatch(string, startPosition);
|
||||
|
||||
function OnigScanner(sources) {
|
||||
var scanner = buildScanner(sources);
|
||||
scanner.constructor = OnigScanner;
|
||||
scanner.__proto__ = OnigScanner.prototype;
|
||||
scanner.sources = sources;
|
||||
return scanner;
|
||||
}
|
||||
|
||||
OnigScanner.prototype.buildScanner = buildScanner;
|
||||
OnigScanner.prototype.findNextMatch = findNextMatch;
|
||||
|
||||
this.OnigScanner = OnigScanner;
|
||||
})();
|
@ -130,11 +130,22 @@ class OnigScannerUserData : public CefBase {
|
||||
};
|
||||
|
||||
OnigScanner::OnigScanner() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/onig_scanner.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
CefRegisterExtension("v8/onig-scanner", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
void OnigScanner::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
const char* methodNames[] = { "findNextMatch", "buildScanner" };
|
||||
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
int arrayLength = sizeof(methodNames) / sizeof(const char *);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = methodNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("$onigScanner", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
bool OnigScanner::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
|
@ -4,21 +4,23 @@
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
class Tags : public CefV8Handler {
|
||||
public:
|
||||
Tags();
|
||||
class Tags : public CefV8Handler {
|
||||
public:
|
||||
Tags();
|
||||
void CreateContextBinding(CefRefPtr<CefV8Context> context);
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
|
||||
virtual bool Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) OVERRIDE;
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Tags);
|
||||
|
||||
// Provide the reference counting implementation for this class.
|
||||
IMPLEMENT_REFCOUNTING(Tags);
|
||||
|
||||
private:
|
||||
CefRefPtr<CefV8Value> ParseEntry(tagEntry entry);
|
||||
};
|
||||
private:
|
||||
Tags(Tags const&);
|
||||
void operator=(Tags const&);
|
||||
CefRefPtr<CefV8Value> ParseEntry(tagEntry entry);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
var $tags = {};
|
||||
(function() {
|
||||
|
||||
native function find(path, tag);
|
||||
$tags.find = find;
|
||||
|
||||
native function getAllTagsAsync(path, callback);
|
||||
$tags.getAllTagsAsync = getAllTagsAsync;
|
||||
|
||||
})();
|
@ -3,100 +3,112 @@
|
||||
|
||||
namespace v8_extensions {
|
||||
|
||||
Tags::Tags() : CefV8Handler() {
|
||||
NSString *filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"v8_extensions/tags.js"];
|
||||
NSString *extensionCode = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
|
||||
CefRegisterExtension("v8/tags", [extensionCode UTF8String], this);
|
||||
}
|
||||
|
||||
CefRefPtr<CefV8Value> Tags::ParseEntry(tagEntry entry) {
|
||||
CefRefPtr<CefV8Value> tagEntry = CefV8Value::CreateObject(NULL);
|
||||
tagEntry->SetValue("name", CefV8Value::CreateString(entry.name), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
tagEntry->SetValue("file", CefV8Value::CreateString(entry.file), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
if (entry.address.pattern) {
|
||||
tagEntry->SetValue("pattern", CefV8Value::CreateString(entry.address.pattern), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
Tags::Tags() : CefV8Handler() {
|
||||
}
|
||||
return tagEntry;
|
||||
}
|
||||
|
||||
bool Tags::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
void Tags::CreateContextBinding(CefRefPtr<CefV8Context> context) {
|
||||
const char* methodNames[] = { "find", "getAllTagsAsync" };
|
||||
|
||||
if (name == "find") {
|
||||
std::string path = arguments[0]->GetStringValue().ToString();
|
||||
std::string tag = arguments[1]->GetStringValue().ToString();
|
||||
tagFileInfo info;
|
||||
tagFile* tagFile;
|
||||
tagFile = tagsOpen(path.c_str(), &info);
|
||||
if (info.status.opened) {
|
||||
tagEntry entry;
|
||||
std::vector<CefRefPtr<CefV8Value>> entries;
|
||||
if (tagsFind(tagFile, &entry, tag.c_str(), TAG_FULLMATCH | TAG_OBSERVECASE) == TagSuccess) {
|
||||
entries.push_back(ParseEntry(entry));
|
||||
while (tagsFindNext(tagFile, &entry) == TagSuccess) {
|
||||
entries.push_back(ParseEntry(entry));
|
||||
}
|
||||
}
|
||||
|
||||
retval = CefV8Value::CreateArray(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
retval->SetValue(i, entries[i]);
|
||||
}
|
||||
tagsClose(tagFile);
|
||||
CefRefPtr<CefV8Value> nativeObject = CefV8Value::CreateObject(NULL);
|
||||
int arrayLength = sizeof(methodNames) / sizeof(const char *);
|
||||
for (int i = 0; i < arrayLength; i++) {
|
||||
const char *functionName = methodNames[i];
|
||||
CefRefPtr<CefV8Value> function = CefV8Value::CreateFunction(functionName, this);
|
||||
nativeObject->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
return true;
|
||||
|
||||
CefRefPtr<CefV8Value> global = context->GetGlobal();
|
||||
global->SetValue("$tags", nativeObject, V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
|
||||
if (name == "getAllTagsAsync") {
|
||||
std::string path = arguments[0]->GetStringValue().ToString();
|
||||
CefRefPtr<CefV8Value> callback = arguments[1];
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
CefRefPtr<CefV8Value> Tags::ParseEntry(tagEntry entry) {
|
||||
CefRefPtr<CefV8Value> tagEntry = CefV8Value::CreateObject(NULL);
|
||||
tagEntry->SetValue("name", CefV8Value::CreateString(entry.name), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
tagEntry->SetValue("file", CefV8Value::CreateString(entry.file), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
if (entry.address.pattern) {
|
||||
tagEntry->SetValue("pattern", CefV8Value::CreateString(entry.address.pattern), V8_PROPERTY_ATTRIBUTE_NONE);
|
||||
}
|
||||
return tagEntry;
|
||||
}
|
||||
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(queue, ^{
|
||||
bool Tags::Execute(const CefString& name,
|
||||
CefRefPtr<CefV8Value> object,
|
||||
const CefV8ValueList& arguments,
|
||||
CefRefPtr<CefV8Value>& retval,
|
||||
CefString& exception) {
|
||||
|
||||
if (name == "find") {
|
||||
std::string path = arguments[0]->GetStringValue().ToString();
|
||||
std::string tag = arguments[1]->GetStringValue().ToString();
|
||||
tagFileInfo info;
|
||||
tagFile* tagFile;
|
||||
tagFile = tagsOpen(path.c_str(), &info);
|
||||
std::vector<tagEntry> entries;
|
||||
|
||||
if (info.status.opened) {
|
||||
tagEntry entry;
|
||||
while (tagsNext(tagFile, &entry) == TagSuccess) {
|
||||
entry.name = strdup(entry.name);
|
||||
entry.file = strdup(entry.file);
|
||||
if (entry.address.pattern) {
|
||||
entry.address.pattern = strdup(entry.address.pattern);
|
||||
std::vector<CefRefPtr<CefV8Value>> entries;
|
||||
if (tagsFind(tagFile, &entry, tag.c_str(), TAG_FULLMATCH | TAG_OBSERVECASE) == TagSuccess) {
|
||||
entries.push_back(ParseEntry(entry));
|
||||
while (tagsFindNext(tagFile, &entry) == TagSuccess) {
|
||||
entries.push_back(ParseEntry(entry));
|
||||
}
|
||||
entries.push_back(entry);
|
||||
}
|
||||
|
||||
retval = CefV8Value::CreateArray(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
retval->SetValue(i, entries[i]);
|
||||
}
|
||||
tagsClose(tagFile);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
||||
dispatch_async(mainQueue, ^{
|
||||
context->Enter();
|
||||
CefRefPtr<CefV8Value> v8Tags = CefV8Value::CreateArray(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
v8Tags->SetValue(i, ParseEntry(entries[i]));
|
||||
free((void*)entries[i].name);
|
||||
free((void*)entries[i].file);
|
||||
if (entries[i].address.pattern) {
|
||||
free((void*)entries[i].address.pattern);
|
||||
if (name == "getAllTagsAsync") {
|
||||
std::string path = arguments[0]->GetStringValue().ToString();
|
||||
CefRefPtr<CefV8Value> callback = arguments[1];
|
||||
CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext();
|
||||
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
dispatch_async(queue, ^{
|
||||
tagFileInfo info;
|
||||
tagFile* tagFile;
|
||||
tagFile = tagsOpen(path.c_str(), &info);
|
||||
std::vector<tagEntry> entries;
|
||||
|
||||
if (info.status.opened) {
|
||||
tagEntry entry;
|
||||
while (tagsNext(tagFile, &entry) == TagSuccess) {
|
||||
entry.name = strdup(entry.name);
|
||||
entry.file = strdup(entry.file);
|
||||
if (entry.address.pattern) {
|
||||
entry.address.pattern = strdup(entry.address.pattern);
|
||||
}
|
||||
entries.push_back(entry);
|
||||
}
|
||||
tagsClose(tagFile);
|
||||
}
|
||||
CefV8ValueList callbackArgs;
|
||||
callbackArgs.push_back(v8Tags);
|
||||
callback->ExecuteFunction(callback, callbackArgs);
|
||||
context->Exit();
|
||||
|
||||
dispatch_queue_t mainQueue = dispatch_get_main_queue();
|
||||
dispatch_async(mainQueue, ^{
|
||||
context->Enter();
|
||||
CefRefPtr<CefV8Value> v8Tags = CefV8Value::CreateArray(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
v8Tags->SetValue(i, ParseEntry(entries[i]));
|
||||
free((void*)entries[i].name);
|
||||
free((void*)entries[i].file);
|
||||
if (entries[i].address.pattern) {
|
||||
free((void*)entries[i].address.pattern);
|
||||
}
|
||||
}
|
||||
CefV8ValueList callbackArgs;
|
||||
callbackArgs.push_back(v8Tags);
|
||||
callback->ExecuteFunction(callback, callbackArgs);
|
||||
context->Exit();
|
||||
});
|
||||
});
|
||||
});
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
usage() {
|
||||
echo 'usage: `basename $0` 'chromium-dir' [cef-release-branch] 1>&2'
|
||||
echo 'usage: update-cef chromium-dir [cef-release-branch] 1>&2'
|
||||
echo
|
||||
echo 'chromium-dir is the root of the chromium directory (i.e. ~/code/chromium)'
|
||||
echo 'CEF release branches can be found at http://code.google.com/p/chromiumembedded/wiki/BranchesAndBuilding'
|
||||
@ -14,9 +14,13 @@ fi
|
||||
|
||||
ATOM_ROOT=$(cd $(dirname $0); pwd -P)/..
|
||||
CHROMIUM_DIR=$1
|
||||
CEF_DIR=$CHROMIUM_DIR/src/cef/
|
||||
CEF_DIR=$CHROMIUM_DIR/src/cef
|
||||
CEF_RELEASE_BRANCH=${2:-1271}
|
||||
CEF_BINARY_PATH=$(echo "$CEF_DIR"/binary_distrib/cef_binary_*_macosx/) # Expand the path
|
||||
CEF_REVISION=$(svnversion $CEF_DIR)
|
||||
CEF_BINARY_PATH=$(echo ${CEF_DIR}/binary_distrib/cef_binary_3.${CEF_RELEASE_BRANCH}.${CEF_REVISION}_macosx/) # Expand the path
|
||||
|
||||
echo "CEF_RELEASE_BRANCH=$CEF_RELEASE_BRANCH"
|
||||
echo "CEF_BINARY_PATH=$CEF_BINARY_PATH"
|
||||
|
||||
# Update and compile CEF
|
||||
CEF_AUTOMATE_SCRIPT_PATH=/tmp/cef-update
|
||||
|
@ -56,3 +56,22 @@ describe "the `atom` global", ->
|
||||
expect(stylesheetElementForId(stylesheetPath).length).toBe 0
|
||||
atom.loadPackage("package-with-module")
|
||||
expect(stylesheetElementForId(stylesheetPath).length).toBe 1
|
||||
|
||||
describe ".loadPackages()", ->
|
||||
beforeEach ->
|
||||
window.rootView = new RootView
|
||||
|
||||
it "terminates the worker when all packages have been loaded", ->
|
||||
spyOn(Worker.prototype, 'terminate').andCallThrough()
|
||||
eventHandler = jasmine.createSpy('eventHandler')
|
||||
rootView.on 'grammars-loaded', eventHandler
|
||||
disabledPackages = config.get("core.disabledPackages")
|
||||
disabledPackages.push('textmate-package.tmbundle')
|
||||
config.set "core.disabledPackages", disabledPackages
|
||||
atom.loadPackages()
|
||||
|
||||
waitsFor "all packages to load", 5000, -> eventHandler.callCount > 0
|
||||
|
||||
runs ->
|
||||
expect(Worker.prototype.terminate).toHaveBeenCalled()
|
||||
expect(Worker.prototype.terminate.calls.length).toBe 1
|
||||
|
1
spec/fixtures/packages/textmate-package.tmbundle/Snippets/.hidden-file
vendored
Normal file
1
spec/fixtures/packages/textmate-package.tmbundle/Snippets/.hidden-file
vendored
Normal file
@ -0,0 +1 @@
|
||||
I am hidden so I shouldn't be loaded
|
1
spec/fixtures/packages/textmate-package.tmbundle/Snippets/invalid.plist
vendored
Normal file
1
spec/fixtures/packages/textmate-package.tmbundle/Snippets/invalid.plist
vendored
Normal file
@ -0,0 +1 @@
|
||||
I am not a valid plist but that shouldn't cause a crisis
|
@ -1,3 +1,5 @@
|
||||
OnigRegExp = require 'onig-reg-exp'
|
||||
|
||||
describe "OnigRegExp", ->
|
||||
describe ".search(string, index)", ->
|
||||
it "returns an array of the match and all capture groups", ->
|
||||
|
@ -3,6 +3,7 @@ _ = require 'underscore'
|
||||
Package = require 'package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
Theme = require 'theme'
|
||||
LoadTextMatePackagesTask = require 'load-text-mate-packages-task'
|
||||
|
||||
messageIdCounter = 1
|
||||
originalSendMessageToBrowserProcess = atom.sendMessageToBrowserProcess
|
||||
@ -13,7 +14,15 @@ _.extend atom,
|
||||
pendingBrowserProcessCallbacks: {}
|
||||
|
||||
loadPackages: ->
|
||||
pack.load() for pack in @getPackages()
|
||||
{packages, asyncTextMatePackages} = _.groupBy @getPackages(), (pack) ->
|
||||
if pack instanceof TextMatePackage and pack.name isnt 'text.tmbundle'
|
||||
'asyncTextMatePackages'
|
||||
else
|
||||
'packages'
|
||||
|
||||
pack.load() for pack in packages
|
||||
if asyncTextMatePackages.length
|
||||
new LoadTextMatePackagesTask(asyncTextMatePackages).start()
|
||||
|
||||
getPackages: ->
|
||||
@getPackageNames().map((name) -> Package.build(name)).filter (pack) -> pack?
|
||||
|
@ -404,6 +404,11 @@ class Editor extends View
|
||||
@gutter.widthChanged = (newWidth) =>
|
||||
@scrollView.css('left', newWidth + 'px')
|
||||
|
||||
rootView?.on 'grammars-loaded', =>
|
||||
@reloadGrammar()
|
||||
for session in @editSessions
|
||||
session.reloadGrammar() unless session is @activeEditSession
|
||||
|
||||
@scrollView.on 'scroll', =>
|
||||
if @scrollView.scrollLeft() == 0
|
||||
@gutter.removeClass('drop-shadow')
|
||||
|
@ -1,6 +1,7 @@
|
||||
$ = require 'jquery'
|
||||
_ = require 'underscore'
|
||||
Subscriber = require 'subscriber'
|
||||
GitRepository = require 'git-repository'
|
||||
|
||||
module.exports =
|
||||
class Git
|
||||
|
@ -1,6 +1,7 @@
|
||||
Range = require 'range'
|
||||
_ = require 'underscore'
|
||||
require 'underscore-extensions'
|
||||
OnigRegExp = require 'onig-reg-exp'
|
||||
|
||||
module.exports =
|
||||
class LanguageMode
|
||||
|
5
src/app/load-text-mate-packages-handler.coffee
Normal file
5
src/app/load-text-mate-packages-handler.coffee
Normal file
@ -0,0 +1,5 @@
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
module.exports =
|
||||
loadPackage: (name) ->
|
||||
callTaskMethod('packageLoaded', new TextMatePackage(name).readGrammars())
|
26
src/app/load-text-mate-packages-task.coffee
Normal file
26
src/app/load-text-mate-packages-task.coffee
Normal file
@ -0,0 +1,26 @@
|
||||
Task = require 'Task'
|
||||
|
||||
module.exports =
|
||||
class LoadTextMatePackagesTask extends Task
|
||||
|
||||
constructor: (@packages) ->
|
||||
super('load-text-mate-packages-handler')
|
||||
|
||||
started: ->
|
||||
@loadNextPackage()
|
||||
|
||||
loadNextPackage: ->
|
||||
unless @packages.length
|
||||
@terminate()
|
||||
rootView.trigger 'grammars-loaded'
|
||||
return
|
||||
|
||||
@package = @packages.shift()
|
||||
@loadPackage(@package.name)
|
||||
|
||||
loadPackage: (name) ->
|
||||
@callWorkerMethod('loadPackage', name)
|
||||
|
||||
packageLoaded: (grammars) ->
|
||||
@package.loadGrammars(grammars)
|
||||
@loadNextPackage()
|
@ -2,16 +2,18 @@ _ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
plist = require 'plist'
|
||||
Token = require 'token'
|
||||
OnigRegExp = require 'onig-reg-exp'
|
||||
OnigScanner = require 'onig-scanner'
|
||||
|
||||
module.exports =
|
||||
class TextMateGrammar
|
||||
@loadFromPath: (path) ->
|
||||
grammar = null
|
||||
@readFromPath: (path) ->
|
||||
grammarContent = null
|
||||
plist.parseString fs.read(path), (e, data) ->
|
||||
throw new Error(e) if e
|
||||
grammar = new TextMateGrammar(data[0])
|
||||
throw new Error("Failed to load grammar at path `#{path}`") unless grammar
|
||||
grammar
|
||||
grammarContent = data[0]
|
||||
throw new Error("Failed to load grammar at path `#{path}`") unless grammarContent
|
||||
grammarContent
|
||||
|
||||
name: null
|
||||
fileTypes: null
|
||||
|
@ -22,28 +22,41 @@ class TextMatePackage extends Package
|
||||
super
|
||||
@preferencesPath = fs.join(@path, "Preferences")
|
||||
@syntaxesPath = fs.join(@path, "Syntaxes")
|
||||
@grammars = []
|
||||
|
||||
load: ->
|
||||
try
|
||||
for grammar in @getGrammars()
|
||||
syntax.addGrammar(grammar)
|
||||
|
||||
for { selector, properties } in @getScopedProperties()
|
||||
syntax.addProperties(selector, properties)
|
||||
@loadGrammars()
|
||||
catch e
|
||||
console.warn "Failed to load package named '#{@name}'", e.stack
|
||||
this
|
||||
|
||||
getGrammars: ->
|
||||
return @grammars if @grammars
|
||||
getGrammars: -> @grammars
|
||||
|
||||
readGrammars: ->
|
||||
grammars = []
|
||||
for grammarPath in fs.list(@syntaxesPath)
|
||||
try
|
||||
grammars.push(TextMateGrammar.readFromPath(grammarPath))
|
||||
catch e
|
||||
console.warn "Failed to load grammar at path '#{grammarPath}'", e.stack
|
||||
grammars
|
||||
|
||||
addGrammar: (rawGrammar) ->
|
||||
grammar = new TextMateGrammar(rawGrammar)
|
||||
@grammars.push(grammar)
|
||||
syntax.addGrammar(grammar)
|
||||
|
||||
loadGrammars: (rawGrammars) ->
|
||||
rawGrammars = @readGrammars() unless rawGrammars?
|
||||
|
||||
@grammars = []
|
||||
if fs.exists(@syntaxesPath)
|
||||
for grammarPath in fs.list(@syntaxesPath)
|
||||
try
|
||||
@grammars.push TextMateGrammar.loadFromPath(grammarPath)
|
||||
catch e
|
||||
console.warn "Failed to load grammar at path '#{grammarPath}'", e.stack
|
||||
@grammars
|
||||
@addGrammar(rawGrammar) for rawGrammar in rawGrammars
|
||||
@loadScopedProperties()
|
||||
|
||||
loadScopedProperties: ->
|
||||
for { selector, properties } in @getScopedProperties()
|
||||
syntax.addProperties(selector, properties)
|
||||
|
||||
getScopedProperties: ->
|
||||
scopedProperties = []
|
||||
|
@ -1,17 +1,14 @@
|
||||
AtomPackage = require 'atom-package'
|
||||
fs = require 'fs'
|
||||
PEG = require 'pegjs'
|
||||
_ = require 'underscore'
|
||||
SnippetExpansion = require './src/snippet-expansion'
|
||||
Snippet = require './src/snippet'
|
||||
require './src/package-extensions'
|
||||
LoadSnippetsTask = require './src/load-snippets-task'
|
||||
|
||||
module.exports =
|
||||
class Snippets extends AtomPackage
|
||||
|
||||
snippetsByExtension: {}
|
||||
parser: PEG.buildParser(fs.read(require.resolve 'snippets/snippets.pegjs'), trackLineAndColumn: true)
|
||||
userSnippetsDir: fs.join(config.configDirPath, 'snippets')
|
||||
loaded: false
|
||||
|
||||
activate: (@rootView) ->
|
||||
window.snippets = this
|
||||
@ -19,10 +16,7 @@ class Snippets extends AtomPackage
|
||||
@rootView.on 'editor:attached', (e, editor) => @enableSnippetsInEditor(editor)
|
||||
|
||||
loadAll: ->
|
||||
for pack in atom.getPackages()
|
||||
pack.loadSnippets()
|
||||
|
||||
@loadDirectory(@userSnippetsDir) if fs.exists(@userSnippetsDir)
|
||||
new LoadSnippetsTask(this).start()
|
||||
|
||||
loadDirectory: (snippetsDirPath) ->
|
||||
for snippetsPath in fs.list(snippetsDirPath) when fs.base(snippetsPath).indexOf('.') isnt 0
|
||||
@ -39,12 +33,16 @@ class Snippets extends AtomPackage
|
||||
for selector, snippetsByName of snippetsBySelector
|
||||
snippetsByPrefix = {}
|
||||
for name, attributes of snippetsByName
|
||||
{ prefix, body } = attributes
|
||||
bodyTree = @parser.parse(body)
|
||||
{ prefix, body, bodyTree } = attributes
|
||||
# if `add` isn't called by the loader task (in specs for example), we need to parse the body
|
||||
bodyTree ?= @getBodyParser().parse(body)
|
||||
snippet = new Snippet({name, prefix, bodyTree})
|
||||
snippetsByPrefix[snippet.prefix] = snippet
|
||||
syntax.addProperties(selector, snippets: snippetsByPrefix)
|
||||
|
||||
getBodyParser: ->
|
||||
require 'snippets/src/snippet-body-parser'
|
||||
|
||||
enableSnippetsInEditor: (editor) ->
|
||||
editor.command 'snippets:expand', (e) =>
|
||||
editSession = editor.activeEditSession
|
||||
|
@ -1,19 +1,17 @@
|
||||
Snippets = require 'snippets'
|
||||
Snippet = require 'snippets/src/snippet'
|
||||
LoadSnippetsTask = require 'snippets/src/load-snippets-task'
|
||||
RootView = require 'root-view'
|
||||
Buffer = require 'buffer'
|
||||
Editor = require 'editor'
|
||||
_ = require 'underscore'
|
||||
fs = require 'fs'
|
||||
AtomPackage = require 'atom-package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
describe "Snippets extension", ->
|
||||
[buffer, editor] = []
|
||||
beforeEach ->
|
||||
rootView = new RootView(require.resolve('fixtures/sample.js'))
|
||||
spyOn(AtomPackage.prototype, 'loadSnippets')
|
||||
spyOn(TextMatePackage.prototype, 'loadSnippets')
|
||||
spyOn(LoadSnippetsTask.prototype, 'start')
|
||||
atom.loadPackage("snippets")
|
||||
editor = rootView.getActiveEditor()
|
||||
buffer = editor.getBuffer()
|
||||
@ -214,34 +212,64 @@ describe "Snippets extension", ->
|
||||
expect(editor.getSelectedBufferRange()).toEqual [[1, 6], [1, 36]]
|
||||
|
||||
describe "snippet loading", ->
|
||||
beforeEach ->
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'start')
|
||||
spyOn(LoadSnippetsTask.prototype, 'loadAtomSnippets').andCallFake -> @snippetsLoaded({})
|
||||
spyOn(LoadSnippetsTask.prototype, 'loadTextMateSnippets').andCallFake -> @snippetsLoaded({})
|
||||
|
||||
it "loads non-hidden snippet files from all atom packages with snippets directories, logging a warning if a file can't be parsed", ->
|
||||
spyOn(console, 'warn').andCallThrough()
|
||||
jasmine.unspy(AtomPackage.prototype, 'loadSnippets')
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'loadAtomSnippets')
|
||||
spyOn(console, 'warn')
|
||||
snippets.loaded = false
|
||||
snippets.loadAll()
|
||||
|
||||
expect(syntax.getProperty(['.test'], 'snippets.test')?.constructor).toBe Snippet
|
||||
waitsFor "all snippets to load", 5000, -> snippets.loaded
|
||||
|
||||
# warn about junk-file, but don't even try to parse a hidden file
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
expect(console.warn.calls.length).toBeGreaterThan 0
|
||||
runs ->
|
||||
expect(syntax.getProperty(['.test'], 'snippets.test')?.constructor).toBe Snippet
|
||||
|
||||
# warn about junk-file, but don't even try to parse a hidden file
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
expect(console.warn.calls.length).toBe 1
|
||||
|
||||
it "loads snippets from all TextMate packages with snippets", ->
|
||||
jasmine.unspy(TextMatePackage.prototype, 'loadSnippets')
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'loadTextMateSnippets')
|
||||
spyOn(console, 'warn')
|
||||
snippets.loaded = false
|
||||
snippets.loadAll()
|
||||
|
||||
snippet = syntax.getProperty(['.source.js'], 'snippets.fun')
|
||||
expect(snippet.constructor).toBe Snippet
|
||||
expect(snippet.prefix).toBe 'fun'
|
||||
expect(snippet.name).toBe 'Function'
|
||||
expect(snippet.body).toBe """
|
||||
function function_name (argument) {
|
||||
\t// body...
|
||||
}
|
||||
"""
|
||||
waitsFor "all snippets to load", 5000, -> snippets.loaded
|
||||
|
||||
describe "Snippets parser", ->
|
||||
runs ->
|
||||
snippet = syntax.getProperty(['.source.js'], 'snippets.fun')
|
||||
expect(snippet.constructor).toBe Snippet
|
||||
expect(snippet.prefix).toBe 'fun'
|
||||
expect(snippet.name).toBe 'Function'
|
||||
expect(snippet.body).toBe """
|
||||
function function_name (argument) {
|
||||
\t// body...
|
||||
}
|
||||
"""
|
||||
|
||||
# warn about junk-file, but don't even try to parse a hidden file
|
||||
expect(console.warn).toHaveBeenCalled()
|
||||
expect(console.warn.calls.length).toBe 1
|
||||
|
||||
it "terminates the worker when loading completes", ->
|
||||
jasmine.unspy(LoadSnippetsTask.prototype, 'loadAtomSnippets')
|
||||
spyOn(Worker.prototype, 'terminate').andCallThrough()
|
||||
snippets.loaded = false
|
||||
snippets.loadAll()
|
||||
|
||||
waitsFor "all snippets to load", 5000, -> snippets.loaded
|
||||
|
||||
runs ->
|
||||
expect(Worker.prototype.terminate).toHaveBeenCalled()
|
||||
expect(Worker.prototype.terminate.calls.length).toBe 1
|
||||
|
||||
describe "Snippet body parser", ->
|
||||
it "breaks a snippet body into lines, with each line containing tab stops at the appropriate position", ->
|
||||
bodyTree = snippets.parser.parse """
|
||||
bodyTree = snippets.getBodyParser().parse """
|
||||
the quick brown $1fox ${2:jumped ${3:over}
|
||||
}the ${4:lazy} dog
|
||||
"""
|
||||
|
53
src/packages/snippets/src/load-snippets-handler.coffee
Normal file
53
src/packages/snippets/src/load-snippets-handler.coffee
Normal file
@ -0,0 +1,53 @@
|
||||
fs = require 'fs'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
SnippetBodyParser = require './snippet-body-parser'
|
||||
|
||||
module.exports =
|
||||
snippetsLoaded: (snippets) ->
|
||||
for snippet in snippets
|
||||
for selector, snippetsByName of snippet
|
||||
for name, attributes of snippetsByName
|
||||
attributes.bodyTree = SnippetBodyParser.parse(attributes.body)
|
||||
callTaskMethod('snippetsLoaded', snippets)
|
||||
|
||||
loadTextMateSnippets: (path) ->
|
||||
snippetsDirPath = fs.join(path, 'Snippets')
|
||||
snippets = []
|
||||
|
||||
for snippetsPath in fs.list(snippetsDirPath)
|
||||
logWarning = ->
|
||||
console.warn "Error reading TextMate snippets file '#{snippetsPath}'"
|
||||
|
||||
continue if fs.base(snippetsPath).indexOf('.') is 0
|
||||
try
|
||||
if object = fs.readPlist(snippetsPath)
|
||||
snippets.push(object) if object
|
||||
else
|
||||
logWarning()
|
||||
catch e
|
||||
logWarning()
|
||||
|
||||
@snippetsLoaded(@translateTextmateSnippets(snippets))
|
||||
|
||||
loadAtomSnippets: (path) ->
|
||||
snippetsDirPath = fs.join(path, 'snippets')
|
||||
snippets = []
|
||||
for snippetsPath in fs.list(snippetsDirPath)
|
||||
continue if fs.base(snippetsPath).indexOf('.') is 0
|
||||
try
|
||||
snippets.push(fs.readObject(snippetsPath))
|
||||
catch e
|
||||
console.warn "Error reading snippets file '#{snippetsPath}'"
|
||||
@snippetsLoaded(snippets)
|
||||
|
||||
translateTextmateSnippets: (tmSnippets) ->
|
||||
atomSnippets = {}
|
||||
for { scope, name, content, tabTrigger } in tmSnippets
|
||||
if scope
|
||||
scope = TextMatePackage.cssSelectorFromScopeSelector(scope)
|
||||
else
|
||||
scope = '*'
|
||||
|
||||
snippetsForScope = (atomSnippets[scope] ?= {})
|
||||
snippetsForScope[name] = { prefix: tabTrigger, body: content }
|
||||
[atomSnippets]
|
34
src/packages/snippets/src/load-snippets-task.coffee
Normal file
34
src/packages/snippets/src/load-snippets-task.coffee
Normal file
@ -0,0 +1,34 @@
|
||||
Task = require 'Task'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
|
||||
module.exports =
|
||||
class LoadSnippetsTask extends Task
|
||||
constructor: (@snippets) ->
|
||||
super('snippets/src/load-snippets-handler')
|
||||
@packages = atom.getPackages()
|
||||
@packages.push(path: config.configDirPath)
|
||||
|
||||
started: ->
|
||||
@loadNextPackageSnippets()
|
||||
|
||||
loadNextPackageSnippets: ->
|
||||
unless @packages.length
|
||||
@terminate()
|
||||
@snippets.loaded = true
|
||||
return
|
||||
|
||||
@packageBeingLoaded = @packages.shift()
|
||||
if @packageBeingLoaded instanceof TextMatePackage
|
||||
@loadTextMateSnippets(@packageBeingLoaded.path)
|
||||
else
|
||||
@loadAtomSnippets(@packageBeingLoaded.path)
|
||||
|
||||
loadAtomSnippets: (path) ->
|
||||
@callWorkerMethod('loadAtomSnippets', path)
|
||||
|
||||
loadTextMateSnippets: (path) ->
|
||||
@callWorkerMethod('loadTextMateSnippets', path)
|
||||
|
||||
snippetsLoaded: (snippets) ->
|
||||
@snippets.add(snippet) for snippet in snippets
|
||||
@loadNextPackageSnippets()
|
@ -1,25 +0,0 @@
|
||||
AtomPackage = require 'atom-package'
|
||||
TextMatePackage = require 'text-mate-package'
|
||||
fs = require 'fs'
|
||||
|
||||
AtomPackage.prototype.loadSnippets = ->
|
||||
snippetsDirPath = fs.join(@path, 'snippets')
|
||||
snippets.loadDirectory(snippetsDirPath) if fs.exists(snippetsDirPath)
|
||||
|
||||
TextMatePackage.prototype.loadSnippets = ->
|
||||
snippetsDirPath = fs.join(@path, 'Snippets')
|
||||
if fs.exists(snippetsDirPath)
|
||||
tmSnippets = fs.list(snippetsDirPath).map (snippetPath) -> fs.readPlist(snippetPath)
|
||||
snippets.add(@translateSnippets(tmSnippets))
|
||||
|
||||
TextMatePackage.prototype.translateSnippets = (tmSnippets) ->
|
||||
atomSnippets = {}
|
||||
for { scope, name, content, tabTrigger } in tmSnippets
|
||||
if scope
|
||||
scope = TextMatePackage.cssSelectorFromScopeSelector(scope)
|
||||
else
|
||||
scope = '*'
|
||||
|
||||
snippetsForScope = (atomSnippets[scope] ?= {})
|
||||
snippetsForScope[name] = { prefix: tabTrigger, body: content }
|
||||
atomSnippets
|
4
src/packages/snippets/src/snippet-body-parser.coffee
Normal file
4
src/packages/snippets/src/snippet-body-parser.coffee
Normal file
@ -0,0 +1,4 @@
|
||||
PEG = require 'pegjs'
|
||||
fs = require 'fs'
|
||||
grammarSrc = fs.read(require.resolve('./snippet-body.pegjs'))
|
||||
module.exports = PEG.buildParser(grammarSrc, trackLineAndColumn: true)
|
@ -2,7 +2,6 @@
|
||||
# http://ringojs.org/api/v0.8/fs/
|
||||
|
||||
_ = require 'underscore'
|
||||
$ = require 'jquery'
|
||||
|
||||
module.exports =
|
||||
# Make the given path absolute by resolving it against the
|
||||
|
18
src/stdlib/git-repository.coffee
Normal file
18
src/stdlib/git-repository.coffee
Normal file
@ -0,0 +1,18 @@
|
||||
module.exports =
|
||||
class GitRepository
|
||||
constructor: (path) ->
|
||||
unless repo = $git.getRepository(path)
|
||||
throw new Error("No Git repository found searching path: " + path)
|
||||
repo.constructor = GitRepository
|
||||
repo.__proto__ = GitRepository.prototype
|
||||
return repo
|
||||
|
||||
getHead: $git.getHead
|
||||
getPath: $git.getPath
|
||||
getStatus: $git.getStatus
|
||||
isIgnored: $git.isIgnored
|
||||
checkoutHead: $git.checkoutHead
|
||||
getDiffStats: $git.getDiffStats
|
||||
isSubmodule: $git.isSubmodule
|
||||
refreshIndex: $git.refreshIndex
|
||||
destroy: $git.destroy
|
11
src/stdlib/onig-reg-exp.coffee
Normal file
11
src/stdlib/onig-reg-exp.coffee
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports =
|
||||
class OnigRegExp
|
||||
constructor: (source) ->
|
||||
regexp = $onigRegExp.buildOnigRegExp(source);
|
||||
regexp.constructor = OnigRegExp
|
||||
regexp.__proto__ = OnigRegExp.prototype
|
||||
regexp.source = source
|
||||
return regexp
|
||||
|
||||
search: $onigRegExp.search
|
||||
test: $onigRegExp.test
|
10
src/stdlib/onig-scanner.coffee
Normal file
10
src/stdlib/onig-scanner.coffee
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports =
|
||||
class OnigScanner
|
||||
constructor: (sources) ->
|
||||
scanner = $onigScanner.buildScanner(sources)
|
||||
scanner.constructor = OnigScanner
|
||||
scanner.__proto__ = OnigScanner.prototype
|
||||
scanner.sources = sources
|
||||
return scanner
|
||||
|
||||
findNextMatch: $onigScanner.findNextMatch
|
@ -25,17 +25,16 @@ require = (path, cb) ->
|
||||
unless file = resolve(path)
|
||||
throw new Error("Require can't find file at path '#{path}'")
|
||||
|
||||
parts = file.split '.'
|
||||
ext = parts[parts.length-1]
|
||||
ext = file.split('.').pop()
|
||||
|
||||
if __moduleExists file
|
||||
if not __modules.loaded[file.toLowerCase()]?
|
||||
console.warn "Circular require: #{__filename} required #{file}"
|
||||
console.warn "Circular require: #{window.__filename} required #{file}"
|
||||
return __modules[file]
|
||||
else if __modules.loaded[file.toLowerCase()]
|
||||
console.warn "Multiple requires (different cases) for #{file}"
|
||||
|
||||
[ previousFilename, window.__filename ] = [ __filename, file ]
|
||||
[ previousFilename, window.__filename ] = [ window.__filename, file ]
|
||||
__modules[file] = {} # Fix for circular references
|
||||
__modules[file] = (exts[ext] or (file) -> __read file) file
|
||||
window.__filename = previousFilename
|
||||
@ -43,33 +42,67 @@ require = (path, cb) ->
|
||||
|
||||
define = (cb) ->
|
||||
__defines.push ->
|
||||
exports = __modules[__filename] or {}
|
||||
exports = __modules[window.__filename] or {}
|
||||
module = exports: exports
|
||||
cb.call exports, require, exports, module
|
||||
__modules.loaded[__filename.toLowerCase()] = true
|
||||
__modules.loaded[window.__filename.toLowerCase()] = true
|
||||
module.exports or exports
|
||||
|
||||
exts =
|
||||
js: (file, code) ->
|
||||
code or= __read file
|
||||
eval("define(function(require, exports, module) { 'use strict';" + code + "})\n//@ sourceURL=" + file)
|
||||
eval("define(function(require, exports, module) { 'use strict';#{code}})\n//@ sourceURL=#{file}")
|
||||
__defines.pop()?.call()
|
||||
coffee: (file) ->
|
||||
exts.js(file, __coffeeCache(file))
|
||||
coffee: (file, retry=true) ->
|
||||
cacheFilePath = getCacheFilePath(file)
|
||||
if __exists(cacheFilePath)
|
||||
compiled = __read(cacheFilePath)
|
||||
writeToCache = false
|
||||
else
|
||||
{CoffeeScript} = require 'coffee-script'
|
||||
compiled = CoffeeScript.compile(__read(file), filename: file)
|
||||
writeToCache = true
|
||||
|
||||
try
|
||||
evaluated = exts.js(file, compiled)
|
||||
$native.write(cacheFilePath, compiled) if writeToCache
|
||||
evaluated
|
||||
catch e
|
||||
if retry
|
||||
# Attempt a second compile to work around mysterious CEF/CoffeeScript
|
||||
# timing issue where the CoffeeScript compiler generates invalid
|
||||
# JavaScript such as [object Object].
|
||||
console.warn "Error evaluating #{file}. Trying again...", e.stack
|
||||
exts.coffee(file, false)
|
||||
else
|
||||
throw e
|
||||
|
||||
getPath = (path) ->
|
||||
path = resolve(path)
|
||||
return path unless path.split('.').pop() is 'coffee'
|
||||
|
||||
cacheFilePath = getCacheFilePath(path)
|
||||
unless __exists(cacheFilePath)
|
||||
{CoffeeScript} = require 'coffee-script'
|
||||
compiled = CoffeeScript.compile(__read(path), filename: path)
|
||||
$native.write(cacheFilePath, compiled)
|
||||
cacheFilePath
|
||||
|
||||
getCacheFilePath = (path) ->
|
||||
"/tmp/atom-compiled-scripts/#{$native.md5ForPath(path)}"
|
||||
|
||||
resolve = (name, {verifyExistence}={}) ->
|
||||
verifyExistence ?= true
|
||||
file = name
|
||||
if /!/.test file
|
||||
parts = file.split '!'
|
||||
file = parts[parts.length-1]
|
||||
file = file.split('!').pop()
|
||||
|
||||
if file[0..1] is './'
|
||||
prefix = __filename.split('/')[0..-2].join '/'
|
||||
prefix = window.__filename.split('/')[0..-2].join '/'
|
||||
file = file.replace './', "#{prefix}/"
|
||||
|
||||
if file[0..2] is '../'
|
||||
prefix = __filename.split('/')[0..-3].join '/'
|
||||
prefix = window.__filename.split('/')[0..-3].join '/'
|
||||
file = file.replace '../', "#{prefix}/"
|
||||
|
||||
if file[0] isnt '/'
|
||||
@ -130,18 +163,6 @@ __exists = (path) ->
|
||||
__isFile = (path) ->
|
||||
$native.isFile path
|
||||
|
||||
__coffeeCache = (filePath) ->
|
||||
{CoffeeScript} = require 'coffee-script'
|
||||
tmpPath = "/tmp/atom-compiled-scripts"
|
||||
cacheFilePath = [tmpPath, $native.md5ForPath(filePath)].join("/")
|
||||
|
||||
if __exists(cacheFilePath)
|
||||
__read(cacheFilePath)
|
||||
else
|
||||
compiled = CoffeeScript.compile(__read(filePath), filename: filePath)
|
||||
$native.write(cacheFilePath, compiled)
|
||||
compiled
|
||||
|
||||
__read = (path) ->
|
||||
try
|
||||
$native.read(path)
|
||||
@ -157,6 +178,7 @@ this.nakedLoad = nakedLoad
|
||||
this.define = define
|
||||
|
||||
this.require.paths = paths
|
||||
this.require.getPath = getPath
|
||||
this.require.exts = exts
|
||||
|
||||
this.require.resolve = resolve
|
||||
|
29
src/stdlib/task-shell.coffee
Normal file
29
src/stdlib/task-shell.coffee
Normal file
@ -0,0 +1,29 @@
|
||||
# This file is loaded within Task's worker thread. It will attempt to invoke
|
||||
# any message with a 'method' and 'args' key on the global `handler` object. The
|
||||
# initial `handler` object contains the `start` method, which is called by the
|
||||
# task itself to relay information from the window thread and bootstrap the
|
||||
# worker's environment. The `start` method then replaces the handler with an
|
||||
# object required from the given `handlerPath`.
|
||||
|
||||
self.window = {}
|
||||
self.attachEvent = ->
|
||||
self.console =
|
||||
warn: -> callTaskMethod 'warn', arguments...
|
||||
log: -> callTaskMethod 'log', arguments...
|
||||
error: -> callTaskMethod 'error', arguments...
|
||||
|
||||
# `callTaskMethod` can be used to invoke method's on the parent `Task` object
|
||||
# back in the window thread.
|
||||
self.callTaskMethod = (method, args...) ->
|
||||
postMessage(method: method, args: args)
|
||||
|
||||
# The worker's initial handler replaces itself when `start` is invoked
|
||||
self.handler =
|
||||
start: ({resourcePath, requirePath, handlerPath}) ->
|
||||
window.resourcePath = resourcePath
|
||||
importScripts(requirePath)
|
||||
self.handler = require(handlerPath)
|
||||
callTaskMethod 'started'
|
||||
|
||||
self.addEventListener 'message', ({data}) ->
|
||||
handler[data.method]?(data.args...) if data.method
|
35
src/stdlib/task.coffee
Normal file
35
src/stdlib/task.coffee
Normal file
@ -0,0 +1,35 @@
|
||||
module.exports =
|
||||
class Task
|
||||
constructor: (@path) ->
|
||||
|
||||
start: ->
|
||||
@worker = new Worker(require.getPath('task-shell'))
|
||||
@worker.onmessage = ({data}) =>
|
||||
if data.method and this[data.method]
|
||||
this[data.method](data.args...)
|
||||
else
|
||||
@onMessage(data)
|
||||
@startWorker()
|
||||
|
||||
log: -> console.log(arguments...)
|
||||
warn: -> console.warn(arguments...)
|
||||
error: -> console.error(arguments...)
|
||||
|
||||
startWorker: ->
|
||||
@callWorkerMethod 'start'
|
||||
resourcePath: window.resourcePath
|
||||
requirePath: require.getPath('require')
|
||||
handlerPath: @path
|
||||
|
||||
started: ->
|
||||
|
||||
onMessage: (message) ->
|
||||
|
||||
callWorkerMethod: (method, args...) ->
|
||||
@postMessage({method, args})
|
||||
|
||||
postMessage: (data) ->
|
||||
@worker.postMessage(data)
|
||||
|
||||
terminate: ->
|
||||
@worker.terminate()
|
@ -1,7 +1,9 @@
|
||||
# Like sands through the hourglass, so are the days of our lives.
|
||||
date = new Date().getTime()
|
||||
require 'atom'
|
||||
require 'window'
|
||||
|
||||
pathToOpen = atom.getWindowState('pathToOpen') ? window.location.params.pathToOpen
|
||||
window.attachRootView(pathToOpen)
|
||||
atom.show()
|
||||
console.log "Load time: #{new Date().getTime() - date}"
|
||||
|
Loading…
Reference in New Issue
Block a user