diff --git a/src/gui/commandcompleter.cpp b/src/gui/commandcompleter.cpp
index 0b33e4967693749abaeeb024b2b86696035b65b6..582ba023af0173555f9ce6fd4761ba98ecd22e8d 100644
--- a/src/gui/commandcompleter.cpp
+++ b/src/gui/commandcompleter.cpp
@@ -23,11 +23,14 @@
 #include <QAbstractItemView>
 #include <QCompleter>
 #include <QCoreApplication>
+#include <QHash>
+#include <QHeaderView>
 #include <QKeyEvent>
+#include <QTableView>
 #include <QPlainTextEdit>
 #include <QScrollBar>
-
-#include <QDebug>
+#include <QStringListModel>
+#include <QShortcut>
 
 namespace {
 
@@ -39,17 +42,296 @@ QStringList scriptableCompletions()
          + scriptableKeywords();
 }
 
+class CommandCompleterModel : public QStringListModel {
+public:
+    explicit CommandCompleterModel(QObject *parent)
+        : QStringListModel(scriptableCompletions(), parent)
+    {
+        for (const auto &name : scriptableObjects())
+            m_doc[name].tag = "t";
+
+        for (const auto &name : scriptableProperties())
+            m_doc[name].tag = "o";
+
+        for (const auto &name : scriptableFunctions())
+            m_doc[name].tag = "fn";
+
+        for (const auto &name : scriptableKeywords())
+            m_doc[name].tag = "k";
+
+        addDocumentation();
+    }
+
+    int columnCount(const QModelIndex &) const override
+    {
+        return 3;
+    }
+
+    QVariant data(const QModelIndex &index, int role) const override
+    {
+        const int row = index.row();
+
+        if (index.column() == 1) {
+            if (role == Qt::DisplayRole || role == Qt::EditRole)
+                return QString(documentationForRow(row).tag);
+
+            if (role == Qt::ForegroundRole)
+                return QColor(Qt::gray);
+
+            return QVariant();
+        }
+
+        if (index.column() == 2) {
+            if (role == Qt::DisplayRole || role == Qt::EditRole)
+                return documentationForRow(row).doc;
+
+            return QVariant();
+        }
+
+        if (role == Qt::ToolTipRole)
+            return typeForRow(row);
+
+        return QStringListModel::data(index, role);
+    }
+
+private:
+    struct ScriptableDocumentation {
+        QString tag;
+        QString doc;
+    };
+
+    // Generated by "utils/script_docs_to_cpp.py" from "src/scriptable/README.md".
+    void addDocumentation()
+    {
+        addDocumentation("version", "String version()", "Returns version string.");
+        addDocumentation("help", "String help()", "Returns help string.");
+        addDocumentation("help", "String help(searchString, ...)", "Returns help for matched commands.");
+        addDocumentation("show", "show()", "Shows main window.");
+        addDocumentation("show", "show(tabName)", "Shows tab.");
+        addDocumentation("showAt", "showAt()", "Shows main window under mouse cursor.");
+        addDocumentation("showAt", "showAt(x, y, [width, height])", "Shows main window with given geometry.");
+        addDocumentation("showAt", "showAt(x, y, width, height, tabName)", "Shows tab with given geometry.");
+        addDocumentation("hide", "hide()", "Hides main window.");
+        addDocumentation("toggle", "bool toggle()", "Shows or hides main window.");
+        addDocumentation("menu", "menu()", "Opens context menu.");
+        addDocumentation("menu", "menu(tabName)", "Shows context menu for given tab.");
+        addDocumentation("exit", "exit()", "Exits server.");
+        addDocumentation("disable", "disable(), enable()", "Disables or enables clipboard content storing.");
+        addDocumentation("monitoring", "bool monitoring()", "Returns true only if clipboard storing is enabled.");
+        addDocumentation("visible", "bool visible()", "Available since v2.4.7.");
+        addDocumentation("focused", "bool focused()", "Available since v2.4.9.");
+        addDocumentation("filter", "filter(filterText)", "Available since v2.4.9.");
+        addDocumentation("ignore", "ignore()", "Ignores current clipboard content (used for automatic commands).");
+        addDocumentation("clipboard", "ByteArray clipboard([mimeType])", "Returns clipboard data for MIME type (default is text).");
+        addDocumentation("selection", "ByteArray selection([mimeType])", "Same as `clipboard()` for Linux/X11 mouse selection.");
+        addDocumentation("copy", "bool copy(text)", "Sets clipboard plain text.");
+        addDocumentation("copy", "bool copy(mimeType, data, [mimeType, data]...)", "Sets clipboard data.");
+        addDocumentation("copy", "bool copy()", "Sends `Ctrl+C` to current window.");
+        addDocumentation("copySelection", "ByteArray copySelection(...)", "Same as `copy(...)` for Linux/X11 mouse selection.");
+        addDocumentation("paste", "paste()", "Pastes current clipboard.");
+        addDocumentation("tab", "Array tab()", "Returns array of with tab names.");
+        addDocumentation("tab", "tab(tabName)", "Sets current tab for the script.");
+        addDocumentation("removeTab", "removeTab(tabName)", "Removes tab.");
+        addDocumentation("renameTab", "renameTab(tabName, newTabName)", "Renames tab.");
+        addDocumentation("tabIcon", "String tabIcon(tabName)", "Returns path to icon for tab.");
+        addDocumentation("tabIcon", "tabIcon(tabName, iconPath)", "Sets icon for tab.");
+        addDocumentation("count", "count(), length(), size()", "Returns amount of items in current tab.");
+        addDocumentation("select", "select(row)", "Copies item in the row to clipboard.");
+        addDocumentation("next", "next()", "Copies next item from current tab to clipboard.");
+        addDocumentation("previous", "previous()", "Copies previous item from current tab to clipboard.");
+        addDocumentation("add", "add(text, ...)", "Adds new text items to current tab.");
+        addDocumentation("insert", "insert(row, text)", "Inserts new text items to current tab.");
+        addDocumentation("remove", "remove(row, ...)", "Removes items in current tab.");
+        addDocumentation("edit", "edit(row, ...)", "Edits items in current tab.");
+        addDocumentation("read", "ByteArray read([mimeType]);", "Same as `clipboard()`.");
+        addDocumentation("read", "ByteArray read(mimeType, row, ...);", "Returns concatenated data from items.");
+        addDocumentation("write", "write(row, mimeType, data, [mimeType, data]...)", "Inserts new item to current tab.");
+        addDocumentation("change", "change(row, mimeType, data, [mimeType, data]...)", "Changes data in item in current tab.");
+        addDocumentation("separator", "String separator()", "Returns item separator (used when concatenating item data).");
+        addDocumentation("separator", "separator(separator)", "Sets item separator for concatenating item data.");
+        addDocumentation("action", "action()", "Opens action dialog.");
+        addDocumentation("action", "action(row, ..., command, outputItemSeparator)", "Runs command for items in current tab.");
+        addDocumentation("popup", "popup(title, message, [time=8000])", "Shows popup message for given time in milliseconds.");
+        addDocumentation("exportTab", "exportTab(fileName)", "Exports current tab into file.");
+        addDocumentation("importTab", "importTab(fileName)", "Imports items from file to a new tab.");
+        addDocumentation("config", "String config()", "Returns help with list of available options.");
+        addDocumentation("config", "String config(optionName)", "Returns value of given option.");
+        addDocumentation("config", "String config(optionName, value)", "Sets option.");
+        addDocumentation("info", "String info([pathName])", "Returns paths and flags used by the application.");
+        addDocumentation("eval", "Value eval(script)", "Evaluates script and returns result.");
+        addDocumentation("currentpath", "String currentpath()", "Returns current path.");
+        addDocumentation("str", "String str(value)", "Converts a value to string.");
+        addDocumentation("input", "ByteArray input()", "Returns standard input passed to the script.");
+        addDocumentation("data", "ByteArray data(mimeType)", "Returns data for automatic commands or selected items.");
+        addDocumentation("setData", "ByteArray setData(mimeType, data)", "Modifies data for `data()` and new clipboard item.");
+        addDocumentation("removeData", "ByteArray removeData(mimeType)", "Removes data for `data()` and new clipboard item.");
+        addDocumentation("dataFormats", "Array dataFormats()", "Returns formats available for `data()`.");
+        addDocumentation("print", "print(value)", "Prints value to standard output.");
+        addDocumentation("abort", "abort()", "Aborts script evaluation.");
+        addDocumentation("fail", "fail()", "Aborts script evaluation with nonzero exit code.");
+        addDocumentation("setCurrentTab", "setCurrentTab(tabName)", "Focus tab without showing main window.");
+        addDocumentation("selectItems", "selectItems(row, ...)", "Selects items in current tab.");
+        addDocumentation("selectedTab", "String selectedTab()", "Returns tab that was selected when script was executed.");
+        addDocumentation("selectedItems", "[row, ...] selectedItems()", "Returns selected rows in current tab.");
+        addDocumentation("currentItem", "int currentItem(), int index()", "Returns current row in current tab.");
+        addDocumentation("escapeHtml", "String escapeHtml(text)", "Returns text with special HTML characters escaped.");
+        addDocumentation("unpack", "Item unpack(data)", "Returns deserialized object from serialized items.");
+        addDocumentation("pack", "ByteArray pack(item)", "Returns serialized item.");
+        addDocumentation("getItem", "Item getItem(row)", "Returns an item in current tab.");
+        addDocumentation("setItem", "setItem(row, item)", "Inserts item to current tab.");
+        addDocumentation("toBase64", "String toBase64(data)", "Returns base64-encoded data.");
+        addDocumentation("fromBase64", "ByteArray fromBase64(base64String)", "Returns base64-decoded data.");
+        addDocumentation("open", "QScriptValue open(url, ...)", "Tries to open URLs in appropriate applications.");
+        addDocumentation("execute", "FinishedCommand execute(argument, ..., null, stdinData, ...)", "Executes a command.");
+        addDocumentation("currentWindowTitle", "String currentWindowTitle()", "Returns window title of currently focused window.");
+        addDocumentation("dialog", "Value dialog(...)", "Shows messages or asks user for input.");
+        addDocumentation("settings", "Array settings()", "Returns array with names of all custom options.");
+        addDocumentation("settings", "Value settings(optionName)", "Returns value for an option.");
+        addDocumentation("settings", "settings(optionName)", "Sets value for a new option or overrides existing option.");
+        addDocumentation("dateString", "String dateString(format)", "Returns text representation of current date and time.");
+        addDocumentation("networkGet", "NetworkReply networkGet(url)", "Sends HTTP GET request.");
+        addDocumentation("networkPost", "NetworkReply networkPost(url, postData)", "Sends HTTP POST request.");
+        addDocumentation("env", "ByteArray env(name)", "Returns value of environment variable with given name.");
+        addDocumentation("setEnv", "bool setEnv(name, value)", "Sets environment variable with given name to given value.");
+        addDocumentation("ByteArray", "ByteArray", "Wrapper for QByteArray Qt class.");
+        addDocumentation("File", "File", "Wrapper for QFile Qt class.");
+        addDocumentation("Dir", "Dir", "Wrapper for QDir Qt class.");
+        addDocumentation("arguments", "(Array)", "Array for accessing arguments passed to current function or the script");
+        addDocumentation("Item", "(Object)", "Type is `Object` and each property is MIME type with data.");
+        addDocumentation("FinishedCommand", "(Object)", "Type is `Object` and properties are:");
+        addDocumentation("NetworkReply", "(Object)", "Type is `Object` and properties are:");
+        addDocumentation("mimeText", "(text/plain)", "Data contains plain text content.");
+        addDocumentation("mimeHtml", "(text/html)", "Data contains HTML content.");
+        addDocumentation("mimeUriList", "(text/uri-list)", "Data contains list of links to files, web pages etc.");
+        addDocumentation("mimeWindowTitle", "(application/x-copyq-owner-window-title)", "Current window title for copied clipboard.");
+        addDocumentation("mimeItems", "(application/x-copyq-item)", "Serialized items.");
+        addDocumentation("mimeItemNotes", "(application/x-copyq-item-notes)", "Data contains notes for item.");
+        addDocumentation("mimeOwner", "(application/x-copyq-owner)", "If available, the clipboard was set from CopyQ (from script or copied items).");
+        addDocumentation("mimeClipboardMode", "(application/x-copyq-clipboard-mode)", "Contains `selection` if data is from X11 mouse selection.");
+        addDocumentation("mimeCurrentTab", "(application/x-copyq-current-tab)", "Current tab name when invoking command from main window.");
+        addDocumentation("mimeSelectedItems", "(application/x-copyq-selected-items)", "Selected items when invoking command from main window.");
+        addDocumentation("mimeCurrentItem", "(application/x-copyq-current-item)", "Current item when invoking command from main window.");
+        addDocumentation("mimeHidden", "(application/x-copyq-hidden)", "If set to `1`, the clipboard or item content will be hidden in GUI.");
+        addDocumentation("mimeShortcut", "(application/x-copyq-shortcut)", "Application or global shortcut which activated the command.");
+        addDocumentation("mimeColor", "(application/x-copyq-color)", "Item color (same as the one used by themes).");
+        addDocumentation("mimeOutputTab", "(application/x-copyq-output-tab)", "Name of the tab where to store new item.");
+        addDocumentation("mimeSyncToClipboard", "(application/x-copyq-sync-to-selection)", "If exists the X11 selection data will be copied to clipboard.");
+        addDocumentation("mimeSyncToSelection", "(application/x-copyq-sync-to-clipboard)", "If exists the clipboard data will be copied to X11 selection.");
+    }
+
+    void addDocumentation(const QString &name, const QString &api, const QString &documentation)
+    {
+        auto &doc = m_doc[name].doc;
+        if (!doc.isEmpty())
+            doc.append("\n");
+
+        doc.append(api + "\n    " + documentation);
+    }
+
+    ScriptableDocumentation documentationForRow(int row) const
+    {
+        const auto index2 = this->index(row, 0);
+        const auto text = QStringListModel::data(index2, Qt::EditRole).toString();
+        return m_doc.value(text);
+    }
+
+    QString typeForRow(int row) const
+    {
+        const auto tagText = documentationForRow(row).tag;
+        if (tagText.isEmpty())
+            return QString();
+
+        const char tag = tagText[0].toLatin1();
+        switch (tag) {
+        case 'a': return "array";
+        case 'k': return "keyword";
+        case 'f': return "function";
+        case 'o': return "object";
+        case 't': return "type";
+        default: return QString();
+        }
+    }
+
+    QHash<QString, ScriptableDocumentation> m_doc;
+};
+
+void setUpHeader(QHeaderView *header)
+{
+    header->hide();
+#if QT_VERSION < 0x050000
+    header->setResizeMode(QHeaderView::ResizeToContents);
+#else
+    header->setSectionResizeMode(QHeaderView::ResizeToContents);
+#endif
+}
+
+class CommandCompleterPopup : public QTableView {
+public:
+    explicit CommandCompleterPopup(QWidget *parent)
+        : QTableView(parent)
+    {
+        setUpHeader(horizontalHeader());
+        setUpHeader(verticalHeader());
+        setShowGrid(false);
+        setContentsMargins(0, 0, 0, 0);
+        setSelectionBehavior(QAbstractItemView::SelectRows);
+        setAlternatingRowColors(true);
+    }
+
+protected:
+    void showEvent(QShowEvent *event) override
+    {
+        QTableView::showEvent(event);
+        startTimer(0);
+    }
+
+    void timerEvent(QTimerEvent *event) override
+    {
+        QTableView::timerEvent(event);
+
+        if (!model())
+            return;
+
+        const auto margins = contentsMargins();
+        const int w = columnsWidth()
+                + (verticalScrollBar()->isVisible() ? verticalScrollBar()->width() : 0)
+                + margins.left() + margins.right();
+        const int h = rowsHeight(8)
+                + (horizontalScrollBar()->isVisible() ? verticalScrollBar()->height() : 0)
+                + margins.top() + margins.bottom();
+        resize(w, h);
+    }
+
+private:
+    int columnsWidth() const
+    {
+        int width = 0;
+        for ( int column = 0; column < model()->columnCount(); ++column )
+            width += columnWidth(column);
+        return width;
+    }
+
+    int rowsHeight(int maxRows) const
+    {
+        int height = 0;
+        for ( int row = 0; row < qMin(maxRows, model()->rowCount()); ++row )
+            height += rowHeight(row);
+        return height;
+    }
+};
+
 } // namespace
 
 CommandCompleter::CommandCompleter(QPlainTextEdit *editor)
     : QObject(editor)
     , m_editor(editor)
-    , m_completer(new QCompleter(scriptableCompletions(), this))
+    , m_completer(new QCompleter(new CommandCompleterModel(this), this))
 {
     m_completer->setWidget(m_editor);
     m_completer->setCompletionMode(QCompleter::PopupCompletion);
     m_completer->setCaseSensitivity(Qt::CaseInsensitive);
 
+    m_completer->setPopup(new CommandCompleterPopup(m_editor));
     m_completer->popup()->installEventFilter(this);
 
     connect( m_completer, SIGNAL(activated(QString)),
@@ -59,6 +341,10 @@ CommandCompleter::CommandCompleter(QPlainTextEdit *editor)
              this, SLOT(updateCompletion()) );
     connect( m_editor, SIGNAL(cursorPositionChanged()),
              m_completer->popup(), SLOT(hide()) );
+
+    auto shortcut = new QShortcut(tr("Ctrl+Space", "Shortcut to show completion menu"), editor);
+    connect( shortcut, SIGNAL(activated()),
+             this, SLOT(showCompletion()) );
 }
 
 bool CommandCompleter::eventFilter(QObject *, QEvent *event)
@@ -88,13 +374,13 @@ bool CommandCompleter::eventFilter(QObject *, QEvent *event)
     }
 }
 
-void CommandCompleter::updateCompletion()
+void CommandCompleter::updateCompletion(bool forceShow)
 {
     const QString completionPrefix = textUnderCursor();
 
     QAbstractItemView *popup = m_completer->popup();
 
-    if ( completionPrefix.length() < 3 ) {
+    if ( !forceShow && completionPrefix.length() < 3 ) {
         popup->hide();
     } else {
         if (completionPrefix != m_completer->completionPrefix()) {
@@ -102,11 +388,7 @@ void CommandCompleter::updateCompletion()
             popup->setCurrentIndex(m_completer->completionModel()->index(0, 0));
         }
 
-        QRect rect = m_editor->cursorRect();
-        QScrollBar *scrollBar = popup->verticalScrollBar();
-        rect.setWidth(
-                    popup->sizeHintForColumn(0)
-                    + (scrollBar ? scrollBar->sizeHint().width() : 0) );
+        const auto rect = m_editor->cursorRect();
         m_completer->complete(rect);
     }
 }
@@ -114,16 +396,24 @@ void CommandCompleter::updateCompletion()
 void CommandCompleter::insertCompletion(const QString &completion)
 {
     QTextCursor tc = m_editor->textCursor();
-    int extra = completion.length() - m_completer->completionPrefix().length();
     tc.movePosition(QTextCursor::Left);
-    tc.movePosition(QTextCursor::EndOfWord);
-    tc.insertText(completion.right(extra));
+    tc.movePosition(QTextCursor::StartOfWord);
+    tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+    tc.insertText(completion);
     m_editor->setTextCursor(tc);
 }
 
+void CommandCompleter::showCompletion()
+{
+    updateCompletion(true);
+}
+
 QString CommandCompleter::textUnderCursor() const
 {
-    QTextCursor tc = m_editor->textCursor();
+    auto tc = m_editor->textCursor();
+    const auto c = tc.document()->characterAt(tc.position() - 1);
+    if (!c.isLetter())
+        return QString();
     tc.select(QTextCursor::WordUnderCursor);
     return tc.selectedText();
 }
diff --git a/src/gui/commandcompleter.h b/src/gui/commandcompleter.h
index 811d48ea7c3822f9e20ee2626ff12a1624d938ee..9b70ff6aae66b577b23ac6cb5bdba215e4e7708d 100644
--- a/src/gui/commandcompleter.h
+++ b/src/gui/commandcompleter.h
@@ -33,14 +33,16 @@ public:
     bool eventFilter(QObject *watched, QEvent *event);
 
 private slots:
-    void updateCompletion();
+    void updateCompletion(bool forceShow = false);
     void insertCompletion(const QString &completion);
+    void showCompletion();
 
 private:
     QString textUnderCursor() const;
 
     QPlainTextEdit *m_editor;
     QCompleter *m_completer;
+    bool m_popupVisible;
 };
 
 #endif // COMMANDCOMPLETER_H
diff --git a/src/gui/commandsyntaxhighlighter.cpp b/src/gui/commandsyntaxhighlighter.cpp
index 3d0793bb0ed5ecb9262f8600f2dc12e4a6055da4..1cd7f0da44d9837edc9aa10c8ba99f8ce9e7e7c4 100644
--- a/src/gui/commandsyntaxhighlighter.cpp
+++ b/src/gui/commandsyntaxhighlighter.cpp
@@ -110,6 +110,7 @@ protected:
 
         QTextCharFormat objectsFormat;
         objectsFormat.setForeground(mixColor(m_bgColor, 40, -60, 40));
+        objectsFormat.setToolTip("Object");
         highlight(text, m_reObjects, objectsFormat);
 
         QTextCharFormat propertyFormat;
@@ -261,6 +262,7 @@ private:
 QStringList scriptableKeywords()
 {
     return QStringList()
+            << "arguments"
             << "break"
             << "do"
             << "instanceof"
diff --git a/src/scriptable/README.md b/src/scriptable/README.md
index 11e8f3ece778ad1b21ad260639463ca7321f7013..d6788cdb2b2d6c81975e22098275ab5e7652700e 100644
--- a/src/scriptable/README.md
+++ b/src/scriptable/README.md
@@ -247,9 +247,9 @@ Opens action dialog.
 
 Runs command for items in current tab.
 
-###### popup(title, message, [timeout=8000])
+###### popup(title, message, [time=8000])
 
-Shows tray popup message for given time in milliseconds.
+Shows popup message for given time in milliseconds.
 
 ###### exportTab(fileName)
 
@@ -299,11 +299,15 @@ Returns standard input passed to the script.
 
 ###### ByteArray data(mimeType)
 
-Returns data for command (item data, clipboard data or text from action dialog).
+Returns data for automatic commands or selected items.
+
+If run from menu or using non-global shortcut the data are taken from selected items.
+
+If run for automatic command the data are clipboard content.
 
 ###### ByteArray setData(mimeType, data)
 
-Modifies data passed to automatic commands or selected items if run from menu or using shortcut.
+Modifies data for `data()` and new clipboard item.
 
 Next automatic command will get updated data.
 
@@ -323,11 +327,11 @@ E.g. following menu command will add tag to selected items.
 
 ###### ByteArray removeData(mimeType)
 
-Same as setData() except it removes given data format.
+Removes data for `data()` and new clipboard item.
 
 ###### Array dataFormats()
 
-Returns formats in data passed to automatic commands or selected items if run from menu or using shortcut.
+Returns formats available for `data()`.
 
 ###### print(value)
 
@@ -355,7 +359,7 @@ Returns tab that was selected when script was executed.
 
 ###### [row, ...] selectedItems()
 
-Returns array with rows of selected items in current tab.
+Returns selected rows in current tab.
 
 ###### int currentItem(), int index()
 
@@ -363,7 +367,7 @@ Returns current row in current tab.
 
 ###### String escapeHtml(text)
 
-Returns HTML representation of text (escapes special HTML characters).
+Returns text with special HTML characters escaped.
 
 ###### Item unpack(data)
 
@@ -526,7 +530,9 @@ Types
 
 ###### ByteArray
 
-Simple wrapper around [QByteArray](http://doc.qt.io/qt-5/qbytearray.html).
+Wrapper for QByteArray Qt class.
+
+See [QByteArray](http://doc.qt.io/qt-5/qbytearray.html).
 
 `ByteArray` is used to store all item data (image data, HTML and even plain text).
 
@@ -540,7 +546,9 @@ var text = str(read(0)) + str(read(1))
 
 ###### File
 
-Wrapper around [QFile](http://doc.qt.io/qt-5/qfile.html).
+Wrapper for QFile Qt class.
+
+See [QFile](http://doc.qt.io/qt-5/qfile.html).
 
 Following code reads contents of "README.md" file from current directory.
 
@@ -552,7 +560,9 @@ var bytes = f.readAll()
 
 ###### Dir
 
-Wrapper around [QDir](http://doc.qt.io/qt-5/qdir.html).
+Wrapper for QDir Qt class.
+
+See [QDir](http://doc.qt.io/qt-5/qdir.html).
 
 Objects
 -------
@@ -631,7 +641,7 @@ Data contains notes for item.
 
 ###### mimeOwner (application/x-copyq-owner)
 
-If this type is available, the clipboard was set from CopyQ (from script or copied items).
+If available, the clipboard was set from CopyQ (from script or copied items).
 
 ###### mimeClipboardMode (application/x-copyq-clipboard-mode)
 
@@ -656,7 +666,9 @@ Current item when invoking command from main window.
 
 ###### mimeHidden (application/x-copyq-hidden)
 
-If set to `1`, the clipboard or item content will be hidden in GUI (notes and tags will be visible).
+If set to `1`, the clipboard or item content will be hidden in GUI.
+
+This won't hide notes and tags.
 
 E.g. if you run following, window title and tool tip will be cleared.
 
@@ -681,9 +693,9 @@ Examples:
 
 ###### mimeOutputTab (application/x-copyq-output-tab)
 
-Valid only in automatic commands.
+Name of the tab where to store new item.
 
-Name of the tab where to store the clipboard data after all automatic commands are run.
+The clipboard data will be stored in tab with this name after all automatic commands are run.
 
 Clear or remove the format to omit storing the data.
 
@@ -693,22 +705,29 @@ E.g. to omit storing the clipboard data use following in an automatic command.
 removeData(mimeOutputTab)
 ```
 
+Valid only in automatic commands.
+
 ###### mimeSyncToClipboard (application/x-copyq-sync-to-selection)
 
-Valid only in Linux/X11 in automatic commands.
+If exists the X11 selection data will be copied to clipboard.
 
-If the format exists the Linux/X11 mouse selection data will be copied to clipboard after all automatic commands are run.
+The synchronization will happend after all automatic commands are run.
 
 ```js
 removeData(mimeSyncToClipboard)
 ```
 
+Valid only in Linux/X11 in automatic commands.
+
 ###### mimeSyncToSelection (application/x-copyq-sync-to-clipboard)
 
-Valid only in Linux/X11 in automatic commands.
+If exists the clipboard data will be copied to X11 selection.
 
-If the format exists the clipboard data will be copied to Linux/X11 mouse selection buffer after all automatic commands are run.
+The synchronization will happend after all automatic commands are run.
 
 ```js
 removeData(mimeSyncToSelection)
 ```
+
+Valid only in Linux/X11 in automatic commands.
+
diff --git a/utils/script_docs_to_cpp.py b/utils/script_docs_to_cpp.py
new file mode 100755
index 0000000000000000000000000000000000000000..a0f39f637514a1adca6b2c85a12af4899d2c5a57
--- /dev/null
+++ b/utils/script_docs_to_cpp.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+'''
+Parses API for C++ from scriptable README file.
+'''
+
+import re
+
+readme = 'src/scriptable/README.md'
+
+def main():
+    with open(readme) as f:
+        api = ''
+        for line in f.readlines():
+            line = line.strip()
+            if line.startswith('###### '):
+                api = line[7:]
+            elif api and line:
+                m = re.match(r'.*?(\w+)\s*(\(|$)', api)
+                if m:
+                    name = m.group(1)
+                    if api.startswith(name + ' '):
+                        api = api[len(name) + 1:]
+                    print('addDocumentation("{}", "{}", "{}");'
+                            .format(name, api, line))
+                api = ''
+
+if __name__ == "__main__":
+    main()