1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-03-29 21:21:15 +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.inputMode_ = AppGui.INPUT_MODE_NORMAL;
this.commandCancelCalled_ = false;
this.currentShortcutKeys_ = []; 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() { buildUi() {
@ -112,8 +124,10 @@ class AppGui {
consoleWidget.hStretch = true; consoleWidget.hStretch = true;
consoleWidget.name = 'console'; consoleWidget.name = 'console';
consoleWidget.prompt = chalk.green('Joplin') + ' ' + chalk.magenta('>') + ' '; consoleWidget.prompt = chalk.green('Joplin') + ' ' + chalk.magenta('>') + ' ';
consoleWidget.on('accept', (event) => { consoleWidget.on('accept', async (event) => {
this.processCommand(event.input, 'console'); consoleWidget.promptVisible = false;
await this.processCommand(event.input, 'console');
consoleWidget.promptVisible = true;
}); });
const hLayout = new HLayoutWidget(); 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; 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() { async start() {
const term = this.term(); const term = this.term();
term.fullscreen(); this.fullScreen();
term.hideCursor();
try { try {
this.renderer_.start(); this.renderer_.start();
@ -344,12 +368,32 @@ class AppGui {
term.grabInput(); term.grabInput();
term.on('key', async (name, matches, data) => { term.on('key', async (name, matches, data) => {
if (name === 'CTRL_C' ) {
term.showCursor(); if (name === 'CTRL_D') {
term.fullscreen(false); 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(); await this.app().exit();
return; 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(); const now = (new Date()).getTime();
@ -381,24 +425,20 @@ class AppGui {
cmd(); cmd();
} else { } else {
consoleWidget.bufferPush(cmd); consoleWidget.bufferPush(cmd);
consoleWidget.pause();
await this.processCommand(cmd); await this.processCommand(cmd);
consoleWidget.resume();
} }
} }
} }
} }
}); });
} catch (error) { } catch (error) {
this.fullScreen(false);
this.logger().error(error); this.logger().error(error);
term.fullscreen(false);
this.term.showCursor();
console.error(error); console.error(error);
} }
process.on('unhandledRejection', (reason, p) => { process.on('unhandledRejection', (reason, p) => {
term.fullscreen(false); this.fullScreen(false);
this.term.showCursor();
console.error('Unhandled promise rejection', p, 'reason:', reason); console.error('Unhandled promise rejection', p, 'reason:', reason);
process.exit(1); 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) => { cmd.setPrompt(async (message, options) => {
consoleWidget.focus(); consoleWidget.focus();
@ -384,6 +389,7 @@ class Application {
this.activeCommand_ = this.findCommandByName(commandName); this.activeCommand_ = this.findCommandByName(commandName);
const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv); const cmdArgs = cliUtils.makeCommandArgs(this.activeCommand_, argv);
await this.activeCommand_.action(cmdArgs); await this.activeCommand_.action(cmdArgs);
this.activeCommand_ = null;
} }
currentCommand() { currentCommand() {

View File

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

View File

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

View File

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

View File

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

View File

@ -49,18 +49,18 @@ if (process.platform === "win32") {
}); });
} }
let commandCancelCalled_ = false; // let commandCancelCalled_ = false;
process.on("SIGINT", async function() { // process.on("SIGINT", async function() {
const cmd = application.currentCommand(); // const cmd = application.currentCommand();
if (!cmd || !cmd.cancellable() || commandCancelCalled_) { // if (!cmd || !cmd.cancellable() || commandCancelCalled_) {
process.exit(0); // process.exit(0);
} else { // } else {
commandCancelCalled_ = true; // commandCancelCalled_ = true;
await cmd.cancel(); // await cmd.cancel();
} // }
}); // });
process.stdout.on('error', function( err ) { process.stdout.on('error', function( err ) {
// https://stackoverflow.com/questions/12329816/error-write-epipe-when-piping-node-output-to-head#15884508 // 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" msgid "Maximise/minimise the console"
msgstr "" msgstr ""
msgid "Press Ctrl+D or type \"exit\" to exit the application"
msgstr ""
msgid "[Cancel]" msgid "[Cancel]"
msgstr "" msgstr ""
@ -172,9 +175,6 @@ msgstr ""
msgid "Edit note." msgid "Edit note."
msgstr "" msgstr ""
msgid "Done editing."
msgstr ""
msgid "" msgid ""
"No text editor is defined. Please set it using `config editor <editor-path>`" "No text editor is defined. Please set it using `config editor <editor-path>`"
msgstr "" msgstr ""

View File

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

View File

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

View File

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