1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-18 09:35:20 +02:00
joplin/CliClient/app/gui/StatusBarWidget.js

172 lines
4.8 KiB
JavaScript
Raw Normal View History

2017-10-15 18:57:09 +02:00
const BaseWidget = require('tkwidgets/BaseWidget.js');
const chalk = require('chalk');
const termutils = require('tkwidgets/framework/termutils.js');
const stripAnsi = require('strip-ansi');
2017-12-14 05:13:43 +02:00
const { handleAutocompletion } = require('../autocompletion.js');
2017-10-15 18:57:09 +02:00
class StatusBarWidget extends BaseWidget {
constructor() {
super();
this.promptState_ = null;
this.inputEventEmitter_ = null;
this.history_ = [];
this.items_ = [];
}
get name() {
return 'statusBar';
}
get canHaveFocus() {
return false;
}
2017-10-15 18:57:09 +02:00
setItemAt(index, text) {
this.items_[index] = stripAnsi(text).trim();
2017-10-15 18:57:09 +02:00
this.invalidate();
}
async prompt(initialText = '', promptString = null, options = null) {
2017-10-15 18:57:09 +02:00
if (this.promptState_) throw new Error('Another prompt already active');
if (promptString === null) promptString = ':';
if (options === null) options = {};
2017-10-15 18:57:09 +02:00
this.root.globalDisableKeyboard(this);
this.promptState_ = {
promise: null,
initialText: stripAnsi(initialText),
promptString: stripAnsi(promptString),
2017-10-15 18:57:09 +02:00
};
if ('cursorPosition' in options) this.promptState_.cursorPosition = options.cursorPosition;
2017-12-12 20:17:30 +02:00
if ('secure' in options) this.promptState_.secure = options.secure;
2017-10-15 18:57:09 +02:00
this.promptState_.promise = new Promise((resolve, reject) => {
this.promptState_.resolve = resolve;
this.promptState_.reject = reject;
});
this.invalidate();
return this.promptState_.promise;
}
get promptActive() {
return !!this.promptState_;
}
get history() {
return this.history_;
}
2017-10-19 00:13:53 +02:00
resetCursor() {
if (!this.promptActive) return;
if (!this.inputEventEmitter_) return;
this.inputEventEmitter_.redraw();
this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY);
this.term.moveTo(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString) + this.inputEventEmitter_.getInput().length, this.absoluteInnerY);
}
2017-10-15 18:57:09 +02:00
render() {
super.render();
2017-10-19 00:13:53 +02:00
const doSaveCursor = !this.promptActive;
if (doSaveCursor) this.term.saveCursor();
2017-10-15 18:57:09 +02:00
this.innerClear();
// Note:
// On Ubuntu, bgBlueBright looks too bright which makes the white text illegible
// On Windows, bgBlueBright is fine and looks dark enough (Windows is probably in the wrong though)
// For now, just don't use any colour at all.
//const textStyle = this.promptActive ? (s) => s : chalk.bgBlueBright.white;
//const textStyle = (s) => s;
const textStyle = this.promptActive ? (s) => s : chalk.gray;
2017-10-15 18:57:09 +02:00
this.term.drawHLine(this.absoluteInnerX, this.absoluteInnerY, this.innerWidth, textStyle(' '));
this.term.moveTo(this.absoluteInnerX, this.absoluteInnerY);
if (this.promptActive) {
this.term.write(textStyle(this.promptState_.promptString));
2017-10-15 19:20:54 +02:00
if (this.inputEventEmitter_) {
2017-10-19 00:13:53 +02:00
// inputField is already waiting for input so in that case just make
// sure that the cursor is at the right position and exit.
this.resetCursor();
2017-10-15 19:20:54 +02:00
return;
}
this.term.showCursor(true);
2017-12-28 21:51:24 +02:00
const isSecurePrompt = !!this.promptState_.secure;
2017-10-15 18:57:09 +02:00
let options = {
cancelable: true,
history: this.history,
default: this.promptState_.initialText,
2017-12-14 15:01:00 +02:00
autoComplete: handleAutocompletion,
autoCompleteHint : true,
autoCompleteMenu : true,
2017-10-15 18:57:09 +02:00
};
if ('cursorPosition' in this.promptState_) options.cursorPosition = this.promptState_.cursorPosition;
2017-12-28 21:51:24 +02:00
if (isSecurePrompt) options.echoChar = true;
2017-10-15 18:57:09 +02:00
this.inputEventEmitter_ = this.term.inputField(options, (error, input) => {
let resolveResult = null;
const resolveFn = this.promptState_.resolve;
if (error) {
this.logger().error('StatusBar: inputField error:', error);
} else {
if (input === undefined) {
// User cancel
} else {
resolveResult = input ? input.trim() : input;
// Add the command to history but only if it's longer than one character.
// Below that it's usually an answer like "y"/"n", etc.
const isConfigPassword = input.indexOf('config ') >= 0 && input.indexOf('password') >= 0;
if (!isSecurePrompt && input && input.length > 1 && !isConfigPassword) this.history_.push(input);
2017-10-15 18:57:09 +02:00
}
}
// If the inputField spans several lines invalidate the root so that
// the interface is relayouted.
if (termutils.textLength(this.promptState_.promptString) + termutils.textLength(input) >= this.innerWidth - 5) {
this.root.invalidate();
}
2017-10-15 18:57:09 +02:00
this.inputEventEmitter_ = null;
this.term.showCursor(false);
this.promptState_ = null;
this.root.globalEnableKeyboard(this);
this.invalidate();
// Only callback once everything has been cleaned up and reset
resolveFn(resolveResult);
});
} else {
for (let i = 0; i < this.items_.length; i++) {
const s = this.items_[i].substr(0, this.innerWidth - 1);
this.term.write(textStyle(s));
2017-10-15 18:57:09 +02:00
}
}
2017-10-19 00:13:53 +02:00
if (doSaveCursor) this.term.restoreCursor();
2017-10-15 18:57:09 +02:00
}
}
module.exports = StatusBarWidget;