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:
parent
4f1133c59a
commit
dcacebf216
@ -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);
|
||||
});
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 ""
|
||||
|
@ -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"
|
||||
|
@ -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 ""
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user