Skip to content

Commit 1ed8109

Browse files
authored
Merge pull request #682 from joshuafcole/0.2.3
0.2.3
2 parents 8705367 + a7c95ad commit 1ed8109

File tree

7 files changed

+122
-81
lines changed

7 files changed

+122
-81
lines changed

bin/eve.js

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
#!/usr/bin/env node
2+
"use strict";
23

34
var path = require("path");
45
var fs = require("fs");
56
var minimist = require("minimist");
67

78
var config = require("../build/src/config");
89
var Owner = config.Owner;
10+
var Mode = config.Mode;
911
var server = require("../build/src/runtime/server");
1012

11-
const argv = minimist(process.argv.slice(2), {boolean: ["server", "editor"]});
13+
const argv = minimist(process.argv.slice(2), {boolean: ["help", "version", "localControl", "server", "editor"]});
1214

1315
// Since our current development pattern uses npm as its package repository, we treat the nearest ancestor directory with a package.json (inclusive) as the directory's "root".
1416
function findRoot(root) {
@@ -34,6 +36,42 @@ var internal = false;
3436
var root = findRoot(process.cwd());
3537
var eveRoot = findRoot(__dirname);
3638

39+
if(argv["help"]) {
40+
let pkg = require(path.join(eveRoot, "package.json"));
41+
console.log(`
42+
Eve ${pkg.version}
43+
44+
Usage: eve [flags] [file]
45+
46+
--help Display this message.
47+
--version Display installed version and exit.
48+
--server Execute code on the server rather than the client.
49+
--editor Display the editor (default if no file is specified).
50+
--port <number> Change the port the Eve server listens to (default 8080).
51+
--localControl Entirely disable server interaction. File changes will be
52+
stored in localStorage.
53+
54+
If the Eve binary is run in a project directory (a directory containing a
55+
package.json file), it will use that directory as your workspace. Otherwise
56+
Eve will use the built-in examples workspace.
57+
58+
If a file is provided, Eve will run it in application-only mode unless the
59+
--editor flag is supplied.
60+
61+
Please refer questions and comments to the mailing list:
62+
https://groups.google.com/forum/#!forum/eve-talk
63+
64+
Please report bugs via GH issues:
65+
https://github.com/witheve/eve/issues
66+
`);
67+
process.exit(0);
68+
}
69+
if(argv["version"]) {
70+
let pkg = require(path.join(eveRoot, "package.json"));
71+
console.log(pkg.version);
72+
process.exit(0);
73+
}
74+
3775

3876
// If we're executing within the eve module/repo, we're running internally and should expose our examples, src, etc.
3977
// This should be handled down the road by some sort of a manifest in conjunction with the `root` rather than hardcoding.
@@ -58,7 +96,10 @@ if(!filepath) {
5896
}
5997
}
6098

61-
var opts = {internal: internal, runtimeOwner: runtimeOwner, controlOwner: controlOwner, editor: editor, port: port, path: filepath, internal: internal, root: root, eveRoot: eveRoot};
99+
let mode = Mode.workspace;
100+
if(filepath && !editor) mode = Mode.file
101+
102+
var opts = {internal: internal, runtimeOwner: runtimeOwner, controlOwner: controlOwner, editor: editor, port: port, path: filepath, internal: internal, root: root, eveRoot: eveRoot, mode};
62103
config.init(opts);
63104

64105
server.run(opts);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "witheve",
3-
"version": "0.2.2",
3+
"version": "0.2.3",
44
"description": "Programming designed for humans",
55
"keywords": ["language", "ide", "relational", "database", "dataflow"],
66
"homepage": "http://witheve.com",

scripts/build-dist.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ function buildDist(callback:() => void) {
2222
let tracker = new Tracker(callback);
2323
build(() => {
2424
mkdirp.sync("dist/build");
25-
mkdirp.sync("dist/css");
2625

2726
var index = fs.readFileSync("./index.html", "utf-8");
2827
if(ENABLE_ANALYTICS) {
@@ -34,13 +33,16 @@ function buildDist(callback:() => void) {
3433
copy("./build/workspaces.js", "./dist/build/workspaces.js", tracker.track("copy packaged workspaces"));
3534

3635

37-
for(let pattern of ["build/src/**/*.js", "build/src/**/*.js.map", "src/**/*.css", "css/**/*.css", "examples/**/*.css"]) {
36+
for(let pattern of ["build/src/**/*", "assets/**/*"]) {
3837
let matches = glob.sync(pattern);
3938
for(let match of matches) {
39+
if(fs.statSync(match).isDirectory()) continue;
4040
let pathname = match.split("/").slice(0, -1).join("/");
4141

4242
// @NOTE: Arghhh
43-
mkdirp.sync("dist/" + pathname);
43+
if(!fs.existsSync("dist/" + pathname)) {
44+
mkdirp.sync("dist/" + pathname);
45+
}
4446
copy(match, "dist/" + match, tracker.track("copy build artifacts"));
4547
}
4648
}

src/client.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -284,20 +284,23 @@ export class EveClient {
284284
browser.init(data.code);
285285
}
286286
if(this.showIDE) {
287-
// Ensure the URL bar is in sync with the server.
288-
// @FIXME: This back and forth of control over where we are
289-
// is an Escherian nightmare.
290-
291-
if(!data.path) {
292-
history.pushState({}, "", window.location.pathname);
293-
}
287+
let path = data.path;
288+
if(path === undefined) path = location.hash && location.hash.slice(1);
289+
//history.replaceState({}, "", window.location.pathname);
294290

295291
this.ide = new IDE();
296292
this.ide.local = this.localControl;
297293
initIDE(this);
298294
this.ide.render();
299-
if(data.path && data.path.length > 2) {
300-
this.ide.loadFile(data.path, data.code);
295+
let found = false;
296+
if(path && path.length > 2) {
297+
let currentHashChunks = path.split("#");//.slice(1);
298+
let docId = currentHashChunks[0];
299+
if(docId && docId[docId.length - 1] === "/") docId = docId.slice(0, -1);
300+
found = this.ide.loadFile(docId, data.code);
301+
}
302+
if(!found && data.internal) {
303+
this.ide.loadFile("/examples/quickstart.eve");
301304
}
302305
}
303306
onHashChange({});
@@ -446,7 +449,15 @@ function initIDE(client:EveClient) {
446449
client.send({type: "close"});
447450
client.send({scope: "root", type: "parse", code})
448451
client.send({type: "eval", persist: false});
452+
449453
let url = `${location.pathname}#${documentId}`;
454+
let currentHashChunks = location.hash.split("#").slice(1);
455+
let curId = currentHashChunks[0];
456+
if(curId && curId[curId.length - 1] === "/") curId = curId.slice(0, -1);
457+
if(curId === documentId && currentHashChunks[1]) {
458+
url += "/#" + currentHashChunks[1];
459+
}
460+
450461
history.pushState({}, "", url + location.search);
451462
analyticsEvent("load-document", documentId);
452463
}

src/config.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
export enum Owner {client, server};
2+
export enum Mode {workspace, file};
23

3-
export interface Config {path?:string, runtimeOwner?: Owner, controlOwner?: Owner, port?:number, editor?: boolean, root?: string, eveRoot?: string, internal?: boolean}
4+
export interface Config {
5+
path?:string,
6+
runtimeOwner?: Owner,
7+
controlOwner?: Owner,
8+
port?:number,
9+
editor?: boolean,
10+
root?: string,
11+
eveRoot?: string,
12+
internal?: boolean,
13+
mode?: Mode
14+
}
415

516
export var config:Config = {};
617

src/ide.ts

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ class Navigator {
419419
{c: "controls", children: [
420420
this.open ? {c: `up-btn flex-row ${(this.currentId === this.rootId) ? "disabled" : ""}`, click: this.navigate, children: [
421421
{c: "up-icon ion-android-arrow-up"},
422-
{c: "label", text: "examples"}
422+
{c: "label", text: "workspaces"}
423423
]} : undefined,
424424
{c: "flex-spacer"},
425425

@@ -2152,6 +2152,7 @@ export class IDE {
21522152
loadFile(docId:string, content?:string) {
21532153
if(!docId) return false;
21542154
if(docId === this.documentId) return false;
2155+
if(this.loading) return false;
21552156

21562157
// We're loading from a remote gist
21572158
if(docId.indexOf("gist:") === 0 && !content) {
@@ -2162,38 +2163,20 @@ export class IDE {
21622163
return true;
21632164
}
21642165

2165-
if(content !== undefined) {
2166-
// @FIXME: It's bad. I know. It will be better when I can swap it all out for the global FileStore guy. I promise.
2167-
// If we're running locally, we may need to ignore the content the server sends us, since our local content is fresher.
2168-
if(this.local && this._fileCache[docId]) {
2169-
content = this._fileCache[docId];
2170-
}
2171-
this.documentId = docId;
2166+
let saves = JSON.parse(localStorage.getItem("eve-saves") || "{}");
2167+
if(this.local && saves[docId]) {
2168+
content = saves[docId];
2169+
this.modified = true;
2170+
2171+
} else if(content) {
21722172
this._fileCache[docId] = content;
2173-
this.editor.reset();
2174-
this.notices = [];
2175-
this.loading = true;
2176-
this.loaded = false;
2177-
this.onLoadFile(this, docId, content);
2178-
return true;
2179-
} else if(this.loading || this.documentId === docId) {
2180-
return false;
2181-
}
21822173

2183-
// Otherwise find the content locally.
2184-
let code;
2185-
if(this.local) {
2186-
let saves = JSON.parse(localStorage.getItem("eve-saves") || "{}");
2187-
code = saves[docId];
2188-
if(code) {
2189-
this.modified = true;
2190-
}
2191-
}
2192-
if(!code) {
2193-
code = this._fileCache[docId];
2174+
} else if(this._fileCache[docId]) {
2175+
content = this._fileCache[docId];
21942176
this.modified = false;
21952177
}
2196-
if(code === undefined) {
2178+
2179+
if(content === undefined) {
21972180
console.error(`Unable to load uncached file: '${docId}'`);
21982181
return false;
21992182
}
@@ -2202,7 +2185,7 @@ export class IDE {
22022185
this.editor.reset();
22032186
this.notices = [];
22042187
this.loading = true;
2205-
this.onLoadFile(this, docId, code);
2188+
this.onLoadFile(this, docId, content);
22062189

22072190
return true;
22082191
}

src/runtime/server.ts

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import * as express from "express";
1010
import * as bodyParser from "body-parser";
1111
import * as minimist from "minimist";
1212

13-
import {config, Config, Owner} from "../config";
13+
import {config, Config, Owner, Mode} from "../config";
1414
import {ActionImplementations} from "./actions";
1515
import {PersistedDatabase} from "./databases/persisted";
1616
import {HttpDatabase} from "./databases/node/http";
@@ -180,52 +180,45 @@ function IDEMessageHandler(client:SocketRuntimeClient, message) {
180180
let data = JSON.parse(message);
181181

182182
if(data.type === "init") {
183-
let {editor, runtimeOwner, controlOwner} = config;
184-
let {url, hash} = data;
183+
let {editor, runtimeOwner, controlOwner, internal, mode} = config;
184+
let {hash} = data;
185185

186+
let content:string;
187+
let path:string;
188+
let isLocal = hash.indexOf("gist:") === 0;
186189

187-
let path = url;
188-
let filepath = path;
189-
if(hash) {
190-
path = hash;
191-
filepath = hash.split("#")[0];
192-
if(filepath[filepath.length - 1] === "/") filepath = filepath.slice(0, -1);
190+
// If we're in file mode, the only valid file to serve is the one specified in `config.path`.
191+
if(mode === Mode.file) {
192+
content = eveSource.find(config.path);
193+
path = config.path;
193194
}
194195

195-
if(config.controlOwner === Owner.client) {
196-
ws.send(JSON.stringify({type: "initProgram", runtimeOwner, controlOwner, path, withIDE: editor}));
197-
return;
198-
}
196+
// Otherwise, anything goes. First we check if the client has requested a specific file in the URL hash.
197+
if(!isLocal && mode === Mode.workspace && hash) {
198+
// @FIXME: This code to strip the editor hash segment out really needs to be abstacted.
199+
let filepath = hash.split("#")[0];
200+
if(filepath[filepath.length - 1] === "/") filepath = filepath.slice(0, -1);
199201

200-
let content = filepath && eveSource.find(filepath);
202+
content = filepath && eveSource.find(filepath);
203+
path = hash;
204+
}
201205

202-
if(!content && config.path && path.indexOf("gist:") === -1) {
206+
// If we've got a path to run with, use it as the default.
207+
if(!isLocal && !content && config.path) {
203208
let workspace = "root";
204209
// @FIXME: This hard-coding isn't technically wrong right now, but it's brittle and poor practice.
205210
content = eveSource.get(config.path, workspace);
206-
if(content) path = eveSource.getRelativePath(config.path, workspace);
211+
path = eveSource.getRelativePath(config.path, workspace);
207212
}
208213

209-
if(content) {
210-
ws.send(JSON.stringify({type: "initProgram", runtimeOwner, controlOwner, path, code: content, withIDE: editor}));
211-
if(runtimeOwner === Owner.server) {
212-
client.load(content, "user");
213-
}
214-
} else {
215-
// @FIXME: Do we still need this fallback for anything? Cases where we need to run an eve file outside of a project?
216-
fs.stat("." + path, (err, stats) => {
217-
if(!err && stats.isFile()) {
218-
let content = fs.readFileSync("." + path).toString();
219-
ws.send(JSON.stringify({type: "initProgram", runtimeOwner, controlOwner, path, code: content, withIDE: editor}));
220-
} else {
221-
path = hash || url;
222-
ws.send(JSON.stringify({type: "initProgram", runtimeOwner, controlOwner, path, withIDE: editor}));
223-
}
214+
// If we can't find the config path in a workspace, try finding it on disk.
215+
if(!isLocal && !content && config.path && fs.existsSync("." + path)) {
216+
content = fs.readFileSync("." + path).toString();
217+
}
224218

225-
if(runtimeOwner === Owner.server) {
226-
client.load(content, "user");
227-
}
228-
});
219+
ws.send(JSON.stringify({type: "initProgram", runtimeOwner, controlOwner, path, code: content, internal, withIDE: editor}));
220+
if(runtimeOwner === Owner.server) {
221+
client.load(content, "user");
229222
}
230223
} else if(data.type === "save"){
231224
eveSource.save(data.path, data.code);

0 commit comments

Comments
 (0)