2017-10-05 19:17:56 +02:00
|
|
|
import { Logger } from 'lib/logger.js';
|
|
|
|
import { Folder } from 'lib/models/folder.js';
|
|
|
|
import { Note } from 'lib/models/note.js';
|
2017-10-06 19:38:17 +02:00
|
|
|
import { cliUtils } from './cli-utils.js';
|
2017-10-07 18:30:27 +02:00
|
|
|
import { reducer, defaultState } from 'lib/reducer.js';
|
2017-10-09 00:34:01 +02:00
|
|
|
import { _ } from 'lib/locale.js';
|
2017-10-05 19:17:56 +02:00
|
|
|
|
2017-10-13 19:25:58 +02:00
|
|
|
const chalk = require('chalk');
|
2017-10-05 19:17:56 +02:00
|
|
|
const tk = require('terminal-kit');
|
2017-10-13 20:21:57 +02:00
|
|
|
const TermWrapper = require('tkwidgets/framework/TermWrapper.js');
|
2017-10-05 19:17:56 +02:00
|
|
|
const Renderer = require('tkwidgets/framework/Renderer.js');
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
const BaseWidget = require('tkwidgets/BaseWidget.js');
|
2017-10-05 19:17:56 +02:00
|
|
|
const ListWidget = require('tkwidgets/ListWidget.js');
|
|
|
|
const TextWidget = require('tkwidgets/TextWidget.js');
|
|
|
|
const HLayoutWidget = require('tkwidgets/HLayoutWidget.js');
|
|
|
|
const VLayoutWidget = require('tkwidgets/VLayoutWidget.js');
|
2017-10-07 23:01:03 +02:00
|
|
|
const ReduxRootWidget = require('tkwidgets/ReduxRootWidget.js');
|
2017-10-05 19:17:56 +02:00
|
|
|
const RootWidget = require('tkwidgets/RootWidget.js');
|
|
|
|
const WindowWidget = require('tkwidgets/WindowWidget.js');
|
|
|
|
|
2017-10-07 23:01:03 +02:00
|
|
|
const NoteWidget = require('./gui/NoteWidget.js');
|
2017-10-08 00:17:10 +02:00
|
|
|
const FolderListWidget = require('./gui/FolderListWidget.js');
|
2017-10-09 21:57:00 +02:00
|
|
|
const NoteListWidget = require('./gui/NoteListWidget.js');
|
2017-10-15 18:57:09 +02:00
|
|
|
const StatusBarWidget = require('./gui/StatusBarWidget.js');
|
|
|
|
const ConsoleWidget = require('./gui/ConsoleWidget.js');
|
2017-10-07 23:01:03 +02:00
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
class AppGui {
|
|
|
|
|
2017-10-07 23:01:03 +02:00
|
|
|
constructor(app, store) {
|
2017-10-05 19:17:56 +02:00
|
|
|
this.app_ = app;
|
2017-10-07 23:01:03 +02:00
|
|
|
this.store_ = store;
|
2017-10-07 18:30:27 +02:00
|
|
|
|
|
|
|
BaseWidget.setLogger(app.logger());
|
|
|
|
|
2017-10-13 20:21:57 +02:00
|
|
|
this.term_ = new TermWrapper(tk.terminal);
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
this.renderer_ = null;
|
|
|
|
this.logger_ = new Logger();
|
2017-10-07 23:01:03 +02:00
|
|
|
this.buildUi();
|
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
|
|
|
|
|
2017-10-07 20:05:35 +02:00
|
|
|
this.renderer_.on('renderDone', async (event) => {
|
2017-10-15 18:57:09 +02:00
|
|
|
//if (this.widget('console').hasFocus) this.widget('console').resetCursor();
|
2017-10-07 20:05:35 +02:00
|
|
|
});
|
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
this.app_.on('modelAction', async (event) => {
|
|
|
|
await this.handleModelAction(event.action);
|
|
|
|
});
|
2017-10-07 18:30:27 +02:00
|
|
|
|
|
|
|
this.shortcuts_ = this.setupShortcuts();
|
2017-10-09 00:34:01 +02:00
|
|
|
|
|
|
|
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
|
|
|
|
|
2017-10-14 20:03:23 +02:00
|
|
|
this.commandCancelCalled_ = false;
|
|
|
|
|
2017-10-09 21:57:00 +02:00
|
|
|
this.currentShortcutKeys_ = [];
|
2017-10-14 20:03:23 +02:00
|
|
|
this.lastShortcutKeyTime_ = 0;
|
|
|
|
|
|
|
|
cliUtils.setStdout((...object) => {
|
2017-10-15 18:57:09 +02:00
|
|
|
return this.stdout(...object);
|
|
|
|
|
|
|
|
// for (let i = 0; i < object.length; i++) {
|
|
|
|
// this.widget('console').bufferPush(object[i]);
|
|
|
|
// }
|
2017-10-14 20:03:23 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
renderer() {
|
|
|
|
return this.renderer_;
|
2017-10-06 19:38:17 +02:00
|
|
|
}
|
2017-10-05 19:17:56 +02:00
|
|
|
|
2017-10-14 23:44:50 +02:00
|
|
|
async forceRender() {
|
|
|
|
this.widget('root').invalidate();
|
|
|
|
await this.renderer_.renderRoot();
|
|
|
|
}
|
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
buildUi() {
|
2017-10-07 23:01:03 +02:00
|
|
|
this.rootWidget_ = new ReduxRootWidget(this.store_);
|
2017-10-09 00:34:01 +02:00
|
|
|
this.rootWidget_.name = 'root';
|
2017-10-05 19:17:56 +02:00
|
|
|
|
2017-10-08 00:17:10 +02:00
|
|
|
const folderList = new FolderListWidget();
|
2017-10-09 20:05:01 +02:00
|
|
|
folderList.style = { borderBottomWidth: 1 };
|
2017-10-08 19:50:43 +02:00
|
|
|
folderList.name = 'folderList';
|
2017-10-09 20:05:01 +02:00
|
|
|
folderList.vStretch = true;
|
2017-10-05 19:17:56 +02:00
|
|
|
folderList.on('currentItemChange', async () => {
|
2017-10-07 22:04:53 +02:00
|
|
|
const folder = folderList.currentItem;
|
2017-10-08 00:17:10 +02:00
|
|
|
this.store_.dispatch({
|
|
|
|
type: 'FOLDERS_SELECT',
|
|
|
|
folderId: folder ? folder.id : 0,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
this.rootWidget_.connect(folderList, (state) => {
|
|
|
|
return {
|
|
|
|
selectedFolderId: state.selectedFolderId,
|
|
|
|
items: state.folders,
|
|
|
|
};
|
2017-10-05 19:17:56 +02:00
|
|
|
});
|
|
|
|
|
2017-10-09 21:57:00 +02:00
|
|
|
const noteList = new NoteListWidget();
|
2017-10-08 19:50:43 +02:00
|
|
|
noteList.name = 'noteList';
|
2017-10-09 20:05:01 +02:00
|
|
|
noteList.vStretch = true;
|
|
|
|
noteList.style = {
|
2017-10-05 19:17:56 +02:00
|
|
|
borderBottomWidth: 1,
|
|
|
|
borderLeftWidth: 1,
|
|
|
|
borderRightWidth: 1,
|
2017-10-09 20:05:01 +02:00
|
|
|
};
|
2017-10-05 19:17:56 +02:00
|
|
|
noteList.on('currentItemChange', async () => {
|
2017-10-07 22:04:53 +02:00
|
|
|
let note = noteList.currentItem;
|
2017-10-07 23:01:03 +02:00
|
|
|
this.store_.dispatch({
|
|
|
|
type: 'NOTES_SELECT',
|
|
|
|
noteId: note ? note.id : 0,
|
|
|
|
});
|
2017-10-08 00:17:10 +02:00
|
|
|
});
|
|
|
|
this.rootWidget_.connect(noteList, (state) => {
|
|
|
|
return {
|
|
|
|
selectedNoteId: state.selectedNoteId,
|
|
|
|
items: state.notes,
|
|
|
|
};
|
2017-10-05 19:17:56 +02:00
|
|
|
});
|
|
|
|
|
2017-10-07 23:01:03 +02:00
|
|
|
const noteText = new NoteWidget();
|
2017-10-09 20:05:01 +02:00
|
|
|
noteText.vStretch = true;
|
2017-10-08 19:50:43 +02:00
|
|
|
noteText.name = 'noteText';
|
2017-10-09 20:05:01 +02:00
|
|
|
noteText.style = { borderBottomWidth: 1 };
|
2017-10-07 23:01:03 +02:00
|
|
|
this.rootWidget_.connect(noteText, (state) => {
|
|
|
|
return { noteId: state.selectedNoteId };
|
|
|
|
});
|
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
const consoleWidget = new ConsoleWidget();
|
2017-10-09 20:05:01 +02:00
|
|
|
consoleWidget.hStretch = true;
|
2017-10-15 18:57:09 +02:00
|
|
|
|
|
|
|
const statusBar = new StatusBarWidget();
|
|
|
|
statusBar.hStretch = true;
|
2017-10-06 19:38:17 +02:00
|
|
|
|
2017-10-06 20:01:10 +02:00
|
|
|
const hLayout = new HLayoutWidget();
|
2017-10-08 19:50:43 +02:00
|
|
|
hLayout.name = 'hLayout';
|
2017-10-06 20:01:10 +02:00
|
|
|
hLayout.addChild(folderList, { type: 'stretch', factor: 1 });
|
|
|
|
hLayout.addChild(noteList, { type: 'stretch', factor: 1 });
|
2017-10-15 18:57:09 +02:00
|
|
|
hLayout.addChild(noteText, { type: 'stretch', factor: 2 });
|
2017-10-05 19:17:56 +02:00
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
const vLayout = new VLayoutWidget();
|
2017-10-08 19:50:43 +02:00
|
|
|
vLayout.name = 'vLayout';
|
2017-10-06 19:38:17 +02:00
|
|
|
vLayout.addChild(hLayout, { type: 'stretch', factor: 1 });
|
2017-10-15 18:57:09 +02:00
|
|
|
vLayout.addChild(consoleWidget, { type: 'fixed', factor: 3 });
|
|
|
|
vLayout.addChild(statusBar, { type: 'fixed', factor: 1 });
|
2017-10-05 19:17:56 +02:00
|
|
|
|
|
|
|
const win1 = new WindowWidget();
|
2017-10-06 19:38:17 +02:00
|
|
|
win1.addChild(vLayout);
|
2017-10-08 19:50:43 +02:00
|
|
|
win1.name = 'mainWindow';
|
2017-10-05 19:17:56 +02:00
|
|
|
|
2017-10-07 23:01:03 +02:00
|
|
|
this.rootWidget_.addChild(win1);
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
setupShortcuts() {
|
|
|
|
const shortcuts = {};
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts['DELETE'] = {
|
|
|
|
description: _('Delete a note'),
|
|
|
|
action: 'rm $n',
|
|
|
|
};
|
2017-10-08 19:50:43 +02:00
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts[' '] = {
|
|
|
|
friendlyName: 'SPACE',
|
|
|
|
description: _('Set a todo as completed / not completed'),
|
|
|
|
action: 'todo toggle $n',
|
|
|
|
}
|
2017-10-08 19:50:43 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
shortcuts[':'] = {
|
2017-10-09 00:34:01 +02:00
|
|
|
description: _('Enter the console'),
|
2017-10-15 18:57:09 +02:00
|
|
|
isDocOnly: true,
|
2017-10-09 00:34:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
shortcuts['ESC'] = {
|
|
|
|
description: _('Exit the console'),
|
|
|
|
isDocOnly: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
shortcuts['ENTER'] = {
|
|
|
|
description: null,
|
|
|
|
action: () => {
|
2017-10-09 20:05:01 +02:00
|
|
|
const w = this.widget('mainWindow').focusedWidget;
|
2017-10-09 00:34:01 +02:00
|
|
|
if (w.name == 'folderList') {
|
|
|
|
this.widget('noteList').focus();
|
|
|
|
} else if (w.name == 'noteList') {
|
|
|
|
this.processCommand('edit $n');
|
|
|
|
}
|
|
|
|
},
|
2017-10-08 19:50:43 +02:00
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts['nn'] = {
|
|
|
|
description: _('Create a new note'),
|
2017-10-15 18:57:09 +02:00
|
|
|
action: { type: 'prompt', initialText: 'mknote ' },
|
2017-10-08 19:50:43 +02:00
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts['nt'] = {
|
|
|
|
description: _('Create a new todo'),
|
2017-10-15 18:57:09 +02:00
|
|
|
action: { type: 'prompt', initialText: 'mktodo ' },
|
2017-10-08 19:50:43 +02:00
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts['nb'] = {
|
|
|
|
description: _('Create a new notebook'),
|
2017-10-15 18:57:09 +02:00
|
|
|
action: { type: 'prompt', initialText: 'mkbook ' },
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
shortcuts['CTRL_JCTRL_Z'] = {
|
|
|
|
friendlyName: 'Ctrl+J Ctrl+Z',
|
|
|
|
description: _('Maximise/minimise the console'),
|
|
|
|
action: () => { this.toggleMaximizeConsole(); },
|
2017-10-08 19:50:43 +02:00
|
|
|
}
|
2017-10-07 18:30:27 +02:00
|
|
|
|
|
|
|
return shortcuts;
|
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
toggleMaximizeConsole() {
|
|
|
|
this.maximizeConsole(!this.consoleIsMaximized());
|
|
|
|
}
|
|
|
|
|
|
|
|
maximizeConsole(doMaximize = true) {
|
2017-10-15 18:57:09 +02:00
|
|
|
// const consoleWidget = this.widget('console');
|
2017-10-09 00:34:01 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
// if (consoleWidget.isMaximized__ === undefined) {
|
|
|
|
// consoleWidget.isMaximized__ = false;
|
|
|
|
// }
|
2017-10-09 00:34:01 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
// if (consoleWidget.isMaximized__ === doMaximize) return;
|
2017-10-09 00:34:01 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
// let constraints = {
|
|
|
|
// type: 'fixed',
|
|
|
|
// factor: !doMaximize ? 5 : this.widget('vLayout').height - 4,
|
|
|
|
// };
|
2017-10-09 00:34:01 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
// consoleWidget.isMaximized__ = doMaximize;
|
2017-10-09 00:34:01 +02:00
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
// this.widget('vLayout').setWidgetConstraints(consoleWidget, constraints);
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
minimizeConsole() {
|
2017-10-15 18:57:09 +02:00
|
|
|
//this.maximizeConsole(false);
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
consoleIsMaximized() {
|
2017-10-15 18:57:09 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
//return this.widget('console').isMaximized__ === true;
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
widget(name) {
|
2017-10-09 00:34:01 +02:00
|
|
|
if (name === 'root') return this.rootWidget_;
|
2017-10-05 19:17:56 +02:00
|
|
|
return this.rootWidget_.childByName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
app() {
|
|
|
|
return this.app_;
|
|
|
|
}
|
|
|
|
|
|
|
|
setLogger(l) {
|
|
|
|
this.logger_ = l;
|
|
|
|
}
|
|
|
|
|
|
|
|
logger() {
|
|
|
|
return this.logger_;
|
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
shortcuts() {
|
|
|
|
return this.shortcuts_;
|
|
|
|
}
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
term() {
|
|
|
|
return this.term_;
|
|
|
|
}
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
activeListItem() {
|
2017-10-09 20:05:01 +02:00
|
|
|
const widget = this.widget('mainWindow').focusedWidget;
|
2017-10-07 18:30:27 +02:00
|
|
|
if (!widget) return null;
|
|
|
|
|
2017-10-08 19:50:43 +02:00
|
|
|
if (widget.name == 'noteList' || widget.name == 'folderList') {
|
2017-10-07 22:04:53 +02:00
|
|
|
return widget.currentItem;
|
2017-10-07 18:30:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2017-10-06 19:38:17 +02:00
|
|
|
async handleModelAction(action) {
|
2017-10-07 20:05:35 +02:00
|
|
|
this.logger().info('Action:', action);
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
let state = Object.assign({}, defaultState);
|
2017-10-07 22:04:53 +02:00
|
|
|
state.notes = this.widget('noteList').items;
|
2017-10-06 19:38:17 +02:00
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
let newState = reducer(state, action);
|
2017-10-06 19:38:17 +02:00
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
if (newState !== state) {
|
2017-10-07 22:04:53 +02:00
|
|
|
this.widget('noteList').items = newState.notes;
|
2017-10-07 18:30:27 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-06 19:38:17 +02:00
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
async processCommand(cmd) {
|
|
|
|
if (!cmd) return;
|
|
|
|
cmd = cmd.trim();
|
|
|
|
if (!cmd.length) return;
|
|
|
|
|
2017-10-07 22:04:53 +02:00
|
|
|
let note = this.widget('noteList').currentItem;
|
|
|
|
let folder = this.widget('folderList').currentItem;
|
2017-10-06 19:38:17 +02:00
|
|
|
let args = cliUtils.splitCommandString(cmd);
|
|
|
|
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
2017-10-08 19:50:43 +02:00
|
|
|
if (args[i] == '$n') {
|
|
|
|
args[i] = note ? note.id : '';
|
|
|
|
} else if (args[i] == '$b') {
|
|
|
|
args[i] = folder ? folder.id : '';
|
2017-10-07 18:30:27 +02:00
|
|
|
} else if (args[i] == '$c') {
|
|
|
|
const item = this.activeListItem();
|
|
|
|
args[i] = item ? item.id : '';
|
|
|
|
}
|
2017-10-06 19:38:17 +02:00
|
|
|
}
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
try {
|
|
|
|
await this.app().execCommand(args);
|
|
|
|
} catch (error) {
|
2017-10-15 18:57:09 +02:00
|
|
|
this.stdout(error.message);
|
2017-10-07 18:30:27 +02:00
|
|
|
}
|
2017-10-06 19:38:17 +02:00
|
|
|
}
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
async updateFolderList() {
|
|
|
|
const folders = await Folder.all();
|
2017-10-07 22:04:53 +02:00
|
|
|
this.widget('folderList').items = folders;
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async updateNoteList(folderId) {
|
2017-10-06 19:38:17 +02:00
|
|
|
const fields = Note.previewFields();
|
|
|
|
fields.splice(fields.indexOf('body'), 1);
|
|
|
|
const notes = folderId ? await Note.previews(folderId, { fields: fields }) : [];
|
2017-10-07 22:04:53 +02:00
|
|
|
this.widget('noteList').items = notes;
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
async updateNoteText(note) {
|
|
|
|
const text = note ? note.body : '';
|
2017-10-07 22:04:53 +02:00
|
|
|
this.widget('noteText').text = text;
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
|
|
|
|
2017-10-09 21:57:00 +02:00
|
|
|
// Any key after which a shortcut is not possible.
|
2017-10-09 00:34:01 +02:00
|
|
|
isSpecialKey(name) {
|
2017-10-15 18:57:09 +02:00
|
|
|
return [':', 'ENTER', 'DOWN', 'UP', 'LEFT', 'RIGHT', 'DELETE', 'BACKSPACE', 'ESCAPE', 'TAB', 'SHIFT_TAB', 'PAGE_UP', 'PAGE_DOWN'].indexOf(name) >= 0;
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
2017-10-14 20:03:23 +02:00
|
|
|
fullScreen(enable = true) {
|
|
|
|
if (enable) {
|
|
|
|
this.term().fullscreen();
|
|
|
|
this.term().hideCursor();
|
|
|
|
this.widget('root').invalidate();
|
|
|
|
} else {
|
|
|
|
this.term().fullscreen(false);
|
|
|
|
this.term().showCursor();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
stdout(...object) {
|
|
|
|
for (let i = 0; i < object.length; i++) {
|
|
|
|
const v = typeof object[i] === 'object' ? JSON.stringify(object[i]) : object[i];
|
|
|
|
this.widget('console').addItem(v);
|
|
|
|
}
|
|
|
|
|
2017-10-15 19:20:54 +02:00
|
|
|
this.updateStatusBarMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
updateStatusBarMessage() {
|
|
|
|
const consoleWidget = this.widget('console');
|
|
|
|
|
|
|
|
let msg = '';
|
|
|
|
|
|
|
|
const text = consoleWidget.items.length ? consoleWidget.items[consoleWidget.items.length - 1] : '';
|
|
|
|
|
|
|
|
const cmd = this.app().currentCommand();
|
|
|
|
if (cmd) {
|
|
|
|
msg += cmd.name();
|
|
|
|
if (cmd.cancellable()) msg += ' [Press Ctrl+C to cancel]';
|
|
|
|
msg += ': ';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (text && text.length) {
|
|
|
|
msg += text;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg !== '') this.widget('statusBar').setItemAt(0, msg);
|
2017-10-15 18:57:09 +02:00
|
|
|
}
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
async start() {
|
|
|
|
const term = this.term();
|
|
|
|
|
2017-10-14 20:03:23 +02:00
|
|
|
this.fullScreen();
|
2017-10-05 19:17:56 +02:00
|
|
|
|
|
|
|
try {
|
|
|
|
this.renderer_.start();
|
|
|
|
|
2017-10-15 18:57:09 +02:00
|
|
|
const statusBar = this.widget('statusBar');
|
2017-10-07 18:30:27 +02:00
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
term.grabInput();
|
|
|
|
|
2017-10-07 18:30:27 +02:00
|
|
|
term.on('key', async (name, matches, data) => {
|
2017-10-14 20:03:23 +02:00
|
|
|
|
|
|
|
if (name === 'CTRL_D') {
|
|
|
|
const cmd = this.app().currentCommand();
|
|
|
|
|
|
|
|
if (cmd && cmd.cancellable() && !this.commandCancelCalled_) {
|
|
|
|
this.commandCancelCalled_ = true;
|
|
|
|
await cmd.cancel();
|
|
|
|
this.commandCancelCalled_ = false;
|
|
|
|
}
|
|
|
|
|
2017-10-09 22:29:49 +02:00
|
|
|
await this.app().exit();
|
2017-10-07 18:30:27 +02:00
|
|
|
return;
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
2017-10-14 20:03:23 +02:00
|
|
|
|
|
|
|
if (name === 'CTRL_C' ) {
|
|
|
|
const cmd = this.app().currentCommand();
|
|
|
|
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
|
2017-10-15 18:57:09 +02:00
|
|
|
this.stdout(_('Press Ctrl+D or type "exit" to exit the application'));
|
2017-10-14 20:03:23 +02:00
|
|
|
} else {
|
|
|
|
this.commandCancelCalled_ = true;
|
|
|
|
await cmd.cancel();
|
|
|
|
this.commandCancelCalled_ = false;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2017-10-09 21:57:00 +02:00
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
const now = (new Date()).getTime();
|
|
|
|
|
2017-10-09 21:57:00 +02:00
|
|
|
if (now - this.lastShortcutKeyTime_ > 800 || this.isSpecialKey(name)) {
|
|
|
|
this.currentShortcutKeys_ = [name];
|
2017-10-09 00:34:01 +02:00
|
|
|
} else {
|
2017-10-09 21:57:00 +02:00
|
|
|
// If the previous key was a special key (eg. up, down arrow), this new key
|
|
|
|
// starts a new shortcut.
|
|
|
|
if (this.currentShortcutKeys_.length && this.isSpecialKey(this.currentShortcutKeys_[0])) {
|
|
|
|
this.currentShortcutKeys_ = [name];
|
|
|
|
} else {
|
|
|
|
this.currentShortcutKeys_.push(name);
|
|
|
|
}
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
this.lastShortcutKeyTime_ = now;
|
|
|
|
|
2017-10-15 19:20:54 +02:00
|
|
|
if (!this.app().currentCommand()) {
|
|
|
|
if (name === ':' && !statusBar.promptActive) {
|
|
|
|
const cmd = await statusBar.prompt();
|
|
|
|
await this.processCommand(cmd);
|
|
|
|
} else {
|
|
|
|
// Don't process shortcut keys if the console is active, except if the shortcut
|
|
|
|
// starts with CTRL (eg. CTRL+J CTRL+Z to maximize the console window).
|
|
|
|
if (!statusBar.promptActive || (this.currentShortcutKeys_.length && this.currentShortcutKeys_[0].indexOf('CTRL') === 0)) {
|
|
|
|
this.logger().debug('Now: ' + name + ', Keys: ', this.currentShortcutKeys_);
|
|
|
|
|
|
|
|
const shortcutKey = this.currentShortcutKeys_.join('');
|
|
|
|
if (shortcutKey in this.shortcuts_) {
|
|
|
|
const cmd = this.shortcuts_[shortcutKey].action;
|
|
|
|
if (!cmd.isDocOnly) {
|
|
|
|
this.currentShortcutKeys_ = [];
|
|
|
|
if (typeof cmd === 'function') {
|
|
|
|
await cmd();
|
|
|
|
} else if (typeof cmd === 'object') {
|
|
|
|
if (cmd.type === 'prompt') {
|
|
|
|
const commandString = await statusBar.prompt(cmd.initialText ? cmd.initialText : '');
|
|
|
|
this.stdout(commandString);
|
|
|
|
await this.processCommand(commandString);
|
|
|
|
} else {
|
|
|
|
throw new Error('Unknown command: ' + JSON.stringify(cmd));
|
|
|
|
}
|
2017-10-15 18:57:09 +02:00
|
|
|
} else {
|
2017-10-15 19:20:54 +02:00
|
|
|
this.stdout(cmd);
|
|
|
|
await this.processCommand(cmd);
|
2017-10-15 18:57:09 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-09 00:34:01 +02:00
|
|
|
}
|
2017-10-07 18:30:27 +02:00
|
|
|
}
|
|
|
|
}
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
2017-10-15 19:20:54 +02:00
|
|
|
|
|
|
|
// Optimisation: Update the status bar only
|
|
|
|
// if the user is not already typing a command:
|
|
|
|
if (!statusBar.promptActive) this.updateStatusBarMessage();
|
2017-10-05 19:17:56 +02:00
|
|
|
});
|
|
|
|
} catch (error) {
|
2017-10-14 20:03:23 +02:00
|
|
|
this.fullScreen(false);
|
2017-10-05 19:17:56 +02:00
|
|
|
this.logger().error(error);
|
|
|
|
console.error(error);
|
|
|
|
}
|
2017-10-08 00:17:10 +02:00
|
|
|
|
|
|
|
process.on('unhandledRejection', (reason, p) => {
|
2017-10-14 20:03:23 +02:00
|
|
|
this.fullScreen(false);
|
2017-10-08 00:17:10 +02:00
|
|
|
console.error('Unhandled promise rejection', p, 'reason:', reason);
|
|
|
|
process.exit(1);
|
|
|
|
});
|
2017-10-05 19:17:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-10-09 00:34:01 +02:00
|
|
|
AppGui.INPUT_MODE_NORMAL = 1;
|
|
|
|
AppGui.INPUT_MODE_META = 2;
|
|
|
|
|
2017-10-05 19:17:56 +02:00
|
|
|
module.exports = AppGui;
|