File indexing completed on 2024-04-28 15:30:52

0001 /*
0002     SPDX-FileCopyrightText: 2003-2005 Anders Lund <anders@alweb.dk>
0003     SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org>
0004     SPDX-FileCopyrightText: 2001 Charles Samuels <charles@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "katecmds.h"
0010 
0011 #include "kateautoindent.h"
0012 #include "katecmd.h"
0013 #include "katedocument.h"
0014 #include "katepartdebug.h"
0015 #include "katerenderer.h"
0016 #include "katesyntaxmanager.h"
0017 #include "katetextline.h"
0018 #include "kateview.h"
0019 
0020 #include <KLocalizedString>
0021 
0022 #include <QDateTime>
0023 #include <QRegularExpression>
0024 
0025 // BEGIN CoreCommands
0026 KateCommands::CoreCommands *KateCommands::CoreCommands::m_instance = nullptr;
0027 
0028 // this returns whether the string s could be converted to
0029 // a bool value, one of on|off|1|0|true|false. the argument val is
0030 // set to the extracted value in case of success
0031 static bool getBoolArg(const QString &t, bool *val)
0032 {
0033     bool res(false);
0034     QString s = t.toLower();
0035     res = (s == QLatin1String("on") || s == QLatin1String("1") || s == QLatin1String("true"));
0036     if (res) {
0037         *val = true;
0038         return true;
0039     }
0040     res = (s == QLatin1String("off") || s == QLatin1String("0") || s == QLatin1String("false"));
0041     if (res) {
0042         *val = false;
0043         return true;
0044     }
0045     return false;
0046 }
0047 
0048 bool KateCommands::CoreCommands::help(KTextEditor::View *, const QString &cmd, QString &msg)
0049 {
0050     QString realcmd = cmd.trimmed();
0051     if (realcmd == QLatin1String("indent")) {
0052         msg = i18n(
0053             "<p>indent</p>"
0054             "<p>Indents the selected lines or the current line</p>");
0055         return true;
0056     } else if (realcmd == QLatin1String("unindent")) {
0057         msg = i18n(
0058             "<p>unindent</p>"
0059             "<p>Unindents the selected lines or current line.</p>");
0060         return true;
0061     } else if (realcmd == QLatin1String("cleanindent")) {
0062         msg = i18n(
0063             "<p>cleanindent</p>"
0064             "<p>Cleans up the indentation of the selected lines or current line according to the indentation settings in the document. </p>");
0065         return true;
0066     } else if (realcmd == QLatin1String("comment")) {
0067         msg = i18n(
0068             "<p>comment</p>"
0069             "<p>Inserts comment markers to make the selection or selected lines or current line a comment according to the text format as defined by the "
0070             "syntax highlight definition for the document.</p>");
0071         return true;
0072     } else if (realcmd == QLatin1String("uncomment")) {
0073         msg = i18n(
0074             "<p>uncomment</p>"
0075             "<p>Removes comment markers from the selection or selected lines or current line according to the text format as defined by the syntax highlight "
0076             "definition for the document.</p>");
0077         return true;
0078     } else if (realcmd == QLatin1String("goto")) {
0079         msg = i18n(
0080             "<p>goto <b>line number</b></p>"
0081             "<p>This command navigates to the specified line number.</p>");
0082         return true;
0083     } else if (realcmd == QLatin1String("set-indent-pasted-text")) {
0084         msg = i18n(
0085             "<p>set-indent-pasted-text <b>enable</b></p>"
0086             "<p>If enabled, indentation of text pasted from the clipboard is adjusted using the current indenter.</p>"
0087             "<p>Possible true values: 1 on true<br/>"
0088             "possible false values: 0 off false</p>");
0089         return true;
0090     } else if (realcmd == QLatin1String("kill-line")) {
0091         msg = i18n("Deletes the current line.");
0092         return true;
0093     } else if (realcmd == QLatin1String("set-tab-width")) {
0094         msg = i18n(
0095             "<p>set-tab-width <b>width</b></p>"
0096             "<p>Sets the tab width to the number <b>width</b></p>");
0097         return true;
0098     } else if (realcmd == QLatin1String("set-replace-tab")) {
0099         msg = i18n(
0100             "<p>set-replace-tab <b>enable</b></p>"
0101             "<p>If enabled, tabs are replaced with spaces as you type.</p>"
0102             "<p>Possible true values: 1 on true<br/>"
0103             "possible false values: 0 off false</p>");
0104         return true;
0105     } else if (realcmd == QLatin1String("set-show-tabs")) {
0106         msg = i18n(
0107             "<p>set-show-tabs <b>enable</b></p>"
0108             "<p>If enabled, TAB characters and trailing whitespace will be visualized by a small dot.</p>"
0109             "<p>Possible true values: 1 on true<br/>"
0110             "possible false values: 0 off false</p>");
0111         return true;
0112     } else if (realcmd == QLatin1String("set-remove-trailing-spaces")) {
0113         msg = i18n(
0114             "<p>set-remove-trailing-spaces <b>mode</b></p>"
0115             "<p>Removes the trailing spaces in the document depending on the <b>mode</b>.</p>"
0116             "<p>Possible values:"
0117             "<ul>"
0118             "<li><b>none</b>: never remove trailing spaces.</li>"
0119             "<li><b>modified</b>: remove trailing spaces only of modified lines.</li>"
0120             "<li><b>all</b>: remove trailing spaces in the entire document.</li>"
0121             "</ul></p>");
0122         return true;
0123     } else if (realcmd == QLatin1String("set-indent-width")) {
0124         msg = i18n(
0125             "<p>set-indent-width <b>width</b></p>"
0126             "<p>Sets the indentation width to the number <b>width</b>. Used only if you are indenting with spaces.</p>");
0127         return true;
0128     } else if (realcmd == QLatin1String("set-indent-mode")) {
0129         msg = i18n(
0130             "<p>set-indent-mode <b>mode</b></p>"
0131             "<p>The mode parameter is a value as seen in the Tools - Indentation menu</p>");
0132         return true;
0133     } else if (realcmd == QLatin1String("set-auto-indent")) {
0134         msg = i18n(
0135             "<p>set-auto-indent <b>enable</b></p>"
0136             "<p>Enable or disable autoindentation.</p>"
0137             "<p>possible true values: 1 on true<br/>"
0138             "possible false values: 0 off false</p>");
0139         return true;
0140     } else if (realcmd == QLatin1String("set-line-numbers")) {
0141         msg = i18n(
0142             "<p>set-line-numbers <b>enable</b></p>"
0143             "<p>Sets the visibility of the line numbers pane.</p>"
0144             "<p> possible true values: 1 on true<br/>"
0145             "possible false values: 0 off false</p>");
0146         return true;
0147     } else if (realcmd == QLatin1String("set-folding-markers")) {
0148         msg = i18n(
0149             "<p>set-folding-markers <b>enable</b></p>"
0150             "<p>Sets the visibility of the folding markers pane.</p>"
0151             "<p> possible true values: 1 on true<br/>"
0152             "possible false values: 0 off false</p>");
0153         return true;
0154     } else if (realcmd == QLatin1String("set-icon-border")) {
0155         msg = i18n(
0156             "<p>set-icon-border <b>enable</b></p>"
0157             "<p>Sets the visibility of the icon border.</p>"
0158             "<p> possible true values: 1 on true<br/>"
0159             "possible false values: 0 off false</p>");
0160         return true;
0161     } else if (realcmd == QLatin1String("set-word-wrap")) {
0162         msg = i18n(
0163             "<p>set-word-wrap <b>enable</b></p>"
0164             "<p>Enables dynamic word wrap according to <b>enable</b></p>"
0165             "<p> possible true values: 1 on true<br/>"
0166             "possible false values: 0 off false</p>");
0167         return true;
0168     } else if (realcmd == QLatin1String("set-word-wrap-column")) {
0169         msg = i18n(
0170             "<p>set-word-wrap-column <b>width</b></p>"
0171             "<p>Sets the line width for hard wrapping to <b>width</b>. This is used if you are having your text wrapped automatically.</p>");
0172         return true;
0173     } else if (realcmd == QLatin1String("set-replace-tabs-save")) {
0174         msg = i18n(
0175             "<p>set-replace-tabs-save <b>enable</b></p>"
0176             "<p>When enabled, tabs will be replaced with whitespace whenever the document is saved.</p>"
0177             "<p> possible true values: 1 on true<br/>"
0178             "possible false values: 0 off false</p>");
0179         return true;
0180     } else if (realcmd == QLatin1String("set-highlight")) {
0181         msg = i18n(
0182             "<p>set-highlight <b>highlight</b></p>"
0183             "<p>Sets the syntax highlighting system for the document. The argument must be a valid highlight name, as seen in the Tools → Highlighting menu. "
0184             "This command provides an autocompletion list for its argument.</p>");
0185         return true;
0186     } else if (realcmd == QLatin1String("set-mode")) {
0187         msg = i18n(
0188             "<p>set-mode <b>mode</b></p>"
0189             "<p>Sets the mode as seen in Tools - Mode</p>");
0190         return true;
0191     } else if (realcmd == QLatin1String("set-show-indent")) {
0192         msg = i18n(
0193             "<p>set-show-indent <b>enable</b></p>"
0194             "<p>If enabled, indentation will be visualized by a vertical dotted line.</p>"
0195             "<p> possible true values: 1 on true<br/>"
0196             "possible false values: 0 off false</p>");
0197         return true;
0198     } else if (realcmd == QLatin1String("print")) {
0199         msg = i18n("<p>Open the Print dialog to print the current document.</p>");
0200         return true;
0201     } else {
0202         return false;
0203     }
0204 }
0205 
0206 bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg, const KTextEditor::Range &range)
0207 {
0208 #define KCC_ERR(s)                                                                                                                                             \
0209     {                                                                                                                                                          \
0210         errorMsg = s;                                                                                                                                          \
0211         return false;                                                                                                                                          \
0212     }
0213     // cast it hardcore, we know that it is really a kateview :)
0214     KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view);
0215 
0216     if (!v) {
0217         KCC_ERR(i18n("Could not access view"));
0218     }
0219 
0220     // create a list of args
0221     QStringList args(_cmd.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts));
0222     QString cmd(args.takeFirst());
0223 
0224     // ALL commands that takes no arguments.
0225     if (cmd == QLatin1String("indent")) {
0226         if (range.isValid()) {
0227             v->doc()->editStart();
0228             for (int line = range.start().line(); line <= range.end().line(); line++) {
0229                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), 1);
0230             }
0231             v->doc()->editEnd();
0232         } else {
0233             v->indent();
0234         }
0235         return true;
0236     } else if (cmd == QLatin1String("unindent")) {
0237         if (range.isValid()) {
0238             v->doc()->editStart();
0239             for (int line = range.start().line(); line <= range.end().line(); line++) {
0240                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), -1);
0241             }
0242             v->doc()->editEnd();
0243         } else {
0244             v->unIndent();
0245         }
0246         return true;
0247     } else if (cmd == QLatin1String("cleanindent")) {
0248         if (range.isValid()) {
0249             v->doc()->editStart();
0250             for (int line = range.start().line(); line <= range.end().line(); line++) {
0251                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), 0);
0252             }
0253             v->doc()->editEnd();
0254         } else {
0255             v->cleanIndent();
0256         }
0257         return true;
0258     } else if (cmd == QLatin1String("fold")) {
0259         return (v->textFolding().newFoldingRange(range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Persistent | Kate::TextFolding::Folded)
0260                 != -1);
0261     } else if (cmd == QLatin1String("tfold")) {
0262         return (v->textFolding().newFoldingRange(range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Folded) != -1);
0263     } else if (cmd == QLatin1String("unfold")) {
0264         QVector<QPair<qint64, Kate::TextFolding::FoldingRangeFlags>> startingRanges = v->textFolding().foldingRangesStartingOnLine(v->cursorPosition().line());
0265         bool unfolded = false;
0266         for (int i = 0; i < startingRanges.size(); ++i) {
0267             if (startingRanges[i].second & Kate::TextFolding::Folded) {
0268                 unfolded = v->textFolding().unfoldRange(startingRanges[i].first) || unfolded;
0269             }
0270         }
0271         return unfolded;
0272     } else if (cmd == QLatin1String("comment")) {
0273         if (range.isValid()) {
0274             v->doc()->editStart();
0275             for (int line = range.start().line(); line <= range.end().line(); line++) {
0276                 v->doc()->comment(v, line, 0, KTextEditor::DocumentPrivate::Comment);
0277             }
0278             v->doc()->editEnd();
0279         } else {
0280             v->comment();
0281         }
0282         return true;
0283     } else if (cmd == QLatin1String("uncomment")) {
0284         if (range.isValid()) {
0285             v->doc()->editStart();
0286             for (int line = range.start().line(); line <= range.end().line(); line++) {
0287                 v->doc()->comment(v, line, 0, KTextEditor::DocumentPrivate::UnComment);
0288             }
0289             v->doc()->editEnd();
0290         } else {
0291             v->uncomment();
0292         }
0293         return true;
0294     } else if (cmd == QLatin1String("kill-line")) {
0295         if (range.isValid()) {
0296             v->doc()->editStart();
0297             for (int line = range.start().line(); line <= range.end().line(); line++) {
0298                 v->doc()->removeLine(range.start().line());
0299             }
0300             v->doc()->editEnd();
0301         } else {
0302             v->killLine();
0303         }
0304         return true;
0305     } else if (cmd == QLatin1String("print")) {
0306         v->print();
0307         return true;
0308     }
0309 
0310     // ALL commands that take a string argument
0311     else if (cmd == QLatin1String("set-indent-mode") || cmd == QLatin1String("set-highlight") || cmd == QLatin1String("set-mode")) {
0312         // need at least one item, otherwise args.first() crashes
0313         if (args.isEmpty()) {
0314             KCC_ERR(i18n("Missing argument. Usage: %1 <value>", cmd));
0315         }
0316 
0317         if (cmd == QLatin1String("set-indent-mode")) {
0318             v->doc()->config()->setIndentationMode(args.join(QLatin1Char(' ')));
0319             v->doc()->rememberUserDidSetIndentationMode();
0320             return true;
0321         } else if (cmd == QLatin1String("set-highlight")) {
0322             if (v->doc()->setHighlightingMode(args.join(QLatin1Char(' ')))) {
0323                 static_cast<KTextEditor::DocumentPrivate *>(v->doc())->setDontChangeHlOnSave();
0324                 return true;
0325             }
0326 
0327             KCC_ERR(i18n("No such highlighting '%1'", args.first()));
0328         } else if (cmd == QLatin1String("set-mode")) {
0329             if (v->doc()->setMode(args.first())) {
0330                 return true;
0331             }
0332 
0333             KCC_ERR(i18n("No such mode '%1'", args.first()));
0334         }
0335     }
0336     // ALL commands that takes exactly one integer argument.
0337     else if (cmd == QLatin1String("set-tab-width") || cmd == QLatin1String("set-indent-width") || cmd == QLatin1String("set-word-wrap-column")
0338              || cmd == QLatin1String("goto")) {
0339         // find a integer value > 0
0340         if (args.isEmpty()) {
0341             KCC_ERR(i18n("Missing argument. Usage: %1 <value>", cmd));
0342         }
0343         bool ok;
0344         int val(args.first().toInt(&ok, 10)); // use base 10 even if the string starts with '0'
0345         if (!ok)
0346             KCC_ERR(i18n("Failed to convert argument '%1' to integer.", args.first()));
0347 
0348         if (cmd == QLatin1String("set-tab-width")) {
0349             if (val < 1) {
0350                 KCC_ERR(i18n("Width must be at least 1."));
0351             }
0352             v->doc()->config()->setTabWidth(val);
0353         } else if (cmd == QLatin1String("set-indent-width")) {
0354             if (val < 1) {
0355                 KCC_ERR(i18n("Width must be at least 1."));
0356             }
0357             v->doc()->config()->setIndentationWidth(val);
0358         } else if (cmd == QLatin1String("set-word-wrap-column")) {
0359             if (val < 2) {
0360                 KCC_ERR(i18n("Column must be at least 1."));
0361             }
0362             v->doc()->setWordWrapAt(val);
0363         } else if (cmd == QLatin1String("goto")) {
0364             if (args.first().at(0) == QLatin1Char('-') || args.first().at(0) == QLatin1Char('+')) {
0365                 // if the number starts with a minus or plus sign, add/subtract the number
0366                 val = v->cursorPosition().line() + val;
0367             } else {
0368                 val--; // convert given line number to the internal representation of line numbers
0369             }
0370 
0371             // constrain cursor to the range [0, number of lines]
0372             if (val < 0) {
0373                 val = 0;
0374             } else if (val > v->doc()->lines() - 1) {
0375                 val = v->doc()->lines() - 1;
0376             }
0377 
0378             v->setCursorPosition(KTextEditor::Cursor(val, 0));
0379             return true;
0380         }
0381         return true;
0382     }
0383 
0384     // ALL commands that takes 1 boolean argument.
0385     else if (cmd == QLatin1String("set-icon-border") || cmd == QLatin1String("set-folding-markers") || cmd == QLatin1String("set-indent-pasted-text")
0386              || cmd == QLatin1String("set-line-numbers") || cmd == QLatin1String("set-replace-tabs") || cmd == QLatin1String("set-show-tabs")
0387              || cmd == QLatin1String("set-word-wrap") || cmd == QLatin1String("set-wrap-cursor") || cmd == QLatin1String("set-replace-tabs-save")
0388              || cmd == QLatin1String("set-show-indent")) {
0389         if (args.isEmpty()) {
0390             KCC_ERR(i18n("Usage: %1 on|off|1|0|true|false", cmd));
0391         }
0392         bool enable = false;
0393         KateDocumentConfig *const config = v->doc()->config();
0394         if (getBoolArg(args.first(), &enable)) {
0395             if (cmd == QLatin1String("set-icon-border")) {
0396                 v->setIconBorder(enable);
0397             } else if (cmd == QLatin1String("set-folding-markers")) {
0398                 v->setFoldingMarkersOn(enable);
0399             } else if (cmd == QLatin1String("set-line-numbers")) {
0400                 v->setLineNumbersOn(enable);
0401             } else if (cmd == QLatin1String("set-show-indent")) {
0402                 v->renderer()->setShowIndentLines(enable);
0403             } else if (cmd == QLatin1String("set-indent-pasted-text")) {
0404                 config->setIndentPastedText(enable);
0405             } else if (cmd == QLatin1String("set-replace-tabs")) {
0406                 config->setReplaceTabsDyn(enable);
0407             } else if (cmd == QLatin1String("set-show-tabs")) {
0408                 config->setShowTabs(enable);
0409             } else if (cmd == QLatin1String("set-show-trailing-spaces")) {
0410                 config->setShowSpaces(enable ? KateDocumentConfig::Trailing : KateDocumentConfig::None);
0411             } else if (cmd == QLatin1String("set-word-wrap")) {
0412                 v->doc()->setWordWrap(enable);
0413             }
0414 
0415             return true;
0416         } else
0417             KCC_ERR(i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false", args.first(), cmd));
0418     } else if (cmd == QLatin1String("set-remove-trailing-spaces")) {
0419         // need at least one item, otherwise args.first() crashes
0420         if (args.count() != 1) {
0421             KCC_ERR(i18n("Usage: set-remove-trailing-spaces 0|-|none or 1|+|mod|modified or 2|*|all"));
0422         }
0423 
0424         QString tmp = args.first().toLower().trimmed();
0425         if (tmp == QLatin1String("1") || tmp == QLatin1String("modified") || tmp == QLatin1String("mod") || tmp == QLatin1String("+")) {
0426             v->doc()->config()->setRemoveSpaces(1);
0427         } else if (tmp == QLatin1String("2") || tmp == QLatin1String("all") || tmp == QLatin1String("*")) {
0428             v->doc()->config()->setRemoveSpaces(2);
0429         } else {
0430             v->doc()->config()->setRemoveSpaces(0);
0431         }
0432     }
0433 
0434     // unlikely..
0435     KCC_ERR(i18n("Unknown command '%1'", cmd));
0436 }
0437 
0438 bool KateCommands::CoreCommands::supportsRange(const QString &range)
0439 {
0440     static QStringList l;
0441 
0442     if (l.isEmpty()) {
0443         l << QStringLiteral("indent") << QStringLiteral("unindent") << QStringLiteral("cleanindent") << QStringLiteral("comment") << QStringLiteral("uncomment")
0444           << QStringLiteral("kill-line") << QStringLiteral("fold") << QStringLiteral("tfold");
0445     }
0446 
0447     return l.contains(range);
0448 }
0449 
0450 KCompletion *KateCommands::CoreCommands::completionObject(KTextEditor::View *view, const QString &cmd)
0451 {
0452     Q_UNUSED(view)
0453 
0454     if (cmd == QLatin1String("set-highlight")) {
0455         QStringList l;
0456         l.reserve(KateHlManager::self()->modeList().size());
0457         const auto modeList = KateHlManager::self()->modeList();
0458         for (const auto &hl : modeList) {
0459             l << hl.name();
0460         }
0461 
0462         KateCmdShellCompletion *co = new KateCmdShellCompletion();
0463         co->setItems(l);
0464         co->setIgnoreCase(true);
0465         return co;
0466     } else if (cmd == QLatin1String("set-remove-trailing-spaces")) {
0467         QStringList l;
0468         l << QStringLiteral("none") << QStringLiteral("modified") << QStringLiteral("all");
0469 
0470         KateCmdShellCompletion *co = new KateCmdShellCompletion();
0471         co->setItems(l);
0472         co->setIgnoreCase(true);
0473         return co;
0474     } else if (cmd == QLatin1String("set-indent-mode")) {
0475         QStringList l = KateAutoIndent::listIdentifiers();
0476         KateCmdShellCompletion *co = new KateCmdShellCompletion();
0477         co->setItems(l);
0478         co->setIgnoreCase(true);
0479         return co;
0480     }
0481 
0482     return nullptr;
0483 }
0484 // END CoreCommands
0485 
0486 // BEGIN Character
0487 KateCommands::Character *KateCommands::Character::m_instance = nullptr;
0488 
0489 bool KateCommands::Character::help(class KTextEditor::View *, const QString &cmd, QString &msg)
0490 {
0491     if (cmd.trimmed() == QLatin1String("char")) {
0492         msg = i18n(
0493             "<p> char <b>identifier</b> </p>"
0494             "<p>This command allows you to insert literal characters by their numerical identifier, in decimal, octal or hexadecimal form.</p>"
0495             "<p>Examples:<ul>"
0496             "<li>char <b>234</b></li>"
0497             "<li>char <b>0x1234</b></li>"
0498             "</ul></p>");
0499         return true;
0500     }
0501     return false;
0502 }
0503 
0504 bool KateCommands::Character::exec(KTextEditor::View *view, const QString &_cmd, QString &, const KTextEditor::Range &)
0505 {
0506     QString cmd = _cmd;
0507 
0508     // hex, octal, base 9+1
0509     static const QRegularExpression num(QStringLiteral("^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,5})$"));
0510     const QRegularExpressionMatch match = num.match(cmd);
0511     if (!match.hasMatch()) {
0512         return false;
0513     }
0514 
0515     cmd = match.captured(1);
0516 
0517     // identify the base
0518 
0519     unsigned short int number = 0;
0520     int base = 10;
0521     if (cmd.startsWith(QLatin1Char('x'))) {
0522         cmd.remove(0, 1);
0523         base = 16;
0524     } else if (cmd.startsWith(QLatin1String("0x"))) {
0525         cmd.remove(0, 2);
0526         base = 16;
0527     } else if (cmd[0] == QLatin1Char('0')) {
0528         base = 8;
0529     }
0530     bool ok;
0531     number = cmd.toUShort(&ok, base);
0532     if (!ok || number == 0) {
0533         return false;
0534     }
0535     if (number <= 255) {
0536         char buf[2];
0537         buf[0] = (char)number;
0538         buf[1] = 0;
0539 
0540         view->document()->insertText(view->cursorPosition(), QString::fromLatin1(buf));
0541     } else {
0542         // do the unicode thing
0543         QChar c(number);
0544 
0545         view->document()->insertText(view->cursorPosition(), QString(&c, 1));
0546     }
0547 
0548     return true;
0549 }
0550 
0551 // END Character
0552 
0553 // BEGIN Date
0554 KateCommands::Date *KateCommands::Date::m_instance = nullptr;
0555 
0556 bool KateCommands::Date::help(class KTextEditor::View *, const QString &cmd, QString &msg)
0557 {
0558     if (cmd.trimmed() == QLatin1String("date")) {
0559         msg = i18n(
0560             "<p>date or date <b>format</b></p>"
0561             "<p>Inserts a date/time string as defined by the specified format, or the format yyyy-MM-dd hh:mm:ss if none is specified.</p>"
0562             "<p>Possible format specifiers are:"
0563             "<table>"
0564             "<tr><td>d</td><td>The day as number without a leading zero (1-31).</td></tr>"
0565             "<tr><td>dd</td><td>The day as number with a leading zero (01-31).</td></tr>"
0566             "<tr><td>ddd</td><td>The abbreviated localized day name (e.g. 'Mon'..'Sun').</td></tr>"
0567             "<tr><td>dddd</td><td>The long localized day name (e.g. 'Monday'..'Sunday').</td></tr>"
0568             "<tr><td>M</td><td>The month as number without a leading zero (1-12).</td></tr>"
0569             "<tr><td>MM</td><td>The month as number with a leading zero (01-12).</td></tr>"
0570             "<tr><td>MMM</td><td>The abbreviated localized month name (e.g. 'Jan'..'Dec').</td></tr>"
0571             "<tr><td>yy</td><td>The year as two digit number (00-99).</td></tr>"
0572             "<tr><td>yyyy</td><td>The year as four digit number (1752-8000).</td></tr>"
0573             "<tr><td>h</td><td>The hour without a leading zero (0..23 or 1..12 if AM/PM display).</td></tr>"
0574             "<tr><td>hh</td><td>The hour with a leading zero (00..23 or 01..12 if AM/PM display).</td></tr>"
0575             "<tr><td>m</td><td>The minute without a leading zero (0..59).</td></tr>"
0576             "<tr><td>mm</td><td>The minute with a leading zero (00..59).</td></tr>"
0577             "<tr><td>s</td><td>The second without a leading zero (0..59).</td></tr>"
0578             "<tr><td>ss</td><td>The second with a leading zero (00..59).</td></tr>"
0579             "<tr><td>z</td><td>The milliseconds without leading zeroes (0..999).</td></tr>"
0580             "<tr><td>zzz</td><td>The milliseconds with leading zeroes (000..999).</td></tr>"
0581             "<tr><td>AP</td><td>Use AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</td></tr>"
0582             "<tr><td>ap</td><td>Use am/pm display. ap will be replaced by either \"am\" or \"pm\".</td></tr>"
0583             "</table></p>");
0584         return true;
0585     }
0586     return false;
0587 }
0588 
0589 bool KateCommands::Date::exec(KTextEditor::View *view, const QString &cmd, QString &, const KTextEditor::Range &)
0590 {
0591     if (!cmd.startsWith(QLatin1String("date"))) {
0592         return false;
0593     }
0594 
0595     if (QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length() - 5)).length() > 0) {
0596         view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length() - 5)));
0597     } else {
0598         view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")));
0599     }
0600 
0601     return true;
0602 }
0603 
0604 // END Date