1 /*
2     SPDX-FileCopyrightText: 2003-2005 Anders Lund <anders@alweb.dk>
3     SPDX-FileCopyrightText: 2001-2010 Christoph Cullmann <cullmann@kde.org>
4     SPDX-FileCopyrightText: 2001 Charles Samuels <charles@kde.org>
5 
6     SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "katecmds.h"
10 
11 #include "kateautoindent.h"
12 #include "katecmd.h"
13 #include "katedocument.h"
14 #include "katepartdebug.h"
15 #include "katerenderer.h"
16 #include "katesyntaxmanager.h"
17 #include "katetextline.h"
18 #include "kateview.h"
19 
20 #include <KLocalizedString>
21 
22 #include <QDateTime>
23 #include <QRegularExpression>
24 
25 // BEGIN CoreCommands
26 KateCommands::CoreCommands *KateCommands::CoreCommands::m_instance = nullptr;
27 
28 // this returns whether the string s could be converted to
29 // a bool value, one of on|off|1|0|true|false. the argument val is
30 // set to the extracted value in case of success
getBoolArg(const QString & t,bool * val)31 static bool getBoolArg(const QString &t, bool *val)
32 {
33     bool res(false);
34     QString s = t.toLower();
35     res = (s == QLatin1String("on") || s == QLatin1String("1") || s == QLatin1String("true"));
36     if (res) {
37         *val = true;
38         return true;
39     }
40     res = (s == QLatin1String("off") || s == QLatin1String("0") || s == QLatin1String("false"));
41     if (res) {
42         *val = false;
43         return true;
44     }
45     return false;
46 }
47 
help(KTextEditor::View *,const QString & cmd,QString & msg)48 bool KateCommands::CoreCommands::help(KTextEditor::View *, const QString &cmd, QString &msg)
49 {
50     QString realcmd = cmd.trimmed();
51     if (realcmd == QLatin1String("indent")) {
52         msg = i18n(
53             "<p>indent</p>"
54             "<p>Indents the selected lines or the current line</p>");
55         return true;
56     } else if (realcmd == QLatin1String("unindent")) {
57         msg = i18n(
58             "<p>unindent</p>"
59             "<p>Unindents the selected lines or current line.</p>");
60         return true;
61     } else if (realcmd == QLatin1String("cleanindent")) {
62         msg = i18n(
63             "<p>cleanindent</p>"
64             "<p>Cleans up the indentation of the selected lines or current line according to the indentation settings in the document. </p>");
65         return true;
66     } else if (realcmd == QLatin1String("comment")) {
67         msg = i18n(
68             "<p>comment</p>"
69             "<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 "
70             "syntax highlight definition for the document.</p>");
71         return true;
72     } else if (realcmd == QLatin1String("uncomment")) {
73         msg = i18n(
74             "<p>uncomment</p>"
75             "<p>Removes comment markers from the selection or selected lines or current line according to the text format as defined by the syntax highlight "
76             "definition for the document.</p>");
77         return true;
78     } else if (realcmd == QLatin1String("goto")) {
79         msg = i18n(
80             "<p>goto <b>line number</b></p>"
81             "<p>This command navigates to the specified line number.</p>");
82         return true;
83     } else if (realcmd == QLatin1String("set-indent-pasted-text")) {
84         msg = i18n(
85             "<p>set-indent-pasted-text <b>enable</b></p>"
86             "<p>If enabled, indentation of text pasted from the clipboard is adjusted using the current indenter.</p>"
87             "<p>Possible true values: 1 on true<br/>"
88             "possible false values: 0 off false</p>");
89         return true;
90     } else if (realcmd == QLatin1String("kill-line")) {
91         msg = i18n("Deletes the current line.");
92         return true;
93     } else if (realcmd == QLatin1String("set-tab-width")) {
94         msg = i18n(
95             "<p>set-tab-width <b>width</b></p>"
96             "<p>Sets the tab width to the number <b>width</b></p>");
97         return true;
98     } else if (realcmd == QLatin1String("set-replace-tab")) {
99         msg = i18n(
100             "<p>set-replace-tab <b>enable</b></p>"
101             "<p>If enabled, tabs are replaced with spaces as you type.</p>"
102             "<p>Possible true values: 1 on true<br/>"
103             "possible false values: 0 off false</p>");
104         return true;
105     } else if (realcmd == QLatin1String("set-show-tabs")) {
106         msg = i18n(
107             "<p>set-show-tabs <b>enable</b></p>"
108             "<p>If enabled, TAB characters and trailing whitespace will be visualized by a small dot.</p>"
109             "<p>Possible true values: 1 on true<br/>"
110             "possible false values: 0 off false</p>");
111         return true;
112     } else if (realcmd == QLatin1String("set-remove-trailing-spaces")) {
113         msg = i18n(
114             "<p>set-remove-trailing-spaces <b>mode</b></p>"
115             "<p>Removes the trailing spaces in the document depending on the <b>mode</b>.</p>"
116             "<p>Possible values:"
117             "<ul>"
118             "<li><b>none</b>: never remove trailing spaces.</li>"
119             "<li><b>modified</b>: remove trailing spaces only of modified lines.</li>"
120             "<li><b>all</b>: remove trailing spaces in the entire document.</li>"
121             "</ul></p>");
122         return true;
123     } else if (realcmd == QLatin1String("set-indent-width")) {
124         msg = i18n(
125             "<p>set-indent-width <b>width</b></p>"
126             "<p>Sets the indentation width to the number <b>width</b>. Used only if you are indenting with spaces.</p>");
127         return true;
128     } else if (realcmd == QLatin1String("set-indent-mode")) {
129         msg = i18n(
130             "<p>set-indent-mode <b>mode</b></p>"
131             "<p>The mode parameter is a value as seen in the Tools - Indentation menu</p>");
132         return true;
133     } else if (realcmd == QLatin1String("set-auto-indent")) {
134         msg = i18n(
135             "<p>set-auto-indent <b>enable</b></p>"
136             "<p>Enable or disable autoindentation.</p>"
137             "<p>possible true values: 1 on true<br/>"
138             "possible false values: 0 off false</p>");
139         return true;
140     } else if (realcmd == QLatin1String("set-line-numbers")) {
141         msg = i18n(
142             "<p>set-line-numbers <b>enable</b></p>"
143             "<p>Sets the visibility of the line numbers pane.</p>"
144             "<p> possible true values: 1 on true<br/>"
145             "possible false values: 0 off false</p>");
146         return true;
147     } else if (realcmd == QLatin1String("set-folding-markers")) {
148         msg = i18n(
149             "<p>set-folding-markers <b>enable</b></p>"
150             "<p>Sets the visibility of the folding markers pane.</p>"
151             "<p> possible true values: 1 on true<br/>"
152             "possible false values: 0 off false</p>");
153         return true;
154     } else if (realcmd == QLatin1String("set-icon-border")) {
155         msg = i18n(
156             "<p>set-icon-border <b>enable</b></p>"
157             "<p>Sets the visibility of the icon border.</p>"
158             "<p> possible true values: 1 on true<br/>"
159             "possible false values: 0 off false</p>");
160         return true;
161     } else if (realcmd == QLatin1String("set-word-wrap")) {
162         msg = i18n(
163             "<p>set-word-wrap <b>enable</b></p>"
164             "<p>Enables dynamic word wrap according to <b>enable</b></p>"
165             "<p> possible true values: 1 on true<br/>"
166             "possible false values: 0 off false</p>");
167         return true;
168     } else if (realcmd == QLatin1String("set-word-wrap-column")) {
169         msg = i18n(
170             "<p>set-word-wrap-column <b>width</b></p>"
171             "<p>Sets the line width for hard wrapping to <b>width</b>. This is used if you are having your text wrapped automatically.</p>");
172         return true;
173     } else if (realcmd == QLatin1String("set-replace-tabs-save")) {
174         msg = i18n(
175             "<p>set-replace-tabs-save <b>enable</b></p>"
176             "<p>When enabled, tabs will be replaced with whitespace whenever the document is saved.</p>"
177             "<p> possible true values: 1 on true<br/>"
178             "possible false values: 0 off false</p>");
179         return true;
180     } else if (realcmd == QLatin1String("set-highlight")) {
181         msg = i18n(
182             "<p>set-highlight <b>highlight</b></p>"
183             "<p>Sets the syntax highlighting system for the document. The argument must be a valid highlight name, as seen in the Tools → Highlighting menu. "
184             "This command provides an autocompletion list for its argument.</p>");
185         return true;
186     } else if (realcmd == QLatin1String("set-mode")) {
187         msg = i18n(
188             "<p>set-mode <b>mode</b></p>"
189             "<p>Sets the mode as seen in Tools - Mode</p>");
190         return true;
191     } else if (realcmd == QLatin1String("set-show-indent")) {
192         msg = i18n(
193             "<p>set-show-indent <b>enable</b></p>"
194             "<p>If enabled, indentation will be visualized by a vertical dotted line.</p>"
195             "<p> possible true values: 1 on true<br/>"
196             "possible false values: 0 off false</p>");
197         return true;
198     } else if (realcmd == QLatin1String("print")) {
199         msg = i18n("<p>Open the Print dialog to print the current document.</p>");
200         return true;
201     } else {
202         return false;
203     }
204 }
205 
exec(KTextEditor::View * view,const QString & _cmd,QString & errorMsg,const KTextEditor::Range & range)206 bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg, const KTextEditor::Range &range)
207 {
208 #define KCC_ERR(s)                                                                                                                                             \
209     {                                                                                                                                                          \
210         errorMsg = s;                                                                                                                                          \
211         return false;                                                                                                                                          \
212     }
213     // cast it hardcore, we know that it is really a kateview :)
214     KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view);
215 
216     if (!v) {
217         KCC_ERR(i18n("Could not access view"));
218     }
219 
220     // create a list of args
221     QStringList args(_cmd.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts));
222     QString cmd(args.takeFirst());
223 
224     // ALL commands that takes no arguments.
225     if (cmd == QLatin1String("indent")) {
226         if (range.isValid()) {
227             v->doc()->editStart();
228             for (int line = range.start().line(); line <= range.end().line(); line++) {
229                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), 1);
230             }
231             v->doc()->editEnd();
232         } else {
233             v->indent();
234         }
235         return true;
236     } else if (cmd == QLatin1String("unindent")) {
237         if (range.isValid()) {
238             v->doc()->editStart();
239             for (int line = range.start().line(); line <= range.end().line(); line++) {
240                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), -1);
241             }
242             v->doc()->editEnd();
243         } else {
244             v->unIndent();
245         }
246         return true;
247     } else if (cmd == QLatin1String("cleanindent")) {
248         if (range.isValid()) {
249             v->doc()->editStart();
250             for (int line = range.start().line(); line <= range.end().line(); line++) {
251                 v->doc()->indent(KTextEditor::Range(line, 0, line, 0), 0);
252             }
253             v->doc()->editEnd();
254         } else {
255             v->cleanIndent();
256         }
257         return true;
258     } else if (cmd == QLatin1String("fold")) {
259         return (v->textFolding().newFoldingRange(range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Persistent | Kate::TextFolding::Folded)
260                 != -1);
261     } else if (cmd == QLatin1String("tfold")) {
262         return (v->textFolding().newFoldingRange(range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Folded) != -1);
263     } else if (cmd == QLatin1String("unfold")) {
264         QVector<QPair<qint64, Kate::TextFolding::FoldingRangeFlags>> startingRanges = v->textFolding().foldingRangesStartingOnLine(v->cursorPosition().line());
265         bool unfolded = false;
266         for (int i = 0; i < startingRanges.size(); ++i) {
267             if (startingRanges[i].second & Kate::TextFolding::Folded) {
268                 unfolded = v->textFolding().unfoldRange(startingRanges[i].first) || unfolded;
269             }
270         }
271         return unfolded;
272     } else if (cmd == QLatin1String("comment")) {
273         if (range.isValid()) {
274             v->doc()->editStart();
275             for (int line = range.start().line(); line <= range.end().line(); line++) {
276                 v->doc()->comment(v, line, 0, 1);
277             }
278             v->doc()->editEnd();
279         } else {
280             v->comment();
281         }
282         return true;
283     } else if (cmd == QLatin1String("uncomment")) {
284         if (range.isValid()) {
285             v->doc()->editStart();
286             for (int line = range.start().line(); line <= range.end().line(); line++) {
287                 v->doc()->comment(v, line, 0, -1);
288             }
289             v->doc()->editEnd();
290         } else {
291             v->uncomment();
292         }
293         return true;
294     } else if (cmd == QLatin1String("kill-line")) {
295         if (range.isValid()) {
296             v->doc()->editStart();
297             for (int line = range.start().line(); line <= range.end().line(); line++) {
298                 v->doc()->removeLine(range.start().line());
299             }
300             v->doc()->editEnd();
301         } else {
302             v->killLine();
303         }
304         return true;
305     } else if (cmd == QLatin1String("print")) {
306         v->print();
307         return true;
308     }
309 
310     // ALL commands that take a string argument
311     else if (cmd == QLatin1String("set-indent-mode") || cmd == QLatin1String("set-highlight") || cmd == QLatin1String("set-mode")) {
312         // need at least one item, otherwise args.first() crashes
313         if (args.isEmpty()) {
314             KCC_ERR(i18n("Missing argument. Usage: %1 <value>", cmd));
315         }
316 
317         if (cmd == QLatin1String("set-indent-mode")) {
318             v->doc()->config()->setIndentationMode(args.join(QLatin1Char(' ')));
319             v->doc()->rememberUserDidSetIndentationMode();
320             return true;
321         } else if (cmd == QLatin1String("set-highlight")) {
322             if (v->doc()->setHighlightingMode(args.join(QLatin1Char(' ')))) {
323                 static_cast<KTextEditor::DocumentPrivate *>(v->doc())->setDontChangeHlOnSave();
324                 return true;
325             }
326 
327             KCC_ERR(i18n("No such highlighting '%1'", args.first()));
328         } else if (cmd == QLatin1String("set-mode")) {
329             if (v->doc()->setMode(args.first())) {
330                 return true;
331             }
332 
333             KCC_ERR(i18n("No such mode '%1'", args.first()));
334         }
335     }
336     // ALL commands that takes exactly one integer argument.
337     else if (cmd == QLatin1String("set-tab-width") || cmd == QLatin1String("set-indent-width") || cmd == QLatin1String("set-word-wrap-column")
338              || cmd == QLatin1String("goto")) {
339         // find a integer value > 0
340         if (args.isEmpty()) {
341             KCC_ERR(i18n("Missing argument. Usage: %1 <value>", cmd));
342         }
343         bool ok;
344         int val(args.first().toInt(&ok, 10)); // use base 10 even if the string starts with '0'
345         if (!ok)
346             KCC_ERR(i18n("Failed to convert argument '%1' to integer.", args.first()));
347 
348         if (cmd == QLatin1String("set-tab-width")) {
349             if (val < 1) {
350                 KCC_ERR(i18n("Width must be at least 1."));
351             }
352             v->doc()->config()->setTabWidth(val);
353         } else if (cmd == QLatin1String("set-indent-width")) {
354             if (val < 1) {
355                 KCC_ERR(i18n("Width must be at least 1."));
356             }
357             v->doc()->config()->setIndentationWidth(val);
358         } else if (cmd == QLatin1String("set-word-wrap-column")) {
359             if (val < 2) {
360                 KCC_ERR(i18n("Column must be at least 1."));
361             }
362             v->doc()->setWordWrapAt(val);
363         } else if (cmd == QLatin1String("goto")) {
364             if (args.first().at(0) == QLatin1Char('-') || args.first().at(0) == QLatin1Char('+')) {
365                 // if the number starts with a minus or plus sign, add/subtract the number
366                 val = v->cursorPosition().line() + val;
367             } else {
368                 val--; // convert given line number to the internal representation of line numbers
369             }
370 
371             // constrain cursor to the range [0, number of lines]
372             if (val < 0) {
373                 val = 0;
374             } else if (val > v->doc()->lines() - 1) {
375                 val = v->doc()->lines() - 1;
376             }
377 
378             v->setCursorPosition(KTextEditor::Cursor(val, 0));
379             return true;
380         }
381         return true;
382     }
383 
384     // ALL commands that takes 1 boolean argument.
385     else if (cmd == QLatin1String("set-icon-border") || cmd == QLatin1String("set-folding-markers") || cmd == QLatin1String("set-indent-pasted-text")
386              || cmd == QLatin1String("set-line-numbers") || cmd == QLatin1String("set-replace-tabs") || cmd == QLatin1String("set-show-tabs")
387              || cmd == QLatin1String("set-word-wrap") || cmd == QLatin1String("set-wrap-cursor") || cmd == QLatin1String("set-replace-tabs-save")
388              || cmd == QLatin1String("set-show-indent")) {
389         if (args.isEmpty()) {
390             KCC_ERR(i18n("Usage: %1 on|off|1|0|true|false", cmd));
391         }
392         bool enable = false;
393         KateDocumentConfig *const config = v->doc()->config();
394         if (getBoolArg(args.first(), &enable)) {
395             if (cmd == QLatin1String("set-icon-border")) {
396                 v->setIconBorder(enable);
397             } else if (cmd == QLatin1String("set-folding-markers")) {
398                 v->setFoldingMarkersOn(enable);
399             } else if (cmd == QLatin1String("set-line-numbers")) {
400                 v->setLineNumbersOn(enable);
401             } else if (cmd == QLatin1String("set-show-indent")) {
402                 v->renderer()->setShowIndentLines(enable);
403             } else if (cmd == QLatin1String("set-indent-pasted-text")) {
404                 config->setIndentPastedText(enable);
405             } else if (cmd == QLatin1String("set-replace-tabs")) {
406                 config->setReplaceTabsDyn(enable);
407             } else if (cmd == QLatin1String("set-show-tabs")) {
408                 config->setShowTabs(enable);
409             } else if (cmd == QLatin1String("set-show-trailing-spaces")) {
410                 config->setShowSpaces(enable ? KateDocumentConfig::Trailing : KateDocumentConfig::None);
411             } else if (cmd == QLatin1String("set-word-wrap")) {
412                 v->doc()->setWordWrap(enable);
413             }
414 
415             return true;
416         } else
417             KCC_ERR(i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false", args.first(), cmd));
418     } else if (cmd == QLatin1String("set-remove-trailing-spaces")) {
419         // need at least one item, otherwise args.first() crashes
420         if (args.count() != 1) {
421             KCC_ERR(i18n("Usage: set-remove-trailing-spaces 0|-|none or 1|+|mod|modified or 2|*|all"));
422         }
423 
424         QString tmp = args.first().toLower().trimmed();
425         if (tmp == QLatin1String("1") || tmp == QLatin1String("modified") || tmp == QLatin1String("mod") || tmp == QLatin1String("+")) {
426             v->doc()->config()->setRemoveSpaces(1);
427         } else if (tmp == QLatin1String("2") || tmp == QLatin1String("all") || tmp == QLatin1String("*")) {
428             v->doc()->config()->setRemoveSpaces(2);
429         } else {
430             v->doc()->config()->setRemoveSpaces(0);
431         }
432     }
433 
434     // unlikely..
435     KCC_ERR(i18n("Unknown command '%1'", cmd));
436 }
437 
supportsRange(const QString & range)438 bool KateCommands::CoreCommands::supportsRange(const QString &range)
439 {
440     static QStringList l;
441 
442     if (l.isEmpty()) {
443         l << QStringLiteral("indent") << QStringLiteral("unindent") << QStringLiteral("cleanindent") << QStringLiteral("comment") << QStringLiteral("uncomment")
444           << QStringLiteral("kill-line") << QStringLiteral("fold") << QStringLiteral("tfold");
445     }
446 
447     return l.contains(range);
448 }
449 
completionObject(KTextEditor::View * view,const QString & cmd)450 KCompletion *KateCommands::CoreCommands::completionObject(KTextEditor::View *view, const QString &cmd)
451 {
452     Q_UNUSED(view)
453 
454     if (cmd == QLatin1String("set-highlight")) {
455         QStringList l;
456         l.reserve(KateHlManager::self()->modeList().size());
457         for (const auto &hl : KateHlManager::self()->modeList()) {
458             l << hl.name();
459         }
460 
461         KateCmdShellCompletion *co = new KateCmdShellCompletion();
462         co->setItems(l);
463         co->setIgnoreCase(true);
464         return co;
465     } else if (cmd == QLatin1String("set-remove-trailing-spaces")) {
466         QStringList l;
467         l << QStringLiteral("none") << QStringLiteral("modified") << QStringLiteral("all");
468 
469         KateCmdShellCompletion *co = new KateCmdShellCompletion();
470         co->setItems(l);
471         co->setIgnoreCase(true);
472         return co;
473     } else if (cmd == QLatin1String("set-indent-mode")) {
474         QStringList l = KateAutoIndent::listIdentifiers();
475         KateCmdShellCompletion *co = new KateCmdShellCompletion();
476         co->setItems(l);
477         co->setIgnoreCase(true);
478         return co;
479     }
480 
481     return nullptr;
482 }
483 // END CoreCommands
484 
485 // BEGIN Character
486 KateCommands::Character *KateCommands::Character::m_instance = nullptr;
487 
help(class KTextEditor::View *,const QString & cmd,QString & msg)488 bool KateCommands::Character::help(class KTextEditor::View *, const QString &cmd, QString &msg)
489 {
490     if (cmd.trimmed() == QLatin1String("char")) {
491         msg = i18n(
492             "<p> char <b>identifier</b> </p>"
493             "<p>This command allows you to insert literal characters by their numerical identifier, in decimal, octal or hexadecimal form.</p>"
494             "<p>Examples:<ul>"
495             "<li>char <b>234</b></li>"
496             "<li>char <b>0x1234</b></li>"
497             "</ul></p>");
498         return true;
499     }
500     return false;
501 }
502 
exec(KTextEditor::View * view,const QString & _cmd,QString &,const KTextEditor::Range &)503 bool KateCommands::Character::exec(KTextEditor::View *view, const QString &_cmd, QString &, const KTextEditor::Range &)
504 {
505     QString cmd = _cmd;
506 
507     // hex, octal, base 9+1
508     static const QRegularExpression num(QStringLiteral("^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,5})$"));
509     const QRegularExpressionMatch match = num.match(cmd);
510     if (!match.hasMatch()) {
511         return false;
512     }
513 
514     cmd = match.captured(1);
515 
516     // identify the base
517 
518     unsigned short int number = 0;
519     int base = 10;
520     if (cmd.startsWith(QLatin1Char('x'))) {
521         cmd.remove(0, 1);
522         base = 16;
523     } else if (cmd.startsWith(QLatin1String("0x"))) {
524         cmd.remove(0, 2);
525         base = 16;
526     } else if (cmd[0] == QLatin1Char('0')) {
527         base = 8;
528     }
529     bool ok;
530     number = cmd.toUShort(&ok, base);
531     if (!ok || number == 0) {
532         return false;
533     }
534     if (number <= 255) {
535         char buf[2];
536         buf[0] = (char)number;
537         buf[1] = 0;
538 
539         view->document()->insertText(view->cursorPosition(), QString::fromLatin1(buf));
540     } else {
541         // do the unicode thing
542         QChar c(number);
543 
544         view->document()->insertText(view->cursorPosition(), QString(&c, 1));
545     }
546 
547     return true;
548 }
549 
550 // END Character
551 
552 // BEGIN Date
553 KateCommands::Date *KateCommands::Date::m_instance = nullptr;
554 
help(class KTextEditor::View *,const QString & cmd,QString & msg)555 bool KateCommands::Date::help(class KTextEditor::View *, const QString &cmd, QString &msg)
556 {
557     if (cmd.trimmed() == QLatin1String("date")) {
558         msg = i18n(
559             "<p>date or date <b>format</b></p>"
560             "<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>"
561             "<p>Possible format specifiers are:"
562             "<table>"
563             "<tr><td>d</td><td>The day as number without a leading zero (1-31).</td></tr>"
564             "<tr><td>dd</td><td>The day as number with a leading zero (01-31).</td></tr>"
565             "<tr><td>ddd</td><td>The abbreviated localized day name (e.g. 'Mon'..'Sun').</td></tr>"
566             "<tr><td>dddd</td><td>The long localized day name (e.g. 'Monday'..'Sunday').</td></tr>"
567             "<tr><td>M</td><td>The month as number without a leading zero (1-12).</td></tr>"
568             "<tr><td>MM</td><td>The month as number with a leading zero (01-12).</td></tr>"
569             "<tr><td>MMM</td><td>The abbreviated localized month name (e.g. 'Jan'..'Dec').</td></tr>"
570             "<tr><td>yy</td><td>The year as two digit number (00-99).</td></tr>"
571             "<tr><td>yyyy</td><td>The year as four digit number (1752-8000).</td></tr>"
572             "<tr><td>h</td><td>The hour without a leading zero (0..23 or 1..12 if AM/PM display).</td></tr>"
573             "<tr><td>hh</td><td>The hour with a leading zero (00..23 or 01..12 if AM/PM display).</td></tr>"
574             "<tr><td>m</td><td>The minute without a leading zero (0..59).</td></tr>"
575             "<tr><td>mm</td><td>The minute with a leading zero (00..59).</td></tr>"
576             "<tr><td>s</td><td>The second without a leading zero (0..59).</td></tr>"
577             "<tr><td>ss</td><td>The second with a leading zero (00..59).</td></tr>"
578             "<tr><td>z</td><td>The milliseconds without leading zeroes (0..999).</td></tr>"
579             "<tr><td>zzz</td><td>The milliseconds with leading zeroes (000..999).</td></tr>"
580             "<tr><td>AP</td><td>Use AM/PM display. AP will be replaced by either \"AM\" or \"PM\".</td></tr>"
581             "<tr><td>ap</td><td>Use am/pm display. ap will be replaced by either \"am\" or \"pm\".</td></tr>"
582             "</table></p>");
583         return true;
584     }
585     return false;
586 }
587 
exec(KTextEditor::View * view,const QString & cmd,QString &,const KTextEditor::Range &)588 bool KateCommands::Date::exec(KTextEditor::View *view, const QString &cmd, QString &, const KTextEditor::Range &)
589 {
590     if (!cmd.startsWith(QLatin1String("date"))) {
591         return false;
592     }
593 
594     if (QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length() - 5)).length() > 0) {
595         view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length() - 5)));
596     } else {
597         view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss")));
598     }
599 
600     return true;
601 }
602 
603 // END Date
604