Various changes

pull/41/head
Laurent Cozic 2017-07-04 19:12:30 +00:00
parent 62c56044b0
commit e323a86563
28 changed files with 282 additions and 13066 deletions

View File

@ -21,6 +21,7 @@ import { Logger } from 'lib/logger.js';
import { uuid } from 'lib/uuid.js';
import { sprintf } from 'sprintf-js';
import { importEnex } from 'import-enex';
import { vorpalUtils } from 'vorpal-utils.js';
import { filename, basename } from 'lib/path-utils.js';
import { _ } from 'lib/locale.js';
import os from 'os';
@ -45,6 +46,8 @@ let synchronizers_ = {};
let logger = new Logger();
let dbLogger = new Logger();
let syncLogger = new Logger();
let showPromptString = true;
let logLevel = Logger.LEVEL_INFO;
commands.push({
usage: 'version',
@ -63,7 +66,7 @@ commands.push({
Folder.save({ title: args['notebook'] }, { duplicateCheck: true }).then((folder) => {
switchCurrentFolder(folder);
}).catch((error) => {
this.log(error);
vorpalUtils.log(this, error);
}).then(() => {
end();
});
@ -74,22 +77,27 @@ commands.push({
usage: 'mknote <note>',
aliases: ['touch'],
description: 'Creates a new note',
action: function(args, end) {
action: async function(args, end) {
if (!currentFolder) {
this.log('Notes can only be created within a notebook.');
end();
return;
}
let path = await parseNotePattern(args['note']);
let note = {
title: args['note'],
parent_id: currentFolder.id,
title: path.title,
parent_id: path.parent ? path.parent.id : currentFolder.id,
};
Note.save(note).catch((error) => {
try {
await Note.save(note);
} catch (error) {
this.log(error);
}).then((note) => {
end();
});
}
end();
},
});
@ -109,12 +117,12 @@ commands.push({
});
commands.push({
usage: 'set <title> <name> [value]',
description: 'Sets the property <name> of the given item to the given [value].',
usage: 'set <item> <name> [value]',
description: 'Sets the property <name> of the given <item> to the given [value].',
action: async function(args, end) {
try {
let promise = null;
let title = args['title'];
let title = args['item'];
let propName = args['name'];
let propValue = args['value'];
if (!propValue) propValue = '';
@ -188,6 +196,63 @@ commands.push({
autocomplete: autocompleteItems,
});
commands.push({
usage: 'edit <title>',
description: 'Edit note.',
action: async function(args, end) {
try {
let title = args['title'];
if (!currentFolder) throw new Error(_('No active notebook.'));
let note = await Note.loadFolderNoteByField(currentFolder.id, 'title', title);
if (!note) throw new Error(_('No note with title "%s" found.', title));
let editorPath = getTextEditorPath();
let editorArgs = editorPath.split(' ');
editorPath = editorArgs[0];
editorArgs = [editorArgs[1]];
let content = await Note.serializeForEdit(note);
const temp = require('temp');
const spawn = require('child_process').spawn;
this.log(_('Starting to edit note...'));
vorpal.hide();
temp.track();
temp.open(Setting.value('appName'), async (error, info) => {
if (error) throw error;
await fs.writeFile(info.path, content);
fs.watch(info.path, (eventType, filename) => {
console.info('cHANGE...');
});
// https://github.com/dthree/vorpal/issues/190
editorArgs.push(info.path);
const childProcess = spawn(editorPath, editorArgs, { stdio: 'inherit' });
childProcess.on('exit', (error, code) => {
this.log(_('Done editing note.'));
vorpal.show();
end();
});
});
} catch(error) {
this.log(error);
end();
}
},
autocomplete: autocompleteItems,
});
commands.push({
usage: 'rm <pattern>',
description: 'Deletes the given item. For a notebook, all the notes within that notebook will be deleted. Use `rm ../<notebook>` to delete a notebook.',
@ -428,8 +493,6 @@ commands.push({
],
action: function(args, end) {
let redrawnCalled = false;
let options = {
onProgress: (report) => {
let line = [];
@ -437,11 +500,10 @@ commands.push({
if (report.remotesToDelete) line.push(_('Remote items to delete: %d/%d.', report.deleteRemote, report.remotesToDelete));
if (report.localsToUdpate) line.push(_('Items to download: %d/%d.', report.createLocal + report.updateLocal, report.localsToUdpate));
if (report.localsToDelete) line.push(_('Local items to delete: %d/%d.', report.deleteLocal, report.localsToDelete));
// redrawnCalled = true;
// vorpal.ui.redraw(line.join(' '));
vorpalUtils.redraw(line.join(' '));
},
onMessage: (msg) => {
if (redrawnCalled) vorpal.ui.redraw.done();
vorpalUtils.redrawDone();
this.log(msg);
},
randomFailures: args.options['random-failures'] === true,
@ -454,7 +516,7 @@ commands.push({
}).catch((error) => {
this.log(error);
}).then(() => {
if (redrawnCalled) vorpal.ui.redraw.done();
vorpalUtils.redrawDone();
this.log(_('Done.'));
end();
});
@ -468,7 +530,6 @@ commands.push({
['--fuzzy-matching', 'For debugging purposes. Do not use.'],
],
action: async function(args, end) {
let redrawnCalled = false;
try {
let filePath = args.file;
let folder = null;
@ -517,11 +578,10 @@ commands.push({
if (progressState.skipped) line.push(_('Skipped: %d.', progressState.skipped));
if (progressState.resourcesCreated) line.push(_('Resources: %d.', progressState.resourcesCreated));
if (progressState.notesTagged) line.push(_('Tagged: %d.', progressState.notesTagged));
redrawnCalled = true;
vorpal.ui.redraw(line.join(' '));
vorpalUtils.redraw(line.join(' '));
},
onError: (error) => {
if (redrawnCalled) vorpal.ui.redraw.done();
vorpalUtils.redrawDone();
let s = error.trace ? error.trace : error.toString();
this.log(s);
},
@ -530,17 +590,34 @@ commands.push({
folder = !folder ? await Folder.save({ title: folderTitle }) : folder;
this.log(_('Importing notes...'));
await importEnex(folder.id, filePath, options);
this.log(_('Done.'));
} catch (error) {
this.log(error);
}
if (redrawnCalled) vorpal.ui.redraw.done();
vorpalUtils.redrawDone();
end();
},
});
async function parseNotePattern(pattern) {
if (pattern.indexOf('..') === 0) {
let pieces = pattern.split('/');
if (pieces.length != 3) throw new Error(_('Invalid pattern: %s', pattern));
let parent = await loadItem(BaseModel.TYPE_FOLDER, pieces[1]);
if (!parent) throw new Error(_('Notebook not found: %s', pieces[1]));
return {
parent: parent,
title: pieces[2],
};
} else {
return {
parent: null,
title: pattern,
};
}
}
async function loadItem(type, pattern) {
let output = await loadItems(type, pattern);
return output.length ? output[0] : null;
@ -633,11 +710,13 @@ function switchCurrentFolder(folder) {
}
function promptString() {
if (!showPromptString) return '';
let path = '~';
if (currentFolder) {
path += '/' + currentFolder.title;
}
return 'joplin:' + path + '$ ';
return Setting.value('appName') + ':' + path + '$ ';
}
function updatePrompt() {
@ -694,6 +773,7 @@ function cmdPromptConfirm(commandInstance, message) {
default: false, // This needs to be false so that, when pressing Ctrl+C, the prompt returns false
message: message,
};
commandInstance.prompt(options, (result) => {
if (result.ok) {
resolve(true);
@ -715,14 +795,31 @@ async function handleStartFlags(argv) {
let nextArg = argv.length >= 2 ? argv[1] : null;
if (arg == '--profile') {
if (!nextArg) {
throw new Error(_('Usage: --profile <dir-path>'));
}
if (!nextArg) throw new Error(_('Usage: --profile <dir-path>'));
initArgs.profileDir = nextArg;
argv.splice(0, 2);
continue;
}
if (arg == '--redraw-disabled') {
vorpalUtils.setRedrawEnabled(false);
argv.splice(0, 1);
continue;
}
if (arg == '--stack-trace-enabled') {
vorpalUtils.setStackTraceEnabled(true);
argv.splice(0, 1);
continue;
}
if (arg == '--log-level') {
if (!nextArg) throw new Error(_('Usage: --log-level <none|error|warn|info|debug>'));
logLevel = Logger.levelStringToId(nextArg);
argv.splice(0, 2);
continue;
}
if (arg.length && arg[0] == '-') {
throw new Error(_('Unknown flag: %s', arg));
} else {
@ -749,7 +846,15 @@ function shellArgsToString(args) {
return output.join(' ');
}
function getTextEditorPath() {
if (Setting.value('editor')) return Setting.value('editor');
if (process.env.EDITOR) return process.env.EDITOR;
throw new Error(_('No text editor is defined. Please set it using `config editor <editor-path>`'));
}
process.stdin.on('keypress', (_, key) => {
console.info(_, key);
if (key && key.name === 'return') {
updatePrompt();
}
@ -762,6 +867,8 @@ process.stdin.on('keypress', (_, key) => {
const vorpal = require('vorpal')();
vorpalUtils.initialize(vorpal);
async function main() {
for (let commandIndex = 0; commandIndex < commands.length; commandIndex++) {
let c = commands[commandIndex];
@ -789,6 +896,8 @@ async function main() {
let argv = process.argv;
argv = await handleStartFlags(argv);
if (argv.length) showPromptString = false;
const profileDir = initArgs.profileDir ? initArgs.profileDir : os.homedir() + '/.config/' + Setting.value('appName');
const resourceDir = profileDir + '/resources';
@ -799,13 +908,13 @@ async function main() {
await fs.mkdirp(resourceDir, 0o755);
logger.addTarget('file', { path: profileDir + '/log.txt' });
logger.setLevel(Logger.LEVEL_DEBUG);
logger.setLevel(logLevel);
dbLogger.addTarget('file', { path: profileDir + '/log-database.txt' });
dbLogger.setLevel(Logger.LEVEL_DEBUG);
dbLogger.setLevel(logLevel);
syncLogger.addTarget('file', { path: profileDir + '/log-sync.txt' });
syncLogger.setLevel(Logger.LEVEL_DEBUG);
syncLogger.setLevel(logLevel);
logger.info(sprintf('Starting %s %s...', packageJson.name, packageJson.version));
logger.info('Profile directory: ' + profileDir);
@ -826,13 +935,15 @@ async function main() {
// If we still have arguments, pass it to Vorpal and exit
if (argv.length) {
vorpal.show();
let cmd = shellArgsToString(argv);
await vorpal.exec(cmd);
await vorpal.exec('exit');
return;
} else {
vorpal.delimiter(promptString());
vorpal.show();
vorpal.history(Setting.value('appId')); // Enables persistent history
vorpal.delimiter(promptString()).show();
if (!activeFolder) {
vorpal.log(_('No notebook is defined. Create one with `mkbook <notebook>`.'));
}

View File

@ -0,0 +1,82 @@
import { time } from 'lib/time-utils.js';
const vorpalUtils = {};
let vorpal_ = null;
let redrawStarted_ = false;
let redrawLastUpdateTime_ = time.unixMs();
let redrawLastLog_ = null;
let redrawEnabled_ = true;
let errorStackTraceEnabled_ = false;
function initialize(vorpal) {
vorpal_ = vorpal;
}
function setRedrawEnabled(v) {
redrawEnabled_ = v;
}
function setStackTraceEnabled(v) {
errorStackTraceEnabled_ = v;
}
function redraw(s) {
if (!redrawEnabled_) {
const now = time.unixMs();
if (now - redrawLastUpdateTime_ > 1000) {
if (vorpal_.activeCommand) {
vorpal_.activeCommand.log(s);
} else {
vorpal_.log(s);
}
redrawLastUpdateTime_ = now;
redrawLastLog_ = null;
} else {
redrawLastLog_ = s;
}
} else {
vorpal_.ui.redraw(s);
}
redrawStarted_ = true;
}
function redrawDone() {
if (!redrawStarted_) return;
if (!redrawEnabled_) {
if (redrawLastLog_) {
if (vorpal_.activeCommand) {
vorpal_.activeCommand.log(redrawLastLog_);
} else {
vorpal_.log(redrawLastLog_);
}
}
} else {
vorpal_.ui.redraw.done();
}
redrawStarted_ = false;
}
function log(commandInstance, o) {
if (errorStackTraceEnabled_) {
commandInstance.log(o);
} else {
if (o instanceof Error) {
commandInstance.log(o.message);
} else {
commandInstance.log(o);
}
}
}
vorpalUtils.initialize = initialize;
vorpalUtils.redraw = redraw;
vorpalUtils.redrawDone = redrawDone;
vorpalUtils.setRedrawEnabled = setRedrawEnabled;
vorpalUtils.setStackTraceEnabled = setStackTraceEnabled;
vorpalUtils.log = log;
export { vorpalUtils };

View File

@ -31,6 +31,7 @@
"sqlite3": "^3.1.8",
"string-to-stream": "^1.1.0",
"tcp-port-used": "^0.1.2",
"temp": "^0.8.3",
"uuid": "^3.0.1",
"vorpal": "^1.12.0"
},

View File

@ -1,6 +1,6 @@
#!/bin/bash
set -e
CLIENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/Temp/TestNotes2 "$@"
bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/Temp/TestNotes2 --stack-trace-enabled --redraw-disabled "$@"
#bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/Temp/TestNotes import-enex --fuzzy-matching /home/laurent/Desktop/afaire.enex afaire
#bash $CLIENT_DIR/build.sh && NODE_PATH="$CLIENT_DIR/build/" node build/main.js --profile ~/Temp/TestNotes import-enex --fuzzy-matching /home/laurent/Desktop/Laurent.enex laurent

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,29 @@
{
"name": "AwesomeProject",
"displayName": "AwesomeProject"
"displayName": "AwesomeProject",
"expo": {
"name": "AwesomeProject",
"description": "No description",
"slug": "AwesomeProject",
"privacy": "public",
"sdkVersion": "18.0.0",
"version": "1.0.0",
"orientation": "portrait",
"primaryColor": "#cccccc",
"icon": "./assets/icons/app-icon.png",
"notification": {
"icon": "./assets/icons/notification-icon.png",
"color": "#000000"
},
"loading": {
"icon": "./assets/icons/loading-icon.png",
"hideExponentText": false
},
"packagerOpts": {
"assetExts": ["ttf"]
},
"ios": {
"supportsTablet": true
}
}
}

View File

@ -8,7 +8,7 @@
import { AppRegistry } from 'react-native';
import { Log } from 'lib/log.js'
import { Root } from 'lib/root.js';
import { Root } from 'app/root.js';
function main() {
AppRegistry.registerComponent('AwesomeProject', () => Root);

View File

@ -11,19 +11,19 @@ import { Note } from 'lib/models/note.js'
import { Folder } from 'lib/models/folder.js'
import { BaseModel } from 'lib/base-model.js'
import { Database } from 'lib/database.js'
import { ItemList } from 'lib/components/item-list.js'
import { NotesScreen } from 'lib/components/screens/notes.js'
import { NoteScreen } from 'lib/components/screens/note.js'
import { FolderScreen } from 'lib/components/screens/folder.js'
import { FoldersScreen } from 'lib/components/screens/folders.js'
import { LoginScreen } from 'lib/components/screens/login.js'
import { LoadingScreen } from 'lib/components/screens/loading.js'
import { ItemList } from 'app/components/item-list.js'
import { NotesScreen } from 'app/components/screens/notes.js'
import { NoteScreen } from 'app/components/screens/note.js'
import { FolderScreen } from 'app/components/screens/folder.js'
import { FoldersScreen } from 'app/components/screens/folders.js'
import { LoginScreen } from 'app/components/screens/login.js'
import { LoadingScreen } from 'app/components/screens/loading.js'
import { Setting } from 'lib/models/setting.js'
import { Synchronizer } from 'lib/synchronizer.js'
import { MenuContext } from 'react-native-popup-menu';
import { SideMenu } from 'lib/components/side-menu.js';
import { SideMenuContent } from 'lib/components/side-menu-content.js';
import { NoteFolderService } from 'lib/services/note-folder-service.js';
import { SideMenu } from 'app/components/side-menu.js';
import { SideMenuContent } from 'app/components/side-menu-content.js';
//import { NoteFolderService } from 'lib/services/note-folder-service.js';
import { DatabaseDriverReactNative } from 'lib/database-driver-react-native';
let defaultState = {
@ -194,7 +194,7 @@ class AppComponent extends React.Component {
BaseModel.dispatch = this.props.dispatch;
BaseModel.db_ = db;
NoteFolderService.dispatch = this.props.dispatch;
//NoteFolderService.dispatch = this.props.dispatch;
db.open({ name: '/storage/emulated/0/Download/joplin-42.sqlite' }).then(() => {
Log.info('Database is ready.');
@ -242,7 +242,7 @@ class AppComponent extends React.Component {
if (!folder) throw new Error('No default folder is defined');
return NoteFolderService.openNoteList(folder.id);
//return NoteFolderService.openNoteList(folder.id);
// this.props.dispatch({
// type: 'Navigation/NAVIGATE',

View File

@ -1,3 +1,3 @@
import { main } from 'lib/main.js';
import { main } from 'app/main.js';
main();

1
ReactNativeClient/lib Symbolic link
View File

@ -0,0 +1 @@
../lib

View File

@ -1,5 +1,6 @@
import moment from 'moment';
import fs from 'fs-extra';
import { _ } from 'lib/locale.js';
class Logger {
@ -100,6 +101,15 @@ class Logger {
info(object) { return this.log(Logger.LEVEL_INFO, object); }
debug(object) { return this.log(Logger.LEVEL_DEBUG, object); }
static levelStringToId(s) {
if (s == 'none') return Logger.LEVEL_NONE;
if (s == 'error') return Logger.LEVEL_ERROR;
if (s == 'warn') return Logger.LEVEL_WARN;
if (s == 'info') return Logger.LEVEL_INFO;
if (s == 'debug') return Logger.LEVEL_DEBUG;
throw new Error(_('Unknown log level: %s', s));
}
}
Logger.LEVEL_NONE = 0;

View File

@ -20,6 +20,10 @@ class Note extends BaseItem {
return super.serialize(note, 'note', fieldNames);
}
static async serializeForEdit(note) {
return super.serialize(note, 'note', []);
}
static modelType() {
return BaseModel.TYPE_NOTE;
}

View File

@ -144,6 +144,7 @@ Setting.defaults_ = {
'sync.onedrive.auth': { value: '', type: 'string', public: false },
'sync.local.path': { value: '', type: 'string', public: true },
'sync.target': { value: 'onedrive', type: 'string', public: true },
'editor': { value: '', type: 'string', public: true },
};
// Contains constants that are set by the application and