1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Fixed editing notes

This commit is contained in:
Laurent Cozic 2017-10-14 19:03:23 +01:00
parent 4f1133c59a
commit dcacebf216
11 changed files with 147 additions and 66 deletions

View File

@ -52,8 +52,20 @@ class AppGui {
this.inputMode_ = AppGui.INPUT_MODE_NORMAL;
this.commandCancelCalled_ = false;
this.currentShortcutKeys_ = [];
this.lastShortcutKeyTime_ = 0;
this.lastShortcutKeyTime_ = 0;
cliUtils.setStdout((...object) => {
for (let i = 0; i < object.length; i++) {
this.widget('console').bufferPush(object[i]);
}
});
}
renderer() {
return this.renderer_;
}
buildUi() {
@ -112,8 +124,10 @@ class AppGui {
consoleWidget.hStretch = true;
consoleWidget.name = 'console';
consoleWidget.prompt = chalk.green('Joplin') + ' ' + chalk.magenta('>') + ' ';
consoleWidget.on('accept', (event) => {
this.processCommand(event.input, 'console');
consoleWidget.on('accept', async (event) => {
consoleWidget.promptVisible = false;
await this.processCommand(event.input, 'console');
consoleWidget.promptVisible = true;
});
const hLayout = new HLayoutWidget();
@ -330,11 +344,21 @@ class AppGui {
return ['ENTER', 'DOWN', 'UP', 'LEFT', 'RIGHT', 'DELETE', 'BACKSPACE', 'ESCAPE', 'TAB', 'SHIFT_TAB'].indexOf(name) >= 0;
}
fullScreen(enable = true) {
if (enable) {
this.term().fullscreen();
this.term().hideCursor();
this.widget('root').invalidate();
} else {
this.term().fullscreen(false);
this.term().showCursor();
}
}
async start() {
const term = this.term();
term.fullscreen();
term.hideCursor();
this.fullScreen();
try {
this.renderer_.start();
@ -344,12 +368,32 @@ class AppGui {
term.grabInput();
term.on('key', async (name, matches, data) => {
if (name === 'CTRL_C' ) {
term.showCursor();
term.fullscreen(false);
if (name === 'CTRL_D') {
const cmd = this.app().currentCommand();
if (cmd && cmd.cancellable() && !this.commandCancelCalled_) {
this.commandCancelCalled_ = true;
await cmd.cancel();
this.commandCancelCalled_ = false;
}
this.fullScreen(false);
await this.app().exit();
return;
}
if (name === 'CTRL_C' ) {
const cmd = this.app().currentCommand();
if (!cmd || !cmd.cancellable() || this.commandCancelCalled_) {
consoleWidget.bufferPush(_('Press Ctrl+D or type "exit" to exit the application'));
} else {
this.commandCancelCalled_ = true;
await cmd.cancel();
this.commandCancelCalled_ = false;
}
return;
}
const now = (new Date()).getTime();
@ -381,24 +425,20 @@ class AppGui {
cmd();
} else {
consoleWidget.bufferPush(cmd);
consoleWidget.pause();
await this.processCommand(cmd);
consoleWidget.resume();
}
}
}
}
});
} catch (error) {
this.fullScreen(false);
this.logger().error(error);
term.fullscreen(false);
this.term.showCursor();
console.error(error);
}
process.on('unhandledRejection', (reason, p) => {
term.fullscreen(false);
this.term.showCursor();
this.fullScreen(false);
console.error('Unhandled promise rejection', p, 'reason:', reason);
process.exit(1);
});

View File

@ -278,6 +278,11 @@ class Application {
}
});
cmd.setForceRender(async () => {
this.gui_.widget('root').invalidate();
await this.gui_.renderer().forceRender();
});
cmd.setPrompt(async (message, options) => {
consoleWidget.focus();
@ -384,6 +389,7 @@ class Application {
this.activeCommand_ = this.findCommandByName(commandName);
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
await this.activeCommand_.action(cmdArgs);
this.activeCommand_ = null;
}
currentCommand() {

View File

@ -55,6 +55,14 @@ class BaseCommand {
if (this.stdout_) this.stdout_(...object);
}
setForceRender(fn) {
this.forceRender_ = fn;
}
async forceRender() {
if (this.forceRender_) await this.forceRender_();
}
setPrompt(fn) {
this.prompt_ = fn;
}

View File

@ -12,7 +12,7 @@ cliUtils.splitCommandString = function(s) {
let r = yargParser(s);
let output = [];
for (let i = 0; i < r._.length; i++) {
let a = r._[i];
let a = r._[i].toString();
a = a.replace(/__JOP_DASH_JOP_DASH__/g, '--');
a = a.replace(/__JOP_DASH__/g, '-');
output.push(a);
@ -213,11 +213,15 @@ let redrawStarted_ = false;
let redrawLastLog_ = null;
let redrawLastUpdateTime_ = 0;
cliUtils.setStdout = function(v) {
this.stdout_ = v;
}
cliUtils.redraw = function(s) {
const now = time.unixMs();
if (now - redrawLastUpdateTime_ > 4000) {
console.info(s);
this.stdout_ (s);
redrawLastUpdateTime_ = now;
redrawLastLog_ = null;
} else {
@ -231,7 +235,7 @@ cliUtils.redrawDone = function() {
if (!redrawStarted_) return;
if (redrawLastLog_) {
console.info(redrawLastLog_);
this.stdout_(redrawLastLog_);
}
redrawLastLog_ = null;

View File

@ -1,5 +1,6 @@
import fs from 'fs-extra';
import { BaseCommand } from './base-command.js';
import { uuid } from 'lib/uuid.js';
import { app } from './app.js';
import { _ } from 'lib/locale.js';
import { Folder } from 'lib/models/folder.js';
@ -7,6 +8,7 @@ import { Note } from 'lib/models/note.js';
import { Setting } from 'lib/models/setting.js';
import { BaseModel } from 'lib/base-model.js';
import { cliUtils } from './cli-utils.js';
import { time } from 'lib/time-utils.js';
class Command extends BaseCommand {
@ -20,13 +22,10 @@ class Command extends BaseCommand {
async action(args) {
let watcher = null;
let newNote = null;
let tempFilePath = null;
const onFinishedEditing = async () => {
if (watcher) watcher.close();
//app().vorpal().show();
newNote = null;
this.stdout(_('Done editing.'));
if (tempFilePath) fs.removeSync(tempFilePath);
}
const textEditorPath = () => {
@ -36,6 +35,10 @@ class Command extends BaseCommand {
}
try {
// -------------------------------------------------------------------------
// Load note or create it if it doesn't exist
// -------------------------------------------------------------------------
let title = args['note'];
if (!app().currentFolder()) throw new Error(_('No active notebook.'));
@ -44,47 +47,55 @@ class Command extends BaseCommand {
if (!note) {
const ok = await this.prompt(_('Note does not exist: "%s". Create it?', title));
if (!ok) return;
newNote = await Note.save({ title: title, parent_id: app().currentFolder().id });
note = await Note.load(newNote.id);
note = await Note.save({ title: title, parent_id: app().currentFolder().id });
note = await Note.load(note.id);
}
// -------------------------------------------------------------------------
// Create the file to be edited and prepare the editor program arguments
// -------------------------------------------------------------------------
let editorPath = textEditorPath();
let editorArgs = editorPath.split(' ');
editorPath = editorArgs[0];
editorArgs = editorArgs.splice(1);
let content = await Note.serializeForEdit(note);
const originalContent = await Note.serializeForEdit(note);
let tempFilePath = Setting.value('tempDir') + '/' + Note.systemPath(note);
tempFilePath = Setting.value('tempDir') + '/' + uuid.create() + '.md';
editorArgs.push(tempFilePath);
const spawn = require('child_process').spawn;
await fs.writeFile(tempFilePath, originalContent);
// -------------------------------------------------------------------------
// Start editing the file
// -------------------------------------------------------------------------
this.logger().info('Disabling fullscreen...');
this.stdout(_('Starting to edit note. Close the editor to get back to the prompt.'));
await this.forceRender();
await fs.writeFile(tempFilePath, content);
const spawnSync = require('child_process').spawnSync;
spawnSync(editorPath, editorArgs, { stdio: 'inherit' });
let watchTimeout = null;
watcher = fs.watch(tempFilePath, (eventType, filename) => {
// We need a timeout because for each change to the file, multiple events are generated.
await this.forceRender();
if (watchTimeout) return;
// -------------------------------------------------------------------------
// Save the note and clean up
// -------------------------------------------------------------------------
watchTimeout = setTimeout(async () => {
let updatedNote = await fs.readFile(tempFilePath, 'utf8');
updatedNote = await Note.unserializeForEdit(updatedNote);
updatedNote.id = note.id;
await Note.save(updatedNote);
//process.stdout.write('.');
watchTimeout = null;
}, 200);
});
const updatedContent = await fs.readFile(tempFilePath, 'utf8');
if (updatedContent !== originalContent) {
let updatedNote = await Note.unserializeForEdit(updatedContent);
updatedNote.id = note.id;
await Note.save(updatedNote);
this.logger().info('Note has been saved');
}
await onFinishedEditing();
const childProcess = spawn(editorPath, editorArgs, { stdio: 'inherit' });
childProcess.on('exit', async (error, code) => {
await onFinishedEditing();
});
} catch(error) {
await onFinishedEditing();
throw error;

View File

@ -153,7 +153,7 @@ class Command extends BaseCommand {
if (reg.syncHasAuth(target)) {
let sync = await reg.synchronizer(target);
if (sync) sync.cancel();
if (sync) await sync.cancel();
} else {
if (this.releaseLockFn_) this.releaseLockFn_();
this.releaseLockFn_ = null;

View File

@ -49,18 +49,18 @@ if (process.platform === "win32") {
});
}
let commandCancelCalled_ = false;
// let commandCancelCalled_ = false;
process.on("SIGINT", async function() {
const cmd = application.currentCommand();
// process.on("SIGINT", async function() {
// const cmd = application.currentCommand();
if (!cmd || !cmd.cancellable() || commandCancelCalled_) {
process.exit(0);
} else {
commandCancelCalled_ = true;
await cmd.cancel();
}
});
// if (!cmd || !cmd.cancellable() || commandCancelCalled_) {
// process.exit(0);
// } else {
// commandCancelCalled_ = true;
// await cmd.cancel();
// }
// });
process.stdout.on('error', function( err ) {
// https://stackoverflow.com/questions/12329816/error-write-epipe-when-piping-node-output-to-head#15884508

View File

@ -39,6 +39,9 @@ msgstr ""
msgid "Maximise/minimise the console"
msgstr ""
msgid "Press Ctrl+D or type \"exit\" to exit the application"
msgstr ""
msgid "[Cancel]"
msgstr ""
@ -172,9 +175,6 @@ msgstr ""
msgid "Edit note."
msgstr ""
msgid "Done editing."
msgstr ""
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr ""

View File

@ -46,6 +46,9 @@ msgstr "Créer un carnet."
msgid "Maximise/minimise the console"
msgstr "Quitter le logiciel."
msgid "Press Ctrl+D or type \"exit\" to exit the application"
msgstr ""
#, fuzzy
msgid "[Cancel]"
msgstr "Annulation..."
@ -189,9 +192,6 @@ msgstr ""
msgid "Edit note."
msgstr "Editer la note."
msgid "Done editing."
msgstr "Edition terminée."
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr ""
@ -744,6 +744,9 @@ msgstr ""
msgid "Welcome"
msgstr "Bienvenue"
#~ msgid "Done editing."
#~ msgstr "Edition terminée."
#, fuzzy
#~ msgid "Confirm"
#~ msgstr "Conflits"

View File

@ -39,6 +39,9 @@ msgstr ""
msgid "Maximise/minimise the console"
msgstr ""
msgid "Press Ctrl+D or type \"exit\" to exit the application"
msgstr ""
msgid "[Cancel]"
msgstr ""
@ -172,9 +175,6 @@ msgstr ""
msgid "Edit note."
msgstr ""
msgid "Done editing."
msgstr ""
msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr ""

View File

@ -136,11 +136,20 @@ class Synchronizer {
return false;
}
cancel() {
async cancel() {
if (this.cancelling_ || this.state() == 'idle') return;
this.logSyncOperation('cancelling', null, null, '');
this.cancelling_ = true;
return new Promise((resolve, reject) => {
const iid = setInterval(() => {
if (this.state() == 'idle') {
clearInterval(iid);
resolve();
}
}, 100);
});
}
cancelling() {