2017-06-25 16:30:44 +00:00
#!/usr/bin/env node
2017-06-22 21:52:27 +00:00
require ( 'source-map-support' ) . install ( ) ;
require ( 'babel-plugin-transform-runtime' ) ;
2017-06-24 18:06:28 +00:00
import { FileApi } from 'lib/file-api.js' ;
import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js' ;
2017-06-27 18:54:12 +00:00
import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js' ;
2017-06-27 19:26:29 +00:00
import { FileApiDriverLocal } from 'lib/file-api-driver-local.js' ;
2017-07-06 18:58:01 +00:00
import { OneDriveApiNodeUtils } from './onedrive-api-node-utils.js' ;
2017-06-24 18:06:28 +00:00
import { Database } from 'lib/database.js' ;
import { DatabaseDriverNode } from 'lib/database-driver-node.js' ;
import { BaseModel } from 'lib/base-model.js' ;
import { Folder } from 'lib/models/folder.js' ;
2017-07-02 12:02:07 +00:00
import { Resource } from 'lib/models/resource.js' ;
2017-06-25 07:35:59 +00:00
import { BaseItem } from 'lib/models/base-item.js' ;
2017-06-24 18:06:28 +00:00
import { Note } from 'lib/models/note.js' ;
2017-07-03 18:58:01 +00:00
import { Tag } from 'lib/models/tag.js' ;
2017-06-24 18:06:28 +00:00
import { Setting } from 'lib/models/setting.js' ;
import { Synchronizer } from 'lib/synchronizer.js' ;
import { Logger } from 'lib/logger.js' ;
import { uuid } from 'lib/uuid.js' ;
2017-06-22 21:52:27 +00:00
import { sprintf } from 'sprintf-js' ;
2017-06-24 17:40:03 +00:00
import { importEnex } from 'import-enex' ;
2017-07-04 19:12:30 +00:00
import { vorpalUtils } from 'vorpal-utils.js' ;
2017-07-05 21:52:31 +00:00
import { FsDriverNode } from './fs-driver-node.js' ;
2017-06-25 11:39:42 +00:00
import { filename , basename } from 'lib/path-utils.js' ;
2017-06-24 18:06:28 +00:00
import { _ } from 'lib/locale.js' ;
2017-06-22 21:52:27 +00:00
import os from 'os' ;
import fs from 'fs-extra' ;
2017-06-23 21:32:24 +00:00
process . on ( 'unhandledRejection' , ( reason , p ) => {
2017-06-25 22:20:07 +00:00
console . error ( 'Unhandled promise rejection' , p , 'reason:' , reason ) ;
2017-06-23 21:32:24 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
const packageJson = require ( './package.json' ) ;
2017-06-24 17:40:03 +00:00
2017-06-27 19:26:29 +00:00
let initArgs = {
profileDir : null ,
}
2017-07-05 21:52:31 +00:00
const fsDriver = new FsDriverNode ( ) ;
Logger . fsDriver _ = fsDriver ;
Resource . fsDriver _ = fsDriver ;
2017-06-29 20:52:52 +00:00
Setting . setConstant ( 'appId' , 'net.cozic.joplin-cli' ) ;
2017-06-25 22:20:07 +00:00
let currentFolder = null ;
let commands = [ ] ;
let database _ = null ;
2017-06-27 19:26:29 +00:00
let synchronizers _ = { } ;
2017-06-25 22:20:07 +00:00
let logger = new Logger ( ) ;
let dbLogger = new Logger ( ) ;
let syncLogger = new Logger ( ) ;
2017-07-04 19:12:30 +00:00
let showPromptString = true ;
let logLevel = Logger . LEVEL _INFO ;
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'version' ,
description : 'Displays version information' ,
action : function ( args , end ) {
this . log ( packageJson . name + ' ' + packageJson . version ) ;
end ( ) ;
} ,
} ) ;
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'mkbook <notebook>' ,
aliases : [ 'mkdir' ] ,
description : 'Creates a new notebook' ,
action : function ( args , end ) {
2017-07-03 18:58:01 +00:00
Folder . save ( { title : args [ 'notebook' ] } , { duplicateCheck : true } ) . then ( ( folder ) => {
2017-06-25 22:20:07 +00:00
switchCurrentFolder ( folder ) ;
2017-06-26 23:20:01 +00:00
} ) . catch ( ( error ) => {
2017-07-04 19:12:30 +00:00
vorpalUtils . log ( this , error ) ;
2017-06-26 23:20:01 +00:00
} ) . then ( ( ) => {
2017-06-25 22:20:07 +00:00
end ( ) ;
} ) ;
} ,
} ) ;
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
2017-07-03 18:58:01 +00:00
usage : 'mknote <note>' ,
2017-06-25 22:20:07 +00:00
aliases : [ 'touch' ] ,
description : 'Creates a new note' ,
2017-07-04 19:12:30 +00:00
action : async function ( args , end ) {
2017-06-25 22:20:07 +00:00
if ( ! currentFolder ) {
this . log ( 'Notes can only be created within a notebook.' ) ;
end ( ) ;
return ;
}
2017-06-24 17:40:03 +00:00
2017-07-04 19:12:30 +00:00
let path = await parseNotePattern ( args [ 'note' ] ) ;
2017-06-25 22:20:07 +00:00
let note = {
2017-07-04 19:12:30 +00:00
title : path . title ,
parent _id : path . parent ? path . parent . id : currentFolder . id ,
2017-06-25 22:20:07 +00:00
} ;
2017-07-04 19:12:30 +00:00
try {
await Note . save ( note ) ;
} catch ( error ) {
2017-06-25 22:20:07 +00:00
this . log ( error ) ;
2017-07-04 19:12:30 +00:00
}
end ( ) ;
2017-06-25 22:20:07 +00:00
} ,
} ) ;
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'use <notebook>' ,
aliases : [ 'cd' ] ,
description : 'Switches to [notebook] - all further operations will happen within this notebook.' ,
action : async function ( args , end ) {
let folderTitle = args [ 'notebook' ] ;
2017-06-25 12:49:46 +00:00
2017-06-25 22:20:07 +00:00
let folder = await Folder . loadByField ( 'title' , folderTitle ) ;
if ( ! folder ) return cmdError ( this , _ ( 'Invalid folder title: %s' , folderTitle ) , end ) ;
switchCurrentFolder ( folder ) ;
end ( ) ;
} ,
autocomplete : autocompleteFolders ,
} ) ;
2017-06-25 12:49:46 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
2017-07-04 19:12:30 +00:00
usage : 'set <item> <name> [value]' ,
description : 'Sets the property <name> of the given <item> to the given [value].' ,
2017-07-02 10:34:07 +00:00
action : async function ( args , end ) {
try {
let promise = null ;
2017-07-04 19:12:30 +00:00
let title = args [ 'item' ] ;
2017-07-02 10:34:07 +00:00
let propName = args [ 'name' ] ;
let propValue = args [ 'value' ] ;
if ( ! propValue ) propValue = '' ;
2017-06-25 12:49:46 +00:00
2017-07-02 10:34:07 +00:00
let item = null ;
if ( ! currentFolder ) {
item = await Folder . loadByField ( 'title' , title ) ;
} else {
item = await Note . loadFolderNoteByField ( currentFolder . id , 'title' , title ) ;
}
if ( ! item ) {
item = await BaseItem . loadItemById ( title ) ;
}
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
if ( ! item ) {
this . log ( _ ( 'No item with title "%s" found.' , title ) ) ;
end ( ) ;
return ;
}
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
let newItem = {
id : item . id ,
type _ : item . type _ ,
} ;
newItem [ propName ] = propValue ;
2017-06-27 19:48:01 +00:00
let ItemClass = BaseItem . itemClass ( newItem ) ;
2017-07-02 10:34:07 +00:00
await ItemClass . save ( newItem ) ;
} catch ( error ) {
2017-06-25 22:20:07 +00:00
this . log ( error ) ;
2017-07-02 10:34:07 +00:00
}
end ( ) ;
2017-06-25 22:20:07 +00:00
} ,
autocomplete : autocompleteItems ,
} ) ;
2017-06-24 17:40:03 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
2017-07-02 10:34:07 +00:00
usage : 'cat <title>' ,
2017-06-25 22:20:07 +00:00
description : 'Displays the given item data.' ,
2017-07-02 15:46:03 +00:00
action : async function ( args , end ) {
try {
let title = args [ 'title' ] ;
2017-06-22 21:52:27 +00:00
2017-07-02 15:46:03 +00:00
let item = null ;
if ( ! currentFolder ) {
item = await Folder . loadByField ( 'title' , title ) ;
} else {
item = await Note . loadFolderNoteByField ( currentFolder . id , 'title' , title ) ;
}
2017-06-22 21:52:27 +00:00
2017-06-25 22:20:07 +00:00
if ( ! item ) {
this . log ( _ ( 'No item with title "%s" found.' , title ) ) ;
end ( ) ;
return ;
}
2017-06-22 21:52:27 +00:00
2017-07-02 15:46:03 +00:00
let content = null ;
2017-06-25 22:20:07 +00:00
if ( ! currentFolder ) {
2017-07-02 15:46:03 +00:00
content = await Folder . serialize ( item ) ;
2017-06-25 22:20:07 +00:00
} else {
2017-07-02 15:46:03 +00:00
content = await Note . serialize ( item ) ;
2017-06-25 22:20:07 +00:00
}
2017-07-02 15:46:03 +00:00
this . log ( content ) ;
} catch ( error ) {
2017-06-25 22:20:07 +00:00
this . log ( error ) ;
2017-07-02 15:46:03 +00:00
}
end ( ) ;
2017-06-25 22:20:07 +00:00
} ,
autocomplete : autocompleteItems ,
} ) ;
2017-06-22 21:52:27 +00:00
2017-07-04 19:12:30 +00:00
commands . push ( {
usage : 'edit <title>' ,
description : 'Edit note.' ,
action : async function ( args , end ) {
2017-07-05 18:31:11 +00:00
let watcher = null ;
const onFinishedEditing = ( ) => {
if ( watcher ) watcher . close ( ) ;
vorpal . show ( ) ;
this . log ( _ ( 'Done editing.' ) ) ;
end ( ) ;
}
try {
2017-07-04 19:12:30 +00:00
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 ( ' ' ) ;
2017-07-05 18:31:11 +00:00
2017-07-04 19:12:30 +00:00
editorPath = editorArgs [ 0 ] ;
2017-07-05 18:31:11 +00:00
editorArgs = editorArgs . splice ( 1 ) ;
2017-07-04 19:12:30 +00:00
let content = await Note . serializeForEdit ( note ) ;
2017-07-05 18:31:11 +00:00
let tempFilePath = Setting . value ( 'profileDir' ) + '/tmp/' + Note . systemPath ( note ) ;
editorArgs . push ( tempFilePath ) ;
2017-07-04 19:12:30 +00:00
const spawn = require ( 'child_process' ) . spawn ;
2017-07-05 18:31:11 +00:00
this . log ( _ ( 'Starting to edit note. Close the editor to get back to the prompt.' ) ) ;
2017-07-04 19:12:30 +00:00
vorpal . hide ( ) ;
2017-07-05 18:31:11 +00:00
await fs . writeFile ( tempFilePath , content ) ;
2017-07-04 19:12:30 +00:00
2017-07-05 18:31:11 +00:00
let watchTimeout = null ;
watcher = fs . watch ( tempFilePath , ( eventType , filename ) => {
// We need a timeout because for each change to the file, multiple events are generated.
2017-07-04 19:12:30 +00:00
2017-07-05 18:31:11 +00:00
if ( watchTimeout ) return ;
2017-07-04 19:12:30 +00:00
2017-07-05 18:31:11 +00:00
watchTimeout = setTimeout ( async ( ) => {
let updatedNote = await fs . readFile ( tempFilePath , 'utf8' ) ;
updatedNote = await Note . unserializeForEdit ( updatedNote ) ;
updatedNote . id = note . id ;
await Note . save ( updatedNote ) ;
watchTimeout = null ;
} , 200 ) ;
} ) ;
2017-07-04 19:12:30 +00:00
2017-07-05 18:31:11 +00:00
const childProcess = spawn ( editorPath , editorArgs , { stdio : 'inherit' } ) ;
childProcess . on ( 'exit' , ( error , code ) => {
onFinishedEditing ( ) ;
2017-07-04 19:12:30 +00:00
} ) ;
} catch ( error ) {
this . log ( error ) ;
2017-07-05 18:31:11 +00:00
onFinishedEditing ( ) ;
2017-07-04 19:12:30 +00:00
}
} ,
autocomplete : autocompleteItems ,
} ) ;
2017-06-25 22:20:07 +00:00
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.' ,
2017-06-30 22:53:22 +00:00
options : [
[ '-f, --force' , 'Deletes the items without asking for confirmation.' ] ,
] ,
2017-06-25 22:20:07 +00:00
action : async function ( args , end ) {
2017-06-26 23:20:01 +00:00
try {
let pattern = args [ 'pattern' ] ;
let itemType = null ;
2017-06-30 22:53:22 +00:00
let force = args . options && args . options . force === true ;
2017-06-26 23:20:01 +00:00
if ( pattern . indexOf ( '*' ) < 0 ) { // Handle it as a simple title
if ( pattern . substr ( 0 , 3 ) == '../' ) {
2017-07-03 19:50:45 +00:00
itemType = BaseModel . TYPE _FOLDER ;
2017-06-26 23:20:01 +00:00
pattern = pattern . substr ( 3 ) ;
} else {
2017-07-03 19:50:45 +00:00
itemType = BaseModel . TYPE _NOTE ;
2017-06-26 23:20:01 +00:00
}
2017-06-22 21:52:27 +00:00
2017-06-26 23:20:01 +00:00
let item = await BaseItem . loadItemByField ( itemType , 'title' , pattern ) ;
if ( ! item ) throw new Error ( _ ( 'No item with title "%s" found.' , pattern ) ) ;
2017-06-22 21:52:27 +00:00
2017-06-30 22:53:22 +00:00
let ok = force ? true : await cmdPromptConfirm ( this , _ ( 'Delete item?' ) ) ;
if ( ok ) {
await BaseItem . deleteItem ( itemType , item . id ) ;
if ( currentFolder && currentFolder . id == item . id ) {
let f = await Folder . defaultFolder ( ) ;
switchCurrentFolder ( f ) ;
}
2017-06-26 23:20:01 +00:00
}
} else { // Handle it as a glob pattern
2017-07-01 15:07:17 +00:00
if ( currentFolder ) {
let notes = await Note . previews ( currentFolder . id , { titlePattern : pattern } ) ;
if ( ! notes . length ) throw new Error ( _ ( 'No note matches this pattern: "%s"' , pattern ) ) ;
let ok = force ? true : await cmdPromptConfirm ( this , _ ( '%d notes match this pattern. Delete them?' , notes . length ) ) ;
if ( ok ) {
for ( let i = 0 ; i < notes . length ; i ++ ) {
await Note . delete ( notes [ i ] . id ) ;
}
2017-06-26 23:20:01 +00:00
}
2017-06-25 22:20:07 +00:00
}
}
2017-06-26 23:20:01 +00:00
} catch ( error ) {
this . log ( error ) ;
2017-06-22 21:52:27 +00:00
}
2017-06-25 22:20:07 +00:00
end ( ) ;
} ,
autocomplete : autocompleteItems ,
} ) ;
2017-06-23 21:32:24 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'mv <pattern> <notebook>' ,
description : 'Moves the notes matching <pattern> to <notebook>.' ,
action : async function ( args , end ) {
2017-06-26 23:20:01 +00:00
try {
2017-07-01 15:07:17 +00:00
if ( ! currentFolder ) throw new Error ( _ ( 'Please select a notebook first.' ) ) ;
2017-06-26 23:20:01 +00:00
let pattern = args [ 'pattern' ] ;
2017-06-25 10:41:03 +00:00
2017-06-26 23:20:01 +00:00
let folder = await Folder . loadByField ( 'title' , args [ 'notebook' ] ) ;
if ( ! folder ) throw new Error ( _ ( 'No folder with title "%s"' , args [ 'notebook' ] ) ) ;
let notes = await Note . previews ( currentFolder . id , { titlePattern : pattern } ) ;
if ( ! notes . length ) throw new Error ( _ ( 'No note matches this pattern: "%s"' , pattern ) ) ;
2017-06-22 21:52:27 +00:00
2017-06-26 23:20:01 +00:00
for ( let i = 0 ; i < notes . length ; i ++ ) {
await Note . save ( { id : notes [ i ] . id , parent _id : folder . id } ) ;
}
} catch ( error ) {
this . log ( error ) ;
2017-06-22 21:52:27 +00:00
}
2017-06-25 22:20:07 +00:00
end ( ) ;
} ,
autocomplete : autocompleteItems ,
} ) ;
2017-06-22 21:52:27 +00:00
2017-07-03 18:58:01 +00:00
commands . push ( {
usage : 'tag <command> [tag] [note]' ,
description : '<command> can be "add", "remove" or "list" to assign or remove [tag] from [note], or to list the notes associated with [tag]. The command `tag list` can be used to list all the tags.' ,
action : async function ( args , end ) {
try {
let tag = null ;
2017-07-03 19:50:45 +00:00
if ( args . tag ) tag = await loadItem ( BaseModel . TYPE _TAG , args . tag ) ;
2017-07-03 18:58:01 +00:00
let note = null ;
2017-07-03 19:50:45 +00:00
if ( args . note ) note = await loadItem ( BaseModel . TYPE _NOTE , args . note ) ;
2017-07-03 18:58:01 +00:00
if ( args . command == 'remove' && ! tag ) throw new Error ( _ ( 'Tag does not exist: "%s"' , args . tag ) ) ;
if ( args . command == 'add' ) {
if ( ! note ) throw new Error ( _ ( 'Note does not exist: "%s"' , args . note ) ) ;
if ( ! tag ) tag = await Tag . save ( { title : args . tag } ) ;
await Tag . addNote ( tag . id , note . id ) ;
} else if ( args . command == 'remove' ) {
if ( ! tag ) throw new Error ( _ ( 'Tag does not exist: "%s"' , args . tag ) ) ;
if ( ! note ) throw new Error ( _ ( 'Note does not exist: "%s"' , args . note ) ) ;
await Tag . removeNote ( tag . id , note . id ) ;
} else if ( args . command == 'list' ) {
if ( tag ) {
let notes = await Tag . notes ( tag . id ) ;
notes . map ( ( note ) => { this . log ( note . title ) ; } ) ;
} else {
let tags = await Tag . all ( ) ;
tags . map ( ( tag ) => { this . log ( tag . title ) ; } ) ;
}
} else {
throw new Error ( _ ( 'Invalid command: "%s"' , args . command ) ) ;
}
} catch ( error ) {
this . log ( error ) ;
}
end ( ) ;
}
} ) ;
2017-06-30 22:53:22 +00:00
commands . push ( {
usage : 'dump' ,
description : 'Dumps the complete database as JSON.' ,
action : async function ( args , end ) {
try {
let items = [ ] ;
let folders = await Folder . all ( ) ;
for ( let i = 0 ; i < folders . length ; i ++ ) {
let folder = folders [ i ] ;
let notes = await Note . previews ( folder . id ) ;
items . push ( folder ) ;
items = items . concat ( notes ) ;
}
2017-07-03 18:58:01 +00:00
let tags = await Tag . all ( ) ;
for ( let i = 0 ; i < tags . length ; i ++ ) {
tags [ i ] . notes _ = await Tag . tagNoteIds ( tags [ i ] . id ) ;
}
items = items . concat ( tags ) ;
2017-06-30 22:53:22 +00:00
this . log ( JSON . stringify ( items ) ) ;
} catch ( error ) {
this . log ( error ) ;
}
end ( ) ;
2017-07-03 18:58:01 +00:00
}
2017-06-30 22:53:22 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'ls [pattern]' ,
description : 'Displays the notes in [notebook]. Use `ls ..` to display the list of notebooks.' ,
options : [
[ '-n, --lines <num>' , 'Displays only the first top <num> lines.' ] ,
[ '-s, --sort <field>' , 'Sorts the item by <field> (eg. title, updated_time, created_time).' ] ,
[ '-r, --reverse' , 'Reverses the sorting order.' ] ,
[ '-t, --type <type>' , 'Displays only the items of the specific type(s). Can be `n` for notes, `t` for todos, or `nt` for notes and todos (eg. `-tt` would display only the todos, while `-ttd` would display notes and todos.' ] ,
2017-06-30 22:53:22 +00:00
[ '-f, --format <format>' , 'Either "text" or "json"' ] ,
2017-06-25 22:20:07 +00:00
] ,
action : async function ( args , end ) {
2017-06-26 23:20:01 +00:00
try {
let pattern = args [ 'pattern' ] ;
let suffix = '' ;
let items = [ ] ;
let options = args . options ;
let queryOptions = { } ;
if ( options . lines ) queryOptions . limit = options . lines ;
if ( options . sort ) {
queryOptions . orderBy = options . sort ;
queryOptions . orderByDir = 'ASC' ;
}
if ( options . reverse === true ) queryOptions . orderByDir = queryOptions . orderByDir == 'ASC' ? 'DESC' : 'ASC' ;
queryOptions . caseInsensitive = true ;
if ( options . type ) {
queryOptions . itemTypes = [ ] ;
if ( options . type . indexOf ( 'n' ) >= 0 ) queryOptions . itemTypes . push ( 'note' ) ;
if ( options . type . indexOf ( 't' ) >= 0 ) queryOptions . itemTypes . push ( 'todo' ) ;
}
if ( pattern ) queryOptions . titlePattern = pattern ;
2017-06-22 21:52:27 +00:00
2017-07-01 15:07:17 +00:00
if ( pattern == '..' || ! currentFolder ) {
2017-06-26 23:20:01 +00:00
items = await Folder . all ( queryOptions ) ;
suffix = '/' ;
} else {
2017-07-01 15:07:17 +00:00
if ( ! currentFolder ) throw new Error ( _ ( 'Please select a notebook first.' ) ) ;
2017-06-26 23:20:01 +00:00
items = await Note . previews ( currentFolder . id , queryOptions ) ;
}
2017-06-22 21:52:27 +00:00
2017-06-30 22:53:22 +00:00
if ( options . format && options . format == 'json' ) {
this . log ( JSON . stringify ( items ) ) ;
} else {
for ( let i = 0 ; i < items . length ; i ++ ) {
let item = items [ i ] ;
let line = '' ;
if ( ! ! item . is _todo ) {
line += sprintf ( '[%s] ' , ! ! item . todo _completed ? 'X' : ' ' ) ;
}
line += item . title + suffix ;
this . log ( line ) ;
2017-06-26 23:20:01 +00:00
}
2017-06-22 21:52:27 +00:00
}
2017-06-27 20:16:03 +00:00
} catch ( error ) {
2017-06-26 23:20:01 +00:00
this . log ( error ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-22 21:52:27 +00:00
2017-06-25 07:35:59 +00:00
end ( ) ;
2017-06-25 22:20:07 +00:00
} ,
autocomplete : autocompleteFolders ,
} ) ;
2017-06-25 07:35:59 +00:00
2017-06-27 20:01:31 +00:00
commands . push ( {
usage : 'config [name] [value]' ,
description : 'Gets or sets a config value. If [value] is not provided, it will show the value of [name]. If neither [name] nor [value] is provided, it will list the current configuration.' ,
2017-06-30 15:33:40 +00:00
action : async function ( args , end ) {
2017-06-27 20:01:31 +00:00
try {
if ( ! args . name && ! args . value ) {
let keys = Setting . publicKeys ( ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
this . log ( keys [ i ] + ' = ' + Setting . value ( keys [ i ] ) ) ;
}
} else if ( args . name && ! args . value ) {
this . log ( args . name + ' = ' + Setting . value ( args . name ) ) ;
} else {
Setting . setValue ( args . name , args . value ) ;
2017-06-30 15:33:40 +00:00
await Setting . saveAll ( ) ;
2017-06-27 20:01:31 +00:00
}
} catch ( error ) {
this . log ( error ) ;
}
end ( ) ;
} ,
} ) ;
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'sync' ,
description : 'Synchronizes with remote storage.' ,
2017-07-02 10:34:07 +00:00
options : [
[ '--random-failures' , 'For debugging purposes. Do not use.' ] ,
] ,
2017-06-25 22:20:07 +00:00
action : function ( args , end ) {
2017-06-30 17:54:01 +00:00
let options = {
onProgress : ( report ) => {
let line = [ ] ;
if ( report . remotesToUpdate ) line . push ( _ ( 'Items to upload: %d/%d.' , report . createRemote + report . updateRemote , report . remotesToUpdate ) ) ;
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 ) ) ;
2017-07-04 19:12:30 +00:00
vorpalUtils . redraw ( line . join ( ' ' ) ) ;
2017-06-30 17:54:01 +00:00
} ,
onMessage : ( msg ) => {
2017-07-04 19:12:30 +00:00
vorpalUtils . redrawDone ( ) ;
2017-06-30 17:54:01 +00:00
this . log ( msg ) ;
} ,
2017-07-02 10:34:07 +00:00
randomFailures : args . options [ 'random-failures' ] === true ,
2017-06-30 17:54:01 +00:00
} ;
2017-06-27 19:26:29 +00:00
this . log ( _ ( 'Synchronization target: %s' , Setting . value ( 'sync.target' ) ) ) ;
synchronizer ( Setting . value ( 'sync.target' ) ) . then ( ( s ) => {
2017-06-30 17:54:01 +00:00
this . log ( _ ( 'Starting synchronization...' ) ) ;
return s . start ( options ) ;
2017-06-25 22:20:07 +00:00
} ) . catch ( ( error ) => {
2017-06-27 19:26:29 +00:00
this . log ( error ) ;
2017-06-25 22:20:07 +00:00
} ) . then ( ( ) => {
2017-07-04 19:12:30 +00:00
vorpalUtils . redrawDone ( ) ;
2017-06-30 17:54:01 +00:00
this . log ( _ ( 'Done.' ) ) ;
2017-06-25 22:20:07 +00:00
end ( ) ;
2017-06-25 11:39:42 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
} ,
} ) ;
2017-06-25 11:39:42 +00:00
2017-06-25 22:20:07 +00:00
commands . push ( {
usage : 'import-enex <file> [notebook]' ,
2017-06-29 20:52:52 +00:00
description : _ ( 'Imports an Evernote notebook file (.enex file).' ) ,
2017-06-25 22:20:07 +00:00
options : [
[ '--fuzzy-matching' , 'For debugging purposes. Do not use.' ] ,
] ,
action : async function ( args , end ) {
2017-06-26 23:20:01 +00:00
try {
let filePath = args . file ;
let folder = null ;
let folderTitle = args [ 'notebook' ] ;
if ( folderTitle ) {
folder = await Folder . loadByField ( 'title' , folderTitle ) ;
2017-06-27 20:53:40 +00:00
if ( ! folder ) {
let ok = await cmdPromptConfirm ( this , _ ( 'Folder does not exists: "%s". Create it?' , folderTitle ) )
if ( ! ok ) {
end ( ) ;
return ;
}
folder = await Folder . save ( { title : folderTitle } ) ;
}
2017-06-26 23:20:01 +00:00
} else {
folderTitle = filename ( filePath ) ;
folderTitle = _ ( 'Imported - %s' , folderTitle ) ;
let inc = 0 ;
while ( true ) {
let t = folderTitle + ( inc ? ' (' + inc + ')' : '' ) ;
let f = await Folder . loadByField ( 'title' , t ) ;
if ( ! f ) {
folderTitle = t ;
break ;
}
inc ++ ;
2017-06-25 22:20:07 +00:00
}
}
2017-06-22 21:52:27 +00:00
2017-06-26 23:20:01 +00:00
let ok = await cmdPromptConfirm ( this , _ ( 'File "%s" will be imported into notebook "%s". Continue?' , basename ( filePath ) , folderTitle ) )
2017-06-25 22:20:07 +00:00
2017-06-26 23:20:01 +00:00
if ( ! ok ) {
end ( ) ;
return ;
}
2017-06-22 21:52:27 +00:00
2017-06-26 23:20:01 +00:00
let options = {
fuzzyMatching : args . options [ 'fuzzy-matching' ] === true ,
onProgress : ( progressState ) => {
let line = [ ] ;
line . push ( _ ( 'Found: %d.' , progressState . loaded ) ) ;
line . push ( _ ( 'Created: %d.' , progressState . created ) ) ;
if ( progressState . updated ) line . push ( _ ( 'Updated: %d.' , progressState . updated ) ) ;
if ( progressState . skipped ) line . push ( _ ( 'Skipped: %d.' , progressState . skipped ) ) ;
if ( progressState . resourcesCreated ) line . push ( _ ( 'Resources: %d.' , progressState . resourcesCreated ) ) ;
2017-07-02 15:46:03 +00:00
if ( progressState . notesTagged ) line . push ( _ ( 'Tagged: %d.' , progressState . notesTagged ) ) ;
2017-07-04 19:12:30 +00:00
vorpalUtils . redraw ( line . join ( ' ' ) ) ;
2017-06-26 23:20:01 +00:00
} ,
onError : ( error ) => {
2017-07-04 19:12:30 +00:00
vorpalUtils . redrawDone ( ) ;
2017-06-26 23:20:01 +00:00
let s = error . trace ? error . trace : error . toString ( ) ;
this . log ( s ) ;
} ,
}
2017-06-22 21:52:27 +00:00
2017-06-26 23:20:01 +00:00
folder = ! folder ? await Folder . save ( { title : folderTitle } ) : folder ;
this . log ( _ ( 'Importing notes...' ) ) ;
await importEnex ( folder . id , filePath , options ) ;
} catch ( error ) {
this . log ( error ) ;
}
2017-06-22 21:52:27 +00:00
2017-07-04 19:12:30 +00:00
vorpalUtils . redrawDone ( ) ;
2017-06-29 21:04:11 +00:00
2017-06-25 22:20:07 +00:00
end ( ) ;
} ,
} ) ;
2017-06-22 21:52:27 +00:00
2017-07-04 19:12:30 +00:00
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 ,
} ;
}
}
2017-07-03 18:58:01 +00:00
async function loadItem ( type , pattern ) {
let output = await loadItems ( type , pattern ) ;
return output . length ? output [ 0 ] : null ;
}
async function loadItems ( type , pattern ) {
let ItemClass = BaseItem . itemClass ( type ) ;
let item = await ItemClass . loadByTitle ( pattern ) ;
if ( item ) return [ item ] ;
item = await ItemClass . load ( pattern ) ;
return [ item ] ;
}
2017-06-25 22:20:07 +00:00
function commandByName ( name ) {
for ( let i = 0 ; i < commands . length ; i ++ ) {
let c = commands [ i ] ;
let n = c . usage . split ( ' ' ) ;
2017-06-29 18:03:16 +00:00
n = n [ 0 ] . trim ( ) ;
2017-06-25 22:20:07 +00:00
if ( n == name ) return c ;
if ( c . aliases && c . aliases . indexOf ( name ) >= 0 ) return c ;
}
return null ;
}
2017-06-25 10:41:03 +00:00
2017-06-25 22:20:07 +00:00
function execCommand ( name , args ) {
return new Promise ( ( resolve , reject ) => {
let cmd = commandByName ( name ) ;
if ( ! cmd ) {
reject ( new Error ( 'Unknown command: ' + name ) ) ;
} else {
cmd . action ( args , function ( ) {
resolve ( ) ;
} ) ;
}
2017-06-25 10:41:03 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-25 10:41:03 +00:00
2017-06-27 19:26:29 +00:00
async function synchronizer ( syncTarget ) {
if ( synchronizers _ [ syncTarget ] ) return synchronizers _ [ syncTarget ] ;
2017-06-22 21:52:27 +00:00
2017-06-25 22:20:07 +00:00
let fileApi = null ;
2017-06-22 21:52:27 +00:00
2017-06-27 19:26:29 +00:00
if ( syncTarget == 'onedrive' ) {
2017-07-06 19:29:09 +00:00
let oneDriveApi = oneDriveApi . instance ( ) ;
// const CLIENT_ID = 'e09fc0de-c958-424f-83a2-e56a721d331b';
// const CLIENT_SECRET = 'JA3cwsqSGHFtjMwd5XoF5L5';
2017-06-22 21:52:27 +00:00
2017-07-06 19:29:09 +00:00
//let driver = new FileApiDriverOneDrive(CLIENT_ID, CLIENT_SECRET);
let driver = new FileApiDriverOneDrive ( oneDriveApi ) ;
2017-06-25 22:20:07 +00:00
let auth = Setting . value ( 'sync.onedrive.auth' ) ;
if ( auth ) {
auth = JSON . parse ( auth ) ;
} else {
2017-07-06 19:29:09 +00:00
const oneDriveApiUtils = new OneDriveApiNodeUtils ( oneDriveApi ) ;
2017-07-06 18:58:01 +00:00
auth = await oneDriveApiUtils . oauthDance ( vorpal ) ;
2017-06-25 22:20:07 +00:00
Setting . setValue ( 'sync.onedrive.auth' , JSON . stringify ( auth ) ) ;
}
2017-06-22 21:52:27 +00:00
2017-07-06 19:29:09 +00:00
//oneDriveApi.setAuth(auth);
oneDriveApi . on ( 'authRefreshed' , ( a ) => {
2017-06-25 22:20:07 +00:00
Setting . setValue ( 'sync.onedrive.auth' , JSON . stringify ( a ) ) ;
} ) ;
2017-06-22 21:52:27 +00:00
2017-07-06 19:29:09 +00:00
let appDir = await oneDriveApi . appDirectory ( ) ;
2017-06-25 22:20:07 +00:00
logger . info ( 'App dir: ' + appDir ) ;
fileApi = new FileApi ( appDir , driver ) ;
fileApi . setLogger ( logger ) ;
2017-06-27 19:26:29 +00:00
} else if ( syncTarget == 'memory' ) {
fileApi = new FileApi ( 'joplin' , new FileApiDriverMemory ( ) ) ;
fileApi . setLogger ( logger ) ;
} else if ( syncTarget == 'local' ) {
2017-06-30 15:33:40 +00:00
let syncDir = Setting . value ( 'sync.local.path' ) ;
if ( ! syncDir ) syncDir = Setting . value ( 'profileDir' ) + '/sync' ;
vorpal . log ( _ ( 'Synchronizing with directory "%s"' , syncDir ) ) ;
2017-06-27 19:26:29 +00:00
await fs . mkdirp ( syncDir , 0o755 ) ;
fileApi = new FileApi ( syncDir , new FileApiDriverLocal ( ) ) ;
2017-06-27 18:54:12 +00:00
fileApi . setLogger ( logger ) ;
2017-06-25 22:20:07 +00:00
} else {
2017-06-27 19:26:29 +00:00
throw new Error ( 'Unknown backend: ' + syncTarget ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-22 21:52:27 +00:00
2017-06-27 19:26:29 +00:00
synchronizers _ [ syncTarget ] = new Synchronizer ( database _ , fileApi ) ;
synchronizers _ [ syncTarget ] . setLogger ( syncLogger ) ;
2017-06-22 21:52:27 +00:00
2017-06-27 19:26:29 +00:00
return synchronizers _ [ syncTarget ] ;
2017-06-25 22:20:07 +00:00
}
2017-06-25 07:52:25 +00:00
2017-06-25 22:20:07 +00:00
function switchCurrentFolder ( folder ) {
currentFolder = folder ;
2017-07-01 15:07:17 +00:00
Setting . setValue ( 'activeFolderId' , folder ? folder . id : '' ) ;
2017-06-25 22:20:07 +00:00
updatePrompt ( ) ;
}
2017-06-22 21:52:27 +00:00
2017-06-25 22:20:07 +00:00
function promptString ( ) {
2017-07-04 19:12:30 +00:00
if ( ! showPromptString ) return '' ;
2017-06-25 22:20:07 +00:00
let path = '~' ;
if ( currentFolder ) {
path += '/' + currentFolder . title ;
}
2017-07-04 19:12:30 +00:00
return Setting . value ( 'appName' ) + ':' + path + '$ ' ;
2017-06-25 22:20:07 +00:00
}
2017-06-25 14:40:42 +00:00
2017-06-25 22:20:07 +00:00
function updatePrompt ( ) {
vorpal . delimiter ( promptString ( ) ) ;
}
2017-06-25 14:40:42 +00:00
2017-06-25 22:20:07 +00:00
// For now, to go around this issue: https://github.com/dthree/vorpal/issues/114
function quotePromptArg ( s ) {
if ( s . indexOf ( ' ' ) >= 0 ) {
return '"' + s + '"' ;
}
return s ;
}
2017-06-25 14:40:42 +00:00
2017-06-25 22:20:07 +00:00
function autocompleteFolders ( ) {
return Folder . all ( ) . then ( ( folders ) => {
let output = [ ] ;
for ( let i = 0 ; i < folders . length ; i ++ ) {
output . push ( quotePromptArg ( folders [ i ] . title ) ) ;
}
output . push ( '..' ) ;
output . push ( '.' ) ;
return output ;
2017-06-25 14:40:42 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-25 14:40:42 +00:00
2017-06-25 22:20:07 +00:00
function autocompleteItems ( ) {
let promise = null ;
if ( ! currentFolder ) {
promise = Folder . all ( ) ;
} else {
promise = Note . previews ( currentFolder . id ) ;
}
2017-06-25 07:35:59 +00:00
2017-06-25 22:20:07 +00:00
return promise . then ( ( items ) => {
let output = [ ] ;
for ( let i = 0 ; i < items . length ; i ++ ) {
output . push ( quotePromptArg ( items [ i ] . title ) ) ;
}
return output ;
2017-06-22 21:52:27 +00:00
} ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-22 21:52:27 +00:00
2017-06-25 22:20:07 +00:00
function cmdError ( commandInstance , msg , end ) {
commandInstance . log ( msg ) ;
end ( ) ;
}
2017-06-22 21:52:27 +00:00
2017-06-25 22:20:07 +00:00
function cmdPromptConfirm ( commandInstance , message ) {
return new Promise ( ( resolve , reject ) => {
let options = {
type : 'confirm' ,
name : 'ok' ,
default : false , // This needs to be false so that, when pressing Ctrl+C, the prompt returns false
message : message ,
} ;
2017-07-04 19:12:30 +00:00
2017-06-25 22:20:07 +00:00
commandInstance . prompt ( options , ( result ) => {
if ( result . ok ) {
resolve ( true ) ;
2017-06-25 11:39:42 +00:00
} else {
2017-06-25 22:20:07 +00:00
resolve ( false ) ;
2017-06-25 11:39:42 +00:00
}
2017-06-25 22:20:07 +00:00
} ) ;
} ) ;
}
2017-06-25 11:39:42 +00:00
2017-06-29 18:03:16 +00:00
// Handles the initial flags passed to main script and
// returns the remaining args.
async function handleStartFlags ( argv ) {
argv = argv . slice ( 0 ) ;
argv . splice ( 0 , 2 ) ; // First arguments are the node executable, and the node JS file
2017-06-27 20:58:27 +00:00
2017-06-29 18:03:16 +00:00
while ( argv . length ) {
let arg = argv [ 0 ] ;
let nextArg = argv . length >= 2 ? argv [ 1 ] : null ;
if ( arg == '--profile' ) {
2017-07-04 19:12:30 +00:00
if ( ! nextArg ) throw new Error ( _ ( 'Usage: --profile <dir-path>' ) ) ;
2017-06-29 18:03:16 +00:00
initArgs . profileDir = nextArg ;
argv . splice ( 0 , 2 ) ;
continue ;
}
2017-06-27 20:58:27 +00:00
2017-07-04 19:12:30 +00:00
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 ;
}
2017-06-29 18:03:16 +00:00
if ( arg . length && arg [ 0 ] == '-' ) {
throw new Error ( _ ( 'Unknown flag: %s' , arg ) ) ;
} else {
break ;
}
}
2017-06-27 20:58:27 +00:00
2017-06-29 18:03:16 +00:00
return argv ;
}
2017-06-27 20:58:27 +00:00
2017-06-29 18:03:16 +00:00
function escapeShellArg ( arg ) {
if ( arg . indexOf ( '"' ) >= 0 && arg . indexOf ( "'" ) >= 0 ) throw new Error ( _ ( 'Command line argument "%s" contains both quotes and double-quotes - aborting.' , arg ) ) ; // Hopeless case
let quote = '"' ;
if ( arg . indexOf ( '"' ) >= 0 ) quote = "'" ;
if ( arg . indexOf ( ' ' ) >= 0 || arg . indexOf ( "\t" ) >= 0 ) return quote + arg + quote ;
return arg ;
}
function shellArgsToString ( args ) {
let output = [ ] ;
for ( let i = 0 ; i < args . length ; i ++ ) {
output . push ( escapeShellArg ( args [ i ] ) ) ;
}
return output . join ( ' ' ) ;
2017-06-25 22:20:07 +00:00
}
2017-06-25 11:39:42 +00:00
2017-07-04 19:12:30 +00:00
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>`' ) ) ;
}
2017-06-25 22:20:07 +00:00
process . stdin . on ( 'keypress' , ( _ , key ) => {
if ( key && key . name === 'return' ) {
updatePrompt ( ) ;
}
2017-06-25 11:39:42 +00:00
2017-06-25 22:20:07 +00:00
if ( key . name === 'tab' ) {
vorpal . ui . imprint ( ) ;
vorpal . log ( vorpal . ui . input ( ) ) ;
}
} ) ;
2017-06-25 11:39:42 +00:00
2017-06-25 22:20:07 +00:00
const vorpal = require ( 'vorpal' ) ( ) ;
2017-06-25 11:39:42 +00:00
2017-07-04 19:12:30 +00:00
vorpalUtils . initialize ( vorpal ) ;
2017-06-25 22:20:07 +00:00
async function main ( ) {
2017-06-25 07:35:59 +00:00
for ( let commandIndex = 0 ; commandIndex < commands . length ; commandIndex ++ ) {
let c = commands [ commandIndex ] ;
2017-06-22 21:52:27 +00:00
let o = vorpal . command ( c . usage , c . description ) ;
2017-06-25 07:35:59 +00:00
if ( c . options ) {
for ( let i = 0 ; i < c . options . length ; i ++ ) {
let options = c . options [ i ] ;
if ( options . length == 2 ) o . option ( options [ 0 ] , options [ 1 ] ) ;
if ( options . length == 3 ) o . option ( options [ 0 ] , options [ 1 ] , options [ 2 ] ) ;
}
}
if ( c . aliases ) {
for ( let i = 0 ; i < c . aliases . length ; i ++ ) {
o . alias ( c . aliases [ i ] ) ;
}
2017-06-22 21:52:27 +00:00
}
if ( c . autocomplete ) {
o . autocomplete ( {
data : c . autocomplete ,
} ) ;
}
o . action ( c . action ) ;
}
2017-06-29 18:03:16 +00:00
let argv = process . argv ;
argv = await handleStartFlags ( argv ) ;
2017-06-25 22:20:07 +00:00
2017-07-04 19:12:30 +00:00
if ( argv . length ) showPromptString = false ;
2017-06-27 19:26:29 +00:00
const profileDir = initArgs . profileDir ? initArgs . profileDir : os . homedir ( ) + '/.config/' + Setting . value ( 'appName' ) ;
2017-06-25 22:20:07 +00:00
const resourceDir = profileDir + '/resources' ;
2017-07-05 18:31:11 +00:00
const tempDir = profileDir + '/tmp' ;
2017-06-25 22:20:07 +00:00
Setting . setConstant ( 'profileDir' , profileDir ) ;
Setting . setConstant ( 'resourceDir' , resourceDir ) ;
2017-07-05 18:31:11 +00:00
Setting . setConstant ( 'tempDir' , tempDir ) ;
2017-06-25 22:20:07 +00:00
await fs . mkdirp ( profileDir , 0o755 ) ;
await fs . mkdirp ( resourceDir , 0o755 ) ;
2017-07-05 18:31:11 +00:00
await fs . mkdirp ( tempDir , 0o755 ) ;
2017-06-25 22:20:07 +00:00
logger . addTarget ( 'file' , { path : profileDir + '/log.txt' } ) ;
2017-07-04 19:12:30 +00:00
logger . setLevel ( logLevel ) ;
2017-06-25 22:20:07 +00:00
dbLogger . addTarget ( 'file' , { path : profileDir + '/log-database.txt' } ) ;
2017-07-04 19:12:30 +00:00
dbLogger . setLevel ( logLevel ) ;
2017-06-25 22:20:07 +00:00
syncLogger . addTarget ( 'file' , { path : profileDir + '/log-sync.txt' } ) ;
2017-07-04 19:12:30 +00:00
syncLogger . setLevel ( logLevel ) ;
2017-06-25 22:20:07 +00:00
logger . info ( sprintf ( 'Starting %s %s...' , packageJson . name , packageJson . version ) ) ;
logger . info ( 'Profile directory: ' + profileDir ) ;
database _ = new Database ( new DatabaseDriverNode ( ) ) ;
database _ . setLogger ( dbLogger ) ;
await database _ . open ( { name : profileDir + '/database.sqlite' } ) ;
BaseModel . db _ = database _ ;
await Setting . load ( ) ;
2017-06-25 10:41:03 +00:00
let activeFolderId = Setting . value ( 'activeFolderId' ) ;
let activeFolder = null ;
if ( activeFolderId ) activeFolder = await Folder . load ( activeFolderId ) ;
if ( ! activeFolder ) activeFolder = await Folder . defaultFolder ( ) ;
2017-07-01 15:07:17 +00:00
Setting . setValue ( 'activeFolderId' , activeFolder ? activeFolder . id : '' ) ;
2017-06-27 20:16:03 +00:00
2017-07-01 15:07:17 +00:00
if ( activeFolder ) await execCommand ( 'cd' , { 'notebook' : activeFolder . title } ) ; // Use execCommand() so that no history entry is created
2017-06-29 18:03:16 +00:00
// If we still have arguments, pass it to Vorpal and exit
if ( argv . length ) {
2017-07-04 19:12:30 +00:00
vorpal . show ( ) ;
2017-06-29 18:03:16 +00:00
let cmd = shellArgsToString ( argv ) ;
await vorpal . exec ( cmd ) ;
await vorpal . exec ( 'exit' ) ;
return ;
2017-06-30 15:33:40 +00:00
} else {
2017-07-04 19:12:30 +00:00
vorpal . delimiter ( promptString ( ) ) ;
vorpal . show ( ) ;
2017-07-02 10:34:07 +00:00
vorpal . history ( Setting . value ( 'appId' ) ) ; // Enables persistent history
2017-07-01 15:07:17 +00:00
if ( ! activeFolder ) {
vorpal . log ( _ ( 'No notebook is defined. Create one with `mkbook <notebook>`.' ) ) ;
}
2017-06-29 18:03:16 +00:00
}
2017-06-22 21:52:27 +00:00
}
main ( ) . catch ( ( error ) => {
2017-06-27 19:26:29 +00:00
vorpal . log ( 'Fatal error:' ) ;
vorpal . log ( error ) ;
2017-06-22 21:52:27 +00:00
} ) ;