diff --git a/CliClient/app/app.js b/CliClient/app/app.js index ee8bfc2bf..04db4c663 100644 --- a/CliClient/app/app.js +++ b/CliClient/app/app.js @@ -177,22 +177,33 @@ class Application extends BaseApplication { await doExit(); } - commands() { - if (this.allCommandsLoaded_) return this.commands_; + commands(uiType = null) { + if (!this.allCommandsLoaded_) { + fs.readdirSync(__dirname).forEach((path) => { + if (path.indexOf('command-') !== 0) return; + const ext = fileExtension(path) + if (ext != 'js') return; - fs.readdirSync(__dirname).forEach((path) => { - if (path.indexOf('command-') !== 0) return; - const ext = fileExtension(path) - if (ext != 'js') return; + let CommandClass = require('./' + path); + let cmd = new CommandClass(); + if (!cmd.enabled()) return; + cmd = this.setupCommand(cmd); + this.commands_[cmd.name()] = cmd; + }); - let CommandClass = require('./' + path); - let cmd = new CommandClass(); - if (!cmd.enabled()) return; - cmd = this.setupCommand(cmd); - this.commands_[cmd.name()] = cmd; - }); + this.allCommandsLoaded_ = true; + } - this.allCommandsLoaded_ = true; + if (uiType !== null) { + let temp = []; + for (let n in this.commands_) { + if (!this.commands_.hasOwnProperty(n)) continue; + const c = this.commands_[n]; + if (!c.supportsUi(uiType)) continue; + temp[n] = c; + } + return temp; + } return this.commands_; } @@ -310,6 +321,8 @@ class Application extends BaseApplication { if (argv.length) { this.gui_ = this.dummyGui(); + this.currentFolder_ = await Folder.load(Setting.value('activeFolderId')); + try { await this.execCommand(argv); } catch (error) { diff --git a/CliClient/app/command-exit.js b/CliClient/app/command-exit.js index 5d73513f1..32be81aff 100644 --- a/CliClient/app/command-exit.js +++ b/CliClient/app/command-exit.js @@ -12,6 +12,10 @@ class Command extends BaseCommand { return _('Exits the application.'); } + compatibleUis() { + return ['gui']; + } + async action(args) { await app().exit(); } diff --git a/CliClient/app/command-help.js b/CliClient/app/command-help.js index a34e118bd..a8fe5c957 100644 --- a/CliClient/app/command-help.js +++ b/CliClient/app/command-help.js @@ -18,7 +18,7 @@ class Command extends BaseCommand { } allCommands() { - const commands = app().commands(); + const commands = app().commands(app().uiType()); let output = []; for (let n in commands) { if (!commands.hasOwnProperty(n)) continue; @@ -69,6 +69,8 @@ class Command extends BaseCommand { this.stdout(''); this.stdout(_('The possible commands are:')); this.stdout(''); + this.stdout(_('Type `help all` for the complete help of all the commands.')); + this.stdout(''); this.stdout(commandNames.join(', ')); this.stdout(''); this.stdout(_('In any command, a note or notebook can be refered to by title or ID, or using the shortcuts `$n` or `$b` for, respectively, the currently selected note or notebook. `$c` can be used to refer to the currently selected item.')); diff --git a/CliClient/app/command-set.js b/CliClient/app/command-set.js index 37274be92..391887523 100644 --- a/CliClient/app/command-set.js +++ b/CliClient/app/command-set.js @@ -2,6 +2,7 @@ const { BaseCommand } = require('./base-command.js'); const { app } = require('./app.js'); const { _ } = require('lib/locale.js'); const { BaseModel } = require('lib/base-model.js'); +const { Database } = require('lib/database.js'); const { Folder } = require('lib/models/folder.js'); const { Note } = require('lib/models/note.js'); const { BaseItem } = require('lib/models/base-item.js'); @@ -12,16 +13,16 @@ class Command extends BaseCommand { return 'set [value]'; } - enabled() { - return false; - } - description() { - return _('Sets the property of the given to the given [value].'); - } + const fields = Note.fields(); + const s = []; + for (let i = 0; i < fields.length; i++) { + const f = fields[i]; + if (f.name === 'id') continue; + s.push(f.name + ' (' + Database.enumName('fieldType', f.type) + ')'); + } - hidden() { - return true; + return _('Sets the property of the given to the given [value]. Possible properties are:\n\n%s', s.join(', ')); } async action(args) { diff --git a/CliClient/app/command-use.js b/CliClient/app/command-use.js index 91157c10a..ea27bc861 100644 --- a/CliClient/app/command-use.js +++ b/CliClient/app/command-use.js @@ -18,8 +18,8 @@ class Command extends BaseCommand { return { data: autocompleteFolders }; } - enabled() { - return false; + compatibleUis() { + return ['cli']; } async action(args) { diff --git a/README_terminal.md b/README_terminal.md index 085120d41..5c299563e 100644 --- a/README_terminal.md +++ b/README_terminal.md @@ -137,6 +137,25 @@ Since this is still an actual URL, the terminal will still make it clickable. An In Markdown, links to resources are represented as a simple ID to the resource. In order to give access to these resources, they will be, like links, converted to local URLs. Clicking this link will then open a browser, which will handle the file - i.e. display the image, open the PDF file, etc. +# Shell mode + +Commands can also be used directly from a shell. To view the list of available commands, type `joplin help all`. To reference a note, notebook or tag you can either use the ID (type `joplin ls -l` to view the ID) or by title. + +For example, this will create a new note "My note" in the notebook "My notebook": + + $ joplin mkbook "My notebook" + $ joplin use "My notebook" + $ joplin mknote "My note" + +To view the newly created note: + + $ joplin ls -l + fe889 07/12/2017 17:57 My note + +Give a new title to the note: + + $ joplin set "My note" title "New title" + # Available shortcuts There are two types of shortcuts: those that manipulate the user interface directly, such as `TAB` to move from one pane to another, and those that are simply shortcuts to actual commands. In a way similar to Vim, these shortcuts are generally a verb followed by an object. For example, typing `mn` ([m]ake [n]ote), is used to create a new note: it will switch the interface to command line mode and pre-fill it with `mknote ""` from where the title of the note can be entered. See below for the full list of shortcuts: diff --git a/ReactNativeClient/lib/BaseApplication.js b/ReactNativeClient/lib/BaseApplication.js index fe9e92280..097313af1 100644 --- a/ReactNativeClient/lib/BaseApplication.js +++ b/ReactNativeClient/lib/BaseApplication.js @@ -66,10 +66,15 @@ class BaseApplication { } switchCurrentFolder(folder) { - this.dispatch({ - type: 'FOLDER_SELECT', - id: folder ? folder.id : '', - }); + if (!this.hasGui()) { + this.currentFolder_ = Object.assign({}, folder); + Setting.setValue('activeFolderId', folder ? folder.id : ''); + } else { + this.dispatch({ + type: 'FOLDER_SELECT', + id: folder ? folder.id : '', + }); + } } // Handles the initial flags passed to main script and @@ -227,6 +232,10 @@ class BaseApplication { return false; } + uiType() { + return this.hasGui() ? 'gui' : 'cli'; + } + generalMiddlewareFn() { const middleware = store => next => (action) => { return this.generalMiddleware(store, next, action); diff --git a/ReactNativeClient/lib/database.js b/ReactNativeClient/lib/database.js index c39901857..940bac41e 100644 --- a/ReactNativeClient/lib/database.js +++ b/ReactNativeClient/lib/database.js @@ -165,6 +165,16 @@ class Database { throw new Error('Unknown enum type or value: ' + type + ', ' + s); } + static enumName(type, id) { + if (type === 'fieldType') { + if (id === Database.TYPE_UNKNOWN) return 'unknown'; + if (id === Database.TYPE_INT) return 'int'; + if (id === Database.TYPE_TEXT) return 'text'; + if (id === Database.TYPE_NUMERIC) return 'numeric'; + throw new Error('Invalid type id: ' + id); + } + } + static formatValue(type, value) { if (value === null || value === undefined) return null; if (type == this.TYPE_INT) return Number(value); diff --git a/docs/terminal/index.html b/docs/terminal/index.html index f11e3a6c6..889d6dfff 100644 --- a/docs/terminal/index.html +++ b/docs/terminal/index.html @@ -309,7 +309,18 @@ sudo ln -s ~/.joplin-bin/bin/joplin /usr/bin/joplin

Since this is still an actual URL, the terminal will still make it clickable. And with shorter URLs, the text is more readable and the links unlikely to be cut. Both resources (files that are attached to notes) and external links are handled in this way.

Attachments / Resources

In Markdown, links to resources are represented as a simple ID to the resource. In order to give access to these resources, they will be, like links, converted to local URLs. Clicking this link will then open a browser, which will handle the file - i.e. display the image, open the PDF file, etc.

-

Available shortcuts

+

Shell mode

+

Commands can also be used directly from a shell. To view the list of available commands, type joplin help all. To reference a note, notebook or tag you can either use the ID (type joplin ls -l to view the ID) or by title.

+

For example, this will create a new note "My note" in the notebook "My notebook":

+
$ joplin mkbook "My notebook"
+$ joplin use "My notebook"
+$ joplin mknote "My note"
+

To view the newly created note:

+
$ joplin ls -l
+fe889 07/12/2017 17:57 My note
+

Give a new title to the note:

+
$ joplin set "My note" title "New title"
+

Available shortcuts

There are two types of shortcuts: those that manipulate the user interface directly, such as TAB to move from one pane to another, and those that are simply shortcuts to actual commands. In a way similar to Vim, these shortcuts are generally a verb followed by an object. For example, typing mn ([m]ake [n]ote), is used to create a new note: it will switch the interface to command line mode and pre-fill it with mknote "" from where the title of the note can be entered. See below for the full list of shortcuts:

Tab       Give focus to next pane
 Shift+Tab Give focus to previous pane