mirror of
https://github.com/quine-global/hyper.git
synced 2026-01-15 05:08:41 -09:00
Handling file opening (#329)
* Add function to escape a shell argument. * Keep track of the last used window. * Implement support for the open-file event. * The shell escape regex needs parentheses to be captured. * Removed lastWindow and added getLastFocusedWindow method to app * Create window create new session only if no callback passed * Added app.windowCallback to handle open-file before "ready" * Small lint fixes * Differeent open file handling: check if it is directory, and if the file is executale or not * Small fixed and added some comments * Added php-escape-shell module in place of custom escapeShellArgument() * Fixed wrong code and added detailed comment * Aliased php_escapeshellcmd import * Rebased; added error handling in OpenFile * changed string contatenation with template literal * Pinned php-escape-shell dependency * Typo fix * getLastdFocusedWindow now uses Array.prototype.reduce() * Notify users of unexisting path while open file
This commit is contained in:
parent
3198a90823
commit
7e941b0451
9 changed files with 106 additions and 14 deletions
43
app/index.js
43
app/index.js
|
|
@ -23,6 +23,15 @@ app.config = config;
|
||||||
app.plugins = plugins;
|
app.plugins = plugins;
|
||||||
app.getWindows = () => new Set([...windowSet]); // return a clone
|
app.getWindows = () => new Set([...windowSet]); // return a clone
|
||||||
|
|
||||||
|
// function to retrive the last focused window in windowSet;
|
||||||
|
// added to app object in order to expose it to plugins.
|
||||||
|
app.getLastFocusedWindow = () => {
|
||||||
|
if (!windowSet.size) return null;
|
||||||
|
return Array.from(windowSet).reduce((lastWindow, win) => {
|
||||||
|
return win.focusTime > lastWindow.focusTime ? win : lastWindow;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
console.log('running in dev mode');
|
console.log('running in dev mode');
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -61,6 +70,7 @@ app.on('ready', () => {
|
||||||
const win = new BrowserWindow(browserOptions);
|
const win = new BrowserWindow(browserOptions);
|
||||||
|
|
||||||
windowSet.add(win);
|
windowSet.add(win);
|
||||||
|
|
||||||
win.loadURL(url);
|
win.loadURL(url);
|
||||||
|
|
||||||
const rpc = createRPC(win);
|
const rpc = createRPC(win);
|
||||||
|
|
@ -84,7 +94,17 @@ app.on('ready', () => {
|
||||||
|
|
||||||
rpc.on('init', () => {
|
rpc.on('init', () => {
|
||||||
win.show();
|
win.show();
|
||||||
if (fn) fn(win);
|
|
||||||
|
// If no callback is passed to createWindow,
|
||||||
|
// a new session will be created by default.
|
||||||
|
if (!fn) fn = (win) => win.rpc.emit('session add req');
|
||||||
|
|
||||||
|
// app.windowCallback is the createWindow callback
|
||||||
|
// that can be setted before the 'ready' app event
|
||||||
|
// and createWindow deifinition. It's exeuted in place of
|
||||||
|
// the callback passed as parameter, and deleted right after.
|
||||||
|
(app.windowCallback || fn)(win);
|
||||||
|
delete (app.windowCallback);
|
||||||
|
|
||||||
// auto updates
|
// auto updates
|
||||||
if (!isDev && process.platform !== 'linux') {
|
if (!isDev && process.platform !== 'linux') {
|
||||||
|
|
@ -214,6 +234,13 @@ app.on('ready', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Keep track of focus time of every window, to figure out
|
||||||
|
// which one of the existing window is the last focused.
|
||||||
|
// Works nicely even if a window is closed and removed.
|
||||||
|
win.on('focus', () => {
|
||||||
|
win.focusTime = process.uptime();
|
||||||
|
});
|
||||||
|
|
||||||
// the window can be closed by the browser process itself
|
// the window can be closed by the browser process itself
|
||||||
win.on('close', () => {
|
win.on('close', () => {
|
||||||
windowSet.delete(win);
|
windowSet.delete(win);
|
||||||
|
|
@ -268,3 +295,17 @@ app.on('ready', () => {
|
||||||
function initSession (opts, fn) {
|
function initSession (opts, fn) {
|
||||||
fn(uuid.v4(), new Session(opts));
|
fn(uuid.v4(), new Session(opts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.on('open-file', (event, path) => {
|
||||||
|
const lastWindow = app.getLastFocusedWindow();
|
||||||
|
const callback = win => win.rpc.emit('open file', { path });
|
||||||
|
if (lastWindow) {
|
||||||
|
callback(lastWindow);
|
||||||
|
} else if (!lastWindow && app.hasOwnProperty('createWindow')) {
|
||||||
|
app.createWindow(callback);
|
||||||
|
} else {
|
||||||
|
// if createWindow not exists yet ('ready' event was not fired),
|
||||||
|
// sets his callback to an app.windowCallback property.
|
||||||
|
app.windowCallback = callback;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
BIN
hyperterm-web-0.0.1.tgz
Normal file
BIN
hyperterm-web-0.0.1.tgz
Normal file
Binary file not shown.
|
|
@ -1,7 +1,5 @@
|
||||||
import { requestSession } from './sessions';
|
import rpc from '../rpc';
|
||||||
|
|
||||||
export function init () {
|
export function init () {
|
||||||
return (dispatch) => {
|
rpc.emit('init');
|
||||||
dispatch(requestSession());
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,6 @@ import {
|
||||||
|
|
||||||
export function addSession (uid, shell, pid) {
|
export function addSession (uid, shell, pid) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const { sessions } = getState();
|
|
||||||
|
|
||||||
// normally this would be encoded as an effect
|
|
||||||
// but the `SESSION_ADD` action is pretty expensive
|
|
||||||
// and we want to get this out as soon as possible
|
|
||||||
const initial = null == sessions.activeUid;
|
|
||||||
if (initial) rpc.emit('init');
|
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: SESSION_ADD,
|
type: SESSION_ADD,
|
||||||
uid,
|
uid,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
|
import * as shellEscape from 'php-escape-shell';
|
||||||
import { setActiveSession } from './sessions';
|
import { setActiveSession } from './sessions';
|
||||||
import { keys } from '../utils/object';
|
import { keys } from '../utils/object';
|
||||||
import { last } from '../utils/array';
|
import { last } from '../utils/array';
|
||||||
|
import { isExecutable } from '../utils/file';
|
||||||
|
import notify from '../utils/notify';
|
||||||
import rpc from '../rpc';
|
import rpc from '../rpc';
|
||||||
import {
|
import {
|
||||||
requestSession,
|
requestSession,
|
||||||
|
|
@ -16,9 +19,12 @@ import {
|
||||||
UI_MOVE_RIGHT,
|
UI_MOVE_RIGHT,
|
||||||
UI_MOVE_TO,
|
UI_MOVE_TO,
|
||||||
UI_SHOW_PREFERENCES,
|
UI_SHOW_PREFERENCES,
|
||||||
UI_WINDOW_MOVE
|
UI_WINDOW_MOVE,
|
||||||
|
UI_OPEN_FILE
|
||||||
} from '../constants/ui';
|
} from '../constants/ui';
|
||||||
|
|
||||||
|
const { stat } = window.require('fs');
|
||||||
|
|
||||||
export function increaseFontSize () {
|
export function increaseFontSize () {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
|
@ -172,3 +178,35 @@ export function windowMove () {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function openFile (path) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
dispatch({
|
||||||
|
type: UI_OPEN_FILE,
|
||||||
|
effect () {
|
||||||
|
stat(path, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err.stack);
|
||||||
|
notify('Unable to open path', `"${path}" doesn't exist.`);
|
||||||
|
} else {
|
||||||
|
// We need to use 'php-escape-shell' property this way
|
||||||
|
// until this eslint issue will be fixed:
|
||||||
|
// https://github.com/eslint/eslint/issues/6755
|
||||||
|
let command = shellEscape.php_escapeshellcmd(path);
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
command = `cd ${command}\n`;
|
||||||
|
} else if (stats.isFile() && isExecutable(stats)) {
|
||||||
|
command += '\n';
|
||||||
|
}
|
||||||
|
rpc.once('session add', ({ uid }) => {
|
||||||
|
rpc.once('session data', () => {
|
||||||
|
dispatch(sendSessionData(uid, command));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dispatch(requestSession());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,4 @@ export const UI_MOVE_RIGHT = 'UI_MOVE_RIGHT';
|
||||||
export const UI_MOVE_TO = 'UI_MOVE_TO';
|
export const UI_MOVE_TO = 'UI_MOVE_TO';
|
||||||
export const UI_SHOW_PREFERENCES = 'UI_SHOW_PREFERENCES';
|
export const UI_SHOW_PREFERENCES = 'UI_SHOW_PREFERENCES';
|
||||||
export const UI_WINDOW_MOVE = 'UI_WINDOW_MOVE';
|
export const UI_WINDOW_MOVE = 'UI_WINDOW_MOVE';
|
||||||
|
export const UI_OPEN_FILE = 'UI_OPEN_FILE';
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,10 @@ rpc.on('preferences', () => {
|
||||||
store_.dispatch(uiActions.showPreferences());
|
store_.dispatch(uiActions.showPreferences());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
rpc.on('open file', ({ path }) => {
|
||||||
|
store_.dispatch(uiActions.openFile(path));
|
||||||
|
});
|
||||||
|
|
||||||
rpc.on('update available', ({ releaseName, releaseNotes }) => {
|
rpc.on('update available', ({ releaseName, releaseNotes }) => {
|
||||||
store_.dispatch(updaterActions.updateAvailable(releaseName, releaseNotes));
|
store_.dispatch(updaterActions.updateAvailable(releaseName, releaseNotes));
|
||||||
});
|
});
|
||||||
|
|
|
||||||
17
lib/utils/file.js
Normal file
17
lib/utils/file.js
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Based on https://github.com/kevva/executable
|
||||||
|
// Since this module doesn't expose the function to check stat mode only,
|
||||||
|
// his logic is pasted here.
|
||||||
|
// Opened an issue and a pull request about it,
|
||||||
|
// to maybe switch to module in the future:
|
||||||
|
// Issue: https://github.com/kevva/executable/issues/9
|
||||||
|
// PR: https://github.com/kevva/executable/pull/10
|
||||||
|
|
||||||
|
export function isExecutable (fileStat) {
|
||||||
|
if (process.platform === 'win32') return true;
|
||||||
|
|
||||||
|
return Boolean(
|
||||||
|
(fileStat['mode'] & parseInt('0001', 8)) ||
|
||||||
|
(fileStat['mode'] & parseInt('0010', 8)) ||
|
||||||
|
(fileStat['mode'] & parseInt('0100', 8))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
"mousetrap": "1.6.0",
|
"mousetrap": "1.6.0",
|
||||||
"ms": "0.7.1",
|
"ms": "0.7.1",
|
||||||
"object-values": "1.0.0",
|
"object-values": "1.0.0",
|
||||||
|
"php-escape-shell": "1.0.0",
|
||||||
"react": "15.3.0",
|
"react": "15.3.0",
|
||||||
"react-addons-pure-render-mixin": "15.3.0",
|
"react-addons-pure-render-mixin": "15.3.0",
|
||||||
"react-deep-force-update": "2.0.1",
|
"react-deep-force-update": "2.0.1",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue