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 "kateview.h" |
18 | |
19 | #include <KLocalizedString> |
20 | |
21 | #include <QDateTime> |
22 | #include <QRegularExpression> |
23 | |
24 | // BEGIN CoreCommands |
25 | KateCommands::CoreCommands *KateCommands::CoreCommands::m_instance = nullptr; |
26 | |
27 | // this returns whether the string s could be converted to |
28 | // a bool value, one of on|off|1|0|true|false. the argument val is |
29 | // set to the extracted value in case of success |
30 | static bool getBoolArg(const QString &t, bool *val) |
31 | { |
32 | bool res(false); |
33 | QString s = t.toLower(); |
34 | res = (s == QLatin1String("on" ) || s == QLatin1String("1" ) || s == QLatin1String("true" )); |
35 | if (res) { |
36 | *val = true; |
37 | return true; |
38 | } |
39 | res = (s == QLatin1String("off" ) || s == QLatin1String("0" ) || s == QLatin1String("false" )); |
40 | if (res) { |
41 | *val = false; |
42 | return true; |
43 | } |
44 | return false; |
45 | } |
46 | |
47 | bool KateCommands::CoreCommands::help(KTextEditor::View *, const QString &cmd, QString &msg) |
48 | { |
49 | QString realcmd = cmd.trimmed(); |
50 | if (realcmd == QLatin1String("indent" )) { |
51 | msg = i18n( |
52 | "<p>indent</p>" |
53 | "<p>Indents the selected lines or the current line</p>" ); |
54 | return true; |
55 | } else if (realcmd == QLatin1String("unindent" )) { |
56 | msg = i18n( |
57 | "<p>unindent</p>" |
58 | "<p>Unindents the selected lines or current line.</p>" ); |
59 | return true; |
60 | } else if (realcmd == QLatin1String("cleanindent" )) { |
61 | msg = i18n( |
62 | "<p>cleanindent</p>" |
63 | "<p>Cleans up the indentation of the selected lines or current line according to the indentation settings in the document. </p>" ); |
64 | return true; |
65 | } else if (realcmd == QLatin1String("comment" )) { |
66 | msg = i18n( |
67 | "<p>comment</p>" |
68 | "<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 " |
69 | "syntax highlight definition for the document.</p>" ); |
70 | return true; |
71 | } else if (realcmd == QLatin1String("uncomment" )) { |
72 | msg = i18n( |
73 | "<p>uncomment</p>" |
74 | "<p>Removes comment markers from the selection or selected lines or current line according to the text format as defined by the syntax highlight " |
75 | "definition for the document.</p>" ); |
76 | return true; |
77 | } else if (realcmd == QLatin1String("goto" )) { |
78 | msg = i18n( |
79 | "<p>goto <b>line number</b></p>" |
80 | "<p>This command navigates to the specified line number.</p>" ); |
81 | return true; |
82 | } else if (realcmd == QLatin1String("set-indent-pasted-text" )) { |
83 | msg = i18n( |
84 | "<p>set-indent-pasted-text <b>enable</b></p>" |
85 | "<p>If enabled, indentation of text pasted from the clipboard is adjusted using the current indenter.</p>" |
86 | "<p>Possible true values: 1 on true<br/>" |
87 | "possible false values: 0 off false</p>" ); |
88 | return true; |
89 | } else if (realcmd == QLatin1String("kill-line" )) { |
90 | msg = i18n("Deletes the current line." ); |
91 | return true; |
92 | } else if (realcmd == QLatin1String("set-tab-width" )) { |
93 | msg = i18n( |
94 | "<p>set-tab-width <b>width</b></p>" |
95 | "<p>Sets the tab width to the number <b>width</b></p>" ); |
96 | return true; |
97 | } else if (realcmd == QLatin1String("set-replace-tab" )) { |
98 | msg = i18n( |
99 | "<p>set-replace-tab <b>enable</b></p>" |
100 | "<p>If enabled, tabs are replaced with spaces as you type.</p>" |
101 | "<p>Possible true values: 1 on true<br/>" |
102 | "possible false values: 0 off false</p>" ); |
103 | return true; |
104 | } else if (realcmd == QLatin1String("set-show-tabs" )) { |
105 | msg = i18n( |
106 | "<p>set-show-tabs <b>enable</b></p>" |
107 | "<p>If enabled, TAB characters and trailing whitespace will be visualized by a small dot.</p>" |
108 | "<p>Possible true values: 1 on true<br/>" |
109 | "possible false values: 0 off false</p>" ); |
110 | return true; |
111 | } else if (realcmd == QLatin1String("set-remove-trailing-spaces" )) { |
112 | msg = i18n( |
113 | "<p>set-remove-trailing-spaces <b>mode</b></p>" |
114 | "<p>Removes the trailing spaces in the document depending on the <b>mode</b>.</p>" |
115 | "<p>Possible values:" |
116 | "<ul>" |
117 | "<li><b>none</b>: never remove trailing spaces.</li>" |
118 | "<li><b>modified</b>: remove trailing spaces only of modified lines.</li>" |
119 | "<li><b>all</b>: remove trailing spaces in the entire document.</li>" |
120 | "</ul></p>" ); |
121 | return true; |
122 | } else if (realcmd == QLatin1String("set-indent-width" )) { |
123 | msg = i18n( |
124 | "<p>set-indent-width <b>width</b></p>" |
125 | "<p>Sets the indentation width to the number <b>width</b>. Used only if you are indenting with spaces.</p>" ); |
126 | return true; |
127 | } else if (realcmd == QLatin1String("set-indent-mode" )) { |
128 | msg = i18n( |
129 | "<p>set-indent-mode <b>mode</b></p>" |
130 | "<p>The mode parameter is a value as seen in the Tools - Indentation menu</p>" ); |
131 | return true; |
132 | } else if (realcmd == QLatin1String("set-auto-indent" )) { |
133 | msg = i18n( |
134 | "<p>set-auto-indent <b>enable</b></p>" |
135 | "<p>Enable or disable autoindentation.</p>" |
136 | "<p>possible true values: 1 on true<br/>" |
137 | "possible false values: 0 off false</p>" ); |
138 | return true; |
139 | } else if (realcmd == QLatin1String("set-line-numbers" )) { |
140 | msg = i18n( |
141 | "<p>set-line-numbers <b>enable</b></p>" |
142 | "<p>Sets the visibility of the line numbers pane.</p>" |
143 | "<p> possible true values: 1 on true<br/>" |
144 | "possible false values: 0 off false</p>" ); |
145 | return true; |
146 | } else if (realcmd == QLatin1String("set-folding-markers" )) { |
147 | msg = i18n( |
148 | "<p>set-folding-markers <b>enable</b></p>" |
149 | "<p>Sets the visibility of the folding markers pane.</p>" |
150 | "<p> possible true values: 1 on true<br/>" |
151 | "possible false values: 0 off false</p>" ); |
152 | return true; |
153 | } else if (realcmd == QLatin1String("set-icon-border" )) { |
154 | msg = i18n( |
155 | "<p>set-icon-border <b>enable</b></p>" |
156 | "<p>Sets the visibility of the icon border.</p>" |
157 | "<p> possible true values: 1 on true<br/>" |
158 | "possible false values: 0 off false</p>" ); |
159 | return true; |
160 | } else if (realcmd == QLatin1String("set-word-wrap" )) { |
161 | msg = i18n( |
162 | "<p>set-word-wrap <b>enable</b></p>" |
163 | "<p>Enables dynamic word wrap according to <b>enable</b></p>" |
164 | "<p> possible true values: 1 on true<br/>" |
165 | "possible false values: 0 off false</p>" ); |
166 | return true; |
167 | } else if (realcmd == QLatin1String("set-word-wrap-column" )) { |
168 | msg = i18n( |
169 | "<p>set-word-wrap-column <b>width</b></p>" |
170 | "<p>Sets the line width for hard wrapping to <b>width</b>. This is used if you are having your text wrapped automatically.</p>" ); |
171 | return true; |
172 | } else if (realcmd == QLatin1String("set-replace-tabs-save" )) { |
173 | msg = i18n( |
174 | "<p>set-replace-tabs-save <b>enable</b></p>" |
175 | "<p>When enabled, tabs will be replaced with whitespace whenever the document is saved.</p>" |
176 | "<p> possible true values: 1 on true<br/>" |
177 | "possible false values: 0 off false</p>" ); |
178 | return true; |
179 | } else if (realcmd == QLatin1String("set-highlight" )) { |
180 | msg = i18n( |
181 | "<p>set-highlight <b>highlight</b></p>" |
182 | "<p>Sets the syntax highlighting system for the document. The argument must be a valid highlight name, as seen in the Tools → Highlighting menu. " |
183 | "This command provides an autocompletion list for its argument.</p>" ); |
184 | return true; |
185 | } else if (realcmd == QLatin1String("set-mode" )) { |
186 | msg = i18n( |
187 | "<p>set-mode <b>mode</b></p>" |
188 | "<p>Sets the mode as seen in Tools - Mode</p>" ); |
189 | return true; |
190 | } else if (realcmd == QLatin1String("set-show-indent" )) { |
191 | msg = i18n( |
192 | "<p>set-show-indent <b>enable</b></p>" |
193 | "<p>If enabled, indentation will be visualized by a vertical dotted line.</p>" |
194 | "<p> possible true values: 1 on true<br/>" |
195 | "possible false values: 0 off false</p>" ); |
196 | return true; |
197 | } else if (realcmd == QLatin1String("print" )) { |
198 | msg = i18n("<p>Open the Print dialog to print the current document.</p>" ); |
199 | return true; |
200 | } else { |
201 | return false; |
202 | } |
203 | } |
204 | |
205 | bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg, const KTextEditor::Range &range) |
206 | { |
207 | #define KCC_ERR(s) \ |
208 | { \ |
209 | errorMsg = s; \ |
210 | return false; \ |
211 | } |
212 | // cast it hardcore, we know that it is really a kateview :) |
213 | KTextEditor::ViewPrivate *v = static_cast<KTextEditor::ViewPrivate *>(view); |
214 | |
215 | if (!v) { |
216 | KCC_ERR(i18n("Could not access view" )); |
217 | } |
218 | |
219 | // create a list of args |
220 | QStringList args(_cmd.split(sep: QRegularExpression(QStringLiteral("\\s+" )), behavior: Qt::SkipEmptyParts)); |
221 | QString cmd(args.takeFirst()); |
222 | |
223 | // ALL commands that takes no arguments. |
224 | if (cmd == QLatin1String("indent" )) { |
225 | if (range.isValid()) { |
226 | v->doc()->editStart(); |
227 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
228 | v->doc()->indent(range: KTextEditor::Range(line, 0, line, 0), change: 1); |
229 | } |
230 | v->doc()->editEnd(); |
231 | } else { |
232 | v->indent(); |
233 | } |
234 | return true; |
235 | } else if (cmd == QLatin1String("unindent" )) { |
236 | if (range.isValid()) { |
237 | v->doc()->editStart(); |
238 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
239 | v->doc()->indent(range: KTextEditor::Range(line, 0, line, 0), change: -1); |
240 | } |
241 | v->doc()->editEnd(); |
242 | } else { |
243 | v->unIndent(); |
244 | } |
245 | return true; |
246 | } else if (cmd == QLatin1String("cleanindent" )) { |
247 | if (range.isValid()) { |
248 | v->doc()->editStart(); |
249 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
250 | v->doc()->indent(range: KTextEditor::Range(line, 0, line, 0), change: 0); |
251 | } |
252 | v->doc()->editEnd(); |
253 | } else { |
254 | v->cleanIndent(); |
255 | } |
256 | return true; |
257 | } else if (cmd == QLatin1String("fold" )) { |
258 | return (v->textFolding().newFoldingRange(range: range.isValid() ? range : v->selectionRange(), flags: Kate::TextFolding::Persistent | Kate::TextFolding::Folded) |
259 | != -1); |
260 | } else if (cmd == QLatin1String("tfold" )) { |
261 | return (v->textFolding().newFoldingRange(range: range.isValid() ? range : v->selectionRange(), flags: Kate::TextFolding::Folded) != -1); |
262 | } else if (cmd == QLatin1String("unfold" )) { |
263 | QList<QPair<qint64, Kate::TextFolding::FoldingRangeFlags>> startingRanges = v->textFolding().foldingRangesStartingOnLine(line: v->cursorPosition().line()); |
264 | bool unfolded = false; |
265 | for (int i = 0; i < startingRanges.size(); ++i) { |
266 | if (startingRanges[i].second & Kate::TextFolding::Folded) { |
267 | unfolded = v->textFolding().unfoldRange(id: startingRanges[i].first) || unfolded; |
268 | } |
269 | } |
270 | return unfolded; |
271 | } else if (cmd == QLatin1String("comment" )) { |
272 | if (range.isValid()) { |
273 | v->doc()->editStart(); |
274 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
275 | v->doc()->comment(view: v, line, column: 0, change: KTextEditor::DocumentPrivate::Comment); |
276 | } |
277 | v->doc()->editEnd(); |
278 | } else { |
279 | v->comment(); |
280 | } |
281 | return true; |
282 | } else if (cmd == QLatin1String("uncomment" )) { |
283 | if (range.isValid()) { |
284 | v->doc()->editStart(); |
285 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
286 | v->doc()->comment(view: v, line, column: 0, change: KTextEditor::DocumentPrivate::UnComment); |
287 | } |
288 | v->doc()->editEnd(); |
289 | } else { |
290 | v->uncomment(); |
291 | } |
292 | return true; |
293 | } else if (cmd == QLatin1String("kill-line" )) { |
294 | if (range.isValid()) { |
295 | v->doc()->editStart(); |
296 | for (int line = range.start().line(); line <= range.end().line(); line++) { |
297 | v->doc()->removeLine(line: range.start().line()); |
298 | } |
299 | v->doc()->editEnd(); |
300 | } else { |
301 | v->killLine(); |
302 | } |
303 | return true; |
304 | } else if (cmd == QLatin1String("print" )) { |
305 | v->print(); |
306 | return true; |
307 | } |
308 | |
309 | // ALL commands that take a string argument |
310 | else if (cmd == QLatin1String("set-indent-mode" ) || cmd == QLatin1String("set-highlight" ) || cmd == QLatin1String("set-mode" )) { |
311 | // need at least one item, otherwise args.first() crashes |
312 | if (args.isEmpty()) { |
313 | KCC_ERR(i18n("Missing argument. Usage: %1 <value>" , cmd)); |
314 | } |
315 | |
316 | if (cmd == QLatin1String("set-indent-mode" )) { |
317 | v->doc()->config()->setIndentationMode(args.join(sep: QLatin1Char(' '))); |
318 | v->doc()->rememberUserDidSetIndentationMode(); |
319 | return true; |
320 | } else if (cmd == QLatin1String("set-highlight" )) { |
321 | if (v->doc()->setHighlightingMode(args.join(sep: QLatin1Char(' ')))) { |
322 | static_cast<KTextEditor::DocumentPrivate *>(v->doc())->setDontChangeHlOnSave(); |
323 | return true; |
324 | } |
325 | |
326 | KCC_ERR(i18n("No such highlighting '%1'" , args.first())); |
327 | } else if (cmd == QLatin1String("set-mode" )) { |
328 | if (v->doc()->setMode(args.first())) { |
329 | return true; |
330 | } |
331 | |
332 | KCC_ERR(i18n("No such mode '%1'" , args.first())); |
333 | } |
334 | } |
335 | // ALL commands that takes exactly one integer argument. |
336 | else if (cmd == QLatin1String("set-tab-width" ) || cmd == QLatin1String("set-indent-width" ) || cmd == QLatin1String("set-word-wrap-column" ) |
337 | || cmd == QLatin1String("goto" )) { |
338 | // find a integer value > 0 |
339 | if (args.isEmpty()) { |
340 | KCC_ERR(i18n("Missing argument. Usage: %1 <value>" , cmd)); |
341 | } |
342 | bool ok; |
343 | int val(args.first().toInt(ok: &ok, base: 10)); // use base 10 even if the string starts with '0' |
344 | if (!ok) |
345 | KCC_ERR(i18n("Failed to convert argument '%1' to integer." , args.first())); |
346 | |
347 | if (cmd == QLatin1String("set-tab-width" )) { |
348 | if (val < 1) { |
349 | KCC_ERR(i18n("Width must be at least 1." )); |
350 | } |
351 | v->doc()->config()->setTabWidth(val); |
352 | } else if (cmd == QLatin1String("set-indent-width" )) { |
353 | if (val < 1) { |
354 | KCC_ERR(i18n("Width must be at least 1." )); |
355 | } |
356 | v->doc()->config()->setIndentationWidth(val); |
357 | } else if (cmd == QLatin1String("set-word-wrap-column" )) { |
358 | if (val < 2) { |
359 | KCC_ERR(i18n("Column must be at least 1." )); |
360 | } |
361 | v->doc()->setWordWrapAt(val); |
362 | } else if (cmd == QLatin1String("goto" )) { |
363 | if (args.first().at(i: 0) == QLatin1Char('-') || args.first().at(i: 0) == QLatin1Char('+')) { |
364 | // if the number starts with a minus or plus sign, add/subtract the number |
365 | val = v->cursorPosition().line() + val; |
366 | } else { |
367 | val--; // convert given line number to the internal representation of line numbers |
368 | } |
369 | |
370 | // constrain cursor to the range [0, number of lines] |
371 | if (val < 0) { |
372 | val = 0; |
373 | } else if (val > v->doc()->lines() - 1) { |
374 | val = v->doc()->lines() - 1; |
375 | } |
376 | |
377 | v->setCursorPosition(KTextEditor::Cursor(val, 0)); |
378 | return true; |
379 | } |
380 | return true; |
381 | } |
382 | |
383 | // ALL commands that takes 1 boolean argument. |
384 | else if (cmd == QLatin1String("set-icon-border" ) || cmd == QLatin1String("set-folding-markers" ) || cmd == QLatin1String("set-indent-pasted-text" ) |
385 | || cmd == QLatin1String("set-line-numbers" ) || cmd == QLatin1String("set-replace-tabs" ) || cmd == QLatin1String("set-show-tabs" ) |
386 | || cmd == QLatin1String("set-word-wrap" ) || cmd == QLatin1String("set-wrap-cursor" ) || cmd == QLatin1String("set-replace-tabs-save" ) |
387 | || cmd == QLatin1String("set-show-indent" )) { |
388 | if (args.isEmpty()) { |
389 | KCC_ERR(i18n("Usage: %1 on|off|1|0|true|false" , cmd)); |
390 | } |
391 | bool enable = false; |
392 | KateDocumentConfig *const config = v->doc()->config(); |
393 | if (getBoolArg(t: args.first(), val: &enable)) { |
394 | if (cmd == QLatin1String("set-icon-border" )) { |
395 | v->setIconBorder(enable); |
396 | } else if (cmd == QLatin1String("set-folding-markers" )) { |
397 | v->setFoldingMarkersOn(enable); |
398 | } else if (cmd == QLatin1String("set-line-numbers" )) { |
399 | v->setLineNumbersOn(enable); |
400 | } else if (cmd == QLatin1String("set-show-indent" )) { |
401 | v->renderer()->setShowIndentLines(enable); |
402 | } else if (cmd == QLatin1String("set-indent-pasted-text" )) { |
403 | config->setIndentPastedText(enable); |
404 | } else if (cmd == QLatin1String("set-replace-tabs" )) { |
405 | config->setReplaceTabsDyn(enable); |
406 | } else if (cmd == QLatin1String("set-show-tabs" )) { |
407 | config->setShowTabs(enable); |
408 | } else if (cmd == QLatin1String("set-show-trailing-spaces" )) { |
409 | config->setShowSpaces(enable ? KateDocumentConfig::Trailing : KateDocumentConfig::None); |
410 | } else if (cmd == QLatin1String("set-word-wrap" )) { |
411 | v->doc()->setWordWrap(enable); |
412 | } |
413 | |
414 | return true; |
415 | } else |
416 | KCC_ERR(i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false" , args.first(), cmd)); |
417 | } else if (cmd == QLatin1String("set-remove-trailing-spaces" )) { |
418 | // need at least one item, otherwise args.first() crashes |
419 | if (args.count() != 1) { |
420 | KCC_ERR(i18n("Usage: set-remove-trailing-spaces 0|-|none or 1|+|mod|modified or 2|*|all" )); |
421 | } |
422 | |
423 | QString tmp = args.first().toLower().trimmed(); |
424 | if (tmp == QLatin1String("1" ) || tmp == QLatin1String("modified" ) || tmp == QLatin1String("mod" ) || tmp == QLatin1String("+" )) { |
425 | v->doc()->config()->setRemoveSpaces(1); |
426 | } else if (tmp == QLatin1String("2" ) || tmp == QLatin1String("all" ) || tmp == QLatin1String("*" )) { |
427 | v->doc()->config()->setRemoveSpaces(2); |
428 | } else { |
429 | v->doc()->config()->setRemoveSpaces(0); |
430 | } |
431 | } |
432 | |
433 | // unlikely.. |
434 | KCC_ERR(i18n("Unknown command '%1'" , cmd)); |
435 | } |
436 | |
437 | bool KateCommands::CoreCommands::supportsRange(const QString &range) |
438 | { |
439 | static QStringList l; |
440 | |
441 | if (l.isEmpty()) { |
442 | l << QStringLiteral("indent" ) << QStringLiteral("unindent" ) << QStringLiteral("cleanindent" ) << QStringLiteral("comment" ) << QStringLiteral("uncomment" ) |
443 | << QStringLiteral("kill-line" ) << QStringLiteral("fold" ) << QStringLiteral("tfold" ); |
444 | } |
445 | |
446 | return l.contains(str: range); |
447 | } |
448 | |
449 | KCompletion *KateCommands::CoreCommands::completionObject(KTextEditor::View *view, const QString &cmd) |
450 | { |
451 | Q_UNUSED(view) |
452 | |
453 | if (cmd == QLatin1String("set-highlight" )) { |
454 | QStringList l; |
455 | l.reserve(asize: KateHlManager::self()->modeList().size()); |
456 | const auto modeList = KateHlManager::self()->modeList(); |
457 | for (const auto &hl : 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 | |
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 | |
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(subject: cmd); |
510 | if (!match.hasMatch()) { |
511 | return false; |
512 | } |
513 | |
514 | cmd = match.captured(nth: 1); |
515 | |
516 | // identify the base |
517 | |
518 | unsigned short int number = 0; |
519 | int base = 10; |
520 | if (cmd.startsWith(c: QLatin1Char('x'))) { |
521 | cmd.remove(i: 0, len: 1); |
522 | base = 16; |
523 | } else if (cmd.startsWith(s: QLatin1String("0x" ))) { |
524 | cmd.remove(i: 0, len: 2); |
525 | base = 16; |
526 | } else if (cmd[0] == QLatin1Char('0')) { |
527 | base = 8; |
528 | } |
529 | bool ok; |
530 | number = cmd.toUShort(ok: &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(position: view->cursorPosition(), text: QString::fromLatin1(ba: buf)); |
540 | } else { |
541 | // do the unicode thing |
542 | QChar c(number); |
543 | |
544 | view->document()->insertText(position: view->cursorPosition(), text: 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 | |
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 | |
588 | bool KateCommands::Date::exec(KTextEditor::View *view, const QString &cmd, QString &, const KTextEditor::Range &) |
589 | { |
590 | if (!cmd.startsWith(s: QLatin1String("date" ))) { |
591 | return false; |
592 | } |
593 | |
594 | if (QDateTime::currentDateTime().toString(format: cmd.mid(position: 5, n: cmd.length() - 5)).length() > 0) { |
595 | view->document()->insertText(position: view->cursorPosition(), text: QDateTime::currentDateTime().toString(format: cmd.mid(position: 5, n: cmd.length() - 5))); |
596 | } else { |
597 | view->document()->insertText(position: view->cursorPosition(), text: QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd hh:mm:ss" ))); |
598 | } |
599 | |
600 | return true; |
601 | } |
602 | |
603 | // END Date |
604 | |