Skip to content

Commit

Permalink
Merge pull request #68 from 0916dhkim/command-line-args
Browse files Browse the repository at this point in the history
Open File By Command Line Argument
  • Loading branch information
0916dhkim committed Mar 19, 2020
2 parents 874a1a8 + 5c2151b commit fa5d774
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/common/event.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
export type EventType =
| "ON-INITIALIZE"
| "ON-CLOSE"
| "ON-NEW-FILE-MENU"
| "ON-OPEN-FILE-MENU"
| "ON-SAVE-MENU"
| "ON-SAVE-AS-MENU";

export type EventOptions<T extends EventType> = { type: T } & {
"ON-INITIALIZE": { processArgs: Array<string> };
"ON-CLOSE": {};
"ON-NEW-FILE-MENU": {};
"ON-OPEN-FILE-MENU": {};
Expand Down
3 changes: 3 additions & 0 deletions src/common/request.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export type RequestType =
| "INVOKE-INITIALIZATION"
| "GET-VERSION"
| "CLOSE-WINDOW"
| "SHOW-OPEN-DIALOG"
Expand All @@ -8,6 +9,7 @@ export type RequestType =
| "SHOW-ERROR-MESSAGE";

export type RequestOptions<T extends RequestType> = { type: T } & {
"INVOKE-INITIALIZATION": {};
"GET-VERSION": {};
"CLOSE-WINDOW": {};
"SHOW-OPEN-DIALOG": {};
Expand All @@ -28,6 +30,7 @@ export type WarningMessageOption = "OK" | "Cancel";
export type OverrideWarningOption = "Save" | "Don't Save" | "Cancel";

export type Response<T extends RequestType> = {
"INVOKE-INITIALIZATION": void;
"GET-VERSION": string;
"CLOSE-WINDOW": void;
"SHOW-OPEN-DIALOG": string | null;
Expand Down
14 changes: 14 additions & 0 deletions src/main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ import {
} from "../common/request";
import * as path from "path";
import { format as formatUrl } from "url";
import { EventEmitter } from "../common/event";

const isDevelopment = process.env.NODE_ENV !== "production";

// global reference to mainWindow (necessary to prevent window from being garbage collected)
let mainWindow: BrowserWindow | null = null;
let closeRequestReceived = false;

async function invokeInitializationRequestHandler(
emit: EventEmitter
): Promise<Response<"INVOKE-INITIALIZATION">> {
emit({
type: "ON-INITIALIZE",
processArgs: process.argv
});
}

async function getVersionRequestHandler(): Promise<Response<"GET-VERSION">> {
return app.getVersion();
}
Expand Down Expand Up @@ -160,6 +170,10 @@ function createMainWindow(): BrowserWindow {
});
});

registerRequestHandler(
"INVOKE-INITIALIZATION",
invokeInitializationRequestHandler.bind(null, emit)
);
registerRequestHandler("GET-VERSION", getVersionRequestHandler);
registerRequestHandler("CLOSE-WINDOW", closeRequestHandler);
registerRequestHandler("SHOW-OPEN-DIALOG", showOpenDialogRequestHandler);
Expand Down
45 changes: 42 additions & 3 deletions src/renderer/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Container, Segment } from "semantic-ui-react";
import { Request } from "../common/request";
import { RequestContext } from "./request_context";
import { castDraft, produce } from "../common/persistence/immer-initialized";
import { UseEventHandler } from "../common/event";
import { UseEventHandler, EventOptions } from "../common/event";
import { WelcomeView } from "./welcome_view";

export interface RootProps {
Expand Down Expand Up @@ -99,6 +99,39 @@ const contentViews: ContentViewElementInterface[] = [
}
];

/**
* Deserialize a file into app data.
* @param path Path of a file to read app data from.
* @returns the deserialized app data. `null` if failed.
*/
function getAppDataFromFile(path: string): AppData | null {
try {
const fileContent = fs.readFileSync(path, { encoding: "utf8" });
return deserializeAppData(fileContent);
} catch {
return null;
}
}

async function initializeHandler(
dispatch: React.Dispatch<RootAction>,
{ processArgs }: EventOptions<"ON-INITIALIZE">
): Promise<void> {
if (processArgs.length < 2) {
// No process argument provided.
return;
}
// The first process argument is a path of an app data file.
// Deserialize the file to initialize this Root component.
const path = processArgs[1];
const deserializedData = getAppDataFromFile(path);
if (deserializedData === null) {
return;
}
dispatch({ type: "Open File", fileData: deserializedData, filePath: path });
return;
}

/**
* @param state Root component state.
* @returns `true` if there is any unsaved changes. `false` otherwise.
Expand Down Expand Up @@ -250,8 +283,7 @@ async function openFileMenuHandler(
if (await ensureSafeToOverrideAppData(request, dispatch, state)) {
const file = await request({ type: "SHOW-OPEN-DIALOG" });
if (file !== null) {
const fileContent = fs.readFileSync(file, { encoding: "utf8" });
const appDataFromFile = deserializeAppData(fileContent);
const appDataFromFile = getAppDataFromFile(file);
if (appDataFromFile === null) {
throw "Failed to deserialize file.";
}
Expand All @@ -277,6 +309,13 @@ export function Root({
contentViewIndex: 0,
currentFilePath: null
});

// Request for initialization event from main process.
React.useEffect(() => {
request({ type: "INVOKE-INITIALIZATION" });
}, [request]);

useEventHandler("ON-INITIALIZE", initializeHandler.bind(null, dispatch));
useEventHandler(
"ON-CLOSE",
closeHandler.bind(null, request, dispatch, state)
Expand Down

0 comments on commit fa5d774

Please sign in to comment.