1 | /* |
2 | SPDX-FileCopyrightText: 2009 Erlend Hamberg <ehamberg@gmail.com> |
3 | SPDX-FileCopyrightText: 2011 Svyatoslav Kuzmich <svatoslav1@gmail.com> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-or-later |
6 | */ |
7 | |
8 | #include <QDir> |
9 | #include <QTimer> |
10 | |
11 | #include <KLocalizedString> |
12 | #include <KTextEditor/Application> |
13 | #include <KTextEditor/Document> |
14 | #include <KTextEditor/Editor> |
15 | #include <KTextEditor/MainWindow> |
16 | #include <KTextEditor/View> |
17 | |
18 | #include <vimode/appcommands.h> |
19 | |
20 | using namespace KateVi; |
21 | |
22 | // BEGIN AppCommands |
23 | AppCommands *AppCommands::m_instance = nullptr; |
24 | |
25 | AppCommands::AppCommands() |
26 | : KTextEditor::Command({QStringLiteral("q" ), QStringLiteral("qa" ), QStringLiteral("qall" ), QStringLiteral("q!" ), QStringLiteral("qa!" ), |
27 | QStringLiteral("qall!" ), QStringLiteral("w" ), QStringLiteral("wq" ), QStringLiteral("wa" ), QStringLiteral("wqa" ), |
28 | QStringLiteral("x" ), QStringLiteral("xa" ), QStringLiteral("new" ), QStringLiteral("vnew" ), QStringLiteral("e" ), |
29 | QStringLiteral("edit" ), QStringLiteral("enew" ), QStringLiteral("sp" ), QStringLiteral("split" ), QStringLiteral("vs" ), |
30 | QStringLiteral("vsplit" ), QStringLiteral("only" ), QStringLiteral("tabe" ), QStringLiteral("tabedit" ), QStringLiteral("tabnew" ), |
31 | QStringLiteral("bd" ), QStringLiteral("bdelete" ), QStringLiteral("tabc" ), QStringLiteral("tabclose" ), QStringLiteral("clo" ), |
32 | QStringLiteral("close" )}) |
33 | , re_write(QStringLiteral("^w(a)?$" )) |
34 | , re_close(QStringLiteral("^bd(elete)?|tabc(lose)?$" )) |
35 | , re_quit(QStringLiteral("^(w)?q(a|all)?(!)?$" )) |
36 | , re_exit(QStringLiteral("^x(a)?$" )) |
37 | , re_edit(QStringLiteral("^e(dit)?|tabe(dit)?|tabnew$" )) |
38 | , re_tabedit(QStringLiteral("^tabe(dit)?|tabnew$" )) |
39 | , re_new(QStringLiteral("^(v)?new$" )) |
40 | , re_split(QStringLiteral("^sp(lit)?$" )) |
41 | , re_vsplit(QStringLiteral("^vs(plit)?$" )) |
42 | , re_vclose(QStringLiteral("^clo(se)?$" )) |
43 | , re_only(QStringLiteral("^on(ly)?$" )) |
44 | { |
45 | } |
46 | |
47 | AppCommands::~AppCommands() |
48 | { |
49 | m_instance = nullptr; |
50 | } |
51 | |
52 | bool AppCommands::exec(KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &) |
53 | { |
54 | QStringList args(cmd.split(sep: QRegularExpression(QStringLiteral("\\s+" )), behavior: Qt::SkipEmptyParts)); |
55 | QString command(args.takeFirst()); |
56 | |
57 | KTextEditor::MainWindow *mainWin = view->mainWindow(); |
58 | KTextEditor::Application *app = KTextEditor::Editor::instance()->application(); |
59 | |
60 | QRegularExpressionMatch match; |
61 | if ((match = re_write.match(subject: command)).hasMatch()) { // TODO: handle writing to specific file |
62 | if (!match.captured(nth: 1).isEmpty()) { // [a]ll |
63 | const auto docs = app->documents(); |
64 | for (KTextEditor::Document *doc : docs) { |
65 | doc->save(); |
66 | } |
67 | msg = i18n("All documents written to disk" ); |
68 | } else { |
69 | view->document()->documentSave(); |
70 | msg = i18n("Document written to disk" ); |
71 | } |
72 | } |
73 | // Other buffer commands are implemented by the KateFileTree plugin |
74 | else if ((match = re_close.match(subject: command)).hasMatch()) { |
75 | QTimer::singleShot(interval: 0, receiver: view, slot: [app, view]() { |
76 | app->closeDocument(document: view->document()); |
77 | }); |
78 | } else if ((match = re_quit.match(subject: command)).hasMatch()) { |
79 | const bool save = !match.captured(nth: 1).isEmpty(); // :[w]q |
80 | const bool allDocuments = !match.captured(nth: 2).isEmpty(); // :q[all] |
81 | const bool doNotPromptForSave = !match.captured(nth: 3).isEmpty(); // :q[!] |
82 | |
83 | if (allDocuments) { |
84 | if (save) { |
85 | const auto docs = app->documents(); |
86 | for (KTextEditor::Document *doc : docs) { |
87 | doc->save(); |
88 | } |
89 | } |
90 | |
91 | if (doNotPromptForSave) { |
92 | const auto docs = app->documents(); |
93 | for (KTextEditor::Document *doc : docs) { |
94 | if (doc->isModified()) { |
95 | doc->setModified(false); |
96 | } |
97 | } |
98 | } |
99 | |
100 | QTimer::singleShot(interval: 0, receiver: this, slot: [this, app]() { |
101 | closeDocuments(documents: app->documents()); |
102 | }); |
103 | } else { |
104 | if (save && view->document()->isModified()) { |
105 | view->document()->documentSave(); |
106 | } |
107 | |
108 | if (doNotPromptForSave) { |
109 | view->document()->setModified(false); |
110 | } |
111 | |
112 | if (mainWin->views().size() > 1) { |
113 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::closeCurrentView); |
114 | } else { |
115 | Q_ASSERT(app->documents().size() > 0); |
116 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::closeCurrentDocument); |
117 | } |
118 | } |
119 | } else if ((match = re_exit.match(subject: command)).hasMatch()) { |
120 | if (!match.captured(nth: 1).isEmpty()) { // a[ll] |
121 | const auto docs = app->documents(); |
122 | for (KTextEditor::Document *doc : docs) { |
123 | doc->save(); |
124 | } |
125 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::quit); |
126 | } else { |
127 | if (view->document()->isModified()) { |
128 | view->document()->documentSave(); |
129 | } |
130 | |
131 | if (app->documents().size() > 1) { |
132 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::closeCurrentDocument); |
133 | } else { |
134 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::quit); |
135 | } |
136 | } |
137 | } else if ((match = re_edit.match(subject: command)).hasMatch()) { |
138 | QString argument = args.join(sep: QLatin1Char(' ')); |
139 | if (argument.isEmpty() || argument == QLatin1String("!" )) { |
140 | if ((match = re_tabedit.match(subject: command)).hasMatch()) { |
141 | if (auto doc = app->openUrl(url: QUrl())) { |
142 | QTimer::singleShot(interval: 0, slot: [mainWin, doc]() { |
143 | mainWin->activateView(document: doc); |
144 | }); |
145 | } |
146 | } else { |
147 | view->document()->documentReload(); |
148 | } |
149 | } else { |
150 | QUrl base = view->document()->url(); |
151 | QUrl url; |
152 | QUrl arg2path(argument); |
153 | if (base.isValid()) { // first try to use the same path as the current open document has |
154 | url = |
155 | QUrl(base.resolved(relative: arg2path)); // resolved handles the case where the args is a relative path, and is the same as using QUrl(args) elsewise |
156 | } else { // else use the cwd |
157 | url = QUrl(QUrl::fromLocalFile(localfile: QDir::currentPath() + QLatin1Char('/')) |
158 | .resolved(relative: arg2path)); // + "/" is needed because of https://lists.qt-project.org/pipermail/qt-interest-old/2011-May/033913.html |
159 | } |
160 | |
161 | // either find existing document or just open it, openUrl will take care of non-existing files, too |
162 | KTextEditor::Document *doc = app->findUrl(url); |
163 | if (!doc) { |
164 | doc = app->openUrl(url); |
165 | } |
166 | if (doc) { |
167 | QTimer::singleShot(interval: 0, slot: [mainWin, doc]() { |
168 | mainWin->activateView(document: doc); |
169 | }); |
170 | } |
171 | } |
172 | // splitView() orientations are reversed from the usual editor convention. |
173 | // 'vsplit' and 'vnew' use Qt::Horizontal to match vi and the Kate UI actions. |
174 | } else if ((match = re_new.match(subject: command)).hasMatch()) { |
175 | if (match.captured(nth: 1) == QLatin1String("v" )) { // vertical split |
176 | mainWin->splitView(orientation: Qt::Horizontal); |
177 | } else { // horizontal split |
178 | mainWin->splitView(orientation: Qt::Vertical); |
179 | } |
180 | mainWin->openUrl(url: QUrl()); |
181 | } else if (command == QLatin1String("enew" )) { |
182 | mainWin->openUrl(url: QUrl()); |
183 | } else if ((match = re_split.match(subject: command)).hasMatch()) { |
184 | mainWin->splitView(orientation: Qt::Vertical); // see above |
185 | } else if ((match = re_vsplit.match(subject: command)).hasMatch()) { |
186 | mainWin->splitView(orientation: Qt::Horizontal); |
187 | } else if ((match = re_vclose.match(subject: command)).hasMatch()) { |
188 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::closeCurrentSplitView); |
189 | } else if ((match = re_only.match(subject: command)).hasMatch()) { |
190 | QTimer::singleShot(interval: 0, receiver: this, slot: &AppCommands::closeOtherSplitViews); |
191 | } |
192 | |
193 | return true; |
194 | } |
195 | |
196 | bool AppCommands::help(KTextEditor::View *view, const QString &cmd, QString &msg) |
197 | { |
198 | Q_UNUSED(view); |
199 | |
200 | if (re_write.match(subject: cmd).hasMatch()) { |
201 | msg = i18n( |
202 | "<p><b>w/wa — write document(s) to disk</b></p>" |
203 | "<p>Usage: <tt><b>w[a]</b></tt></p>" |
204 | "<p>Writes the current document(s) to disk. " |
205 | "It can be called in two ways:<br />" |
206 | " <tt>w</tt> — writes the current document to disk<br />" |
207 | " <tt>wa</tt> — writes all documents to disk.</p>" |
208 | "<p>If no file name is associated with the document, " |
209 | "a file dialog will be shown.</p>" ); |
210 | return true; |
211 | } else if (re_quit.match(subject: cmd).hasMatch()) { |
212 | msg = i18n( |
213 | "<p><b>q/qa/wq/wqa — [write and] quit</b></p>" |
214 | "<p>Usage: <tt><b>[w]q[a]</b></tt></p>" |
215 | "<p>Quits the application. If <tt>w</tt> is prepended, it also writes" |
216 | " the document(s) to disk. This command " |
217 | "can be called in several ways:<br />" |
218 | " <tt>q</tt> — closes the current view.<br />" |
219 | " <tt>qa</tt> — closes all views, effectively quitting the application.<br />" |
220 | " <tt>wq</tt> — writes the current document to disk and closes its view.<br />" |
221 | " <tt>wqa</tt> — writes all documents to disk and quits.</p>" |
222 | "<p>In all cases, if the view being closed is the last view, the application quits. " |
223 | "If no file name is associated with the document and it should be written to disk, " |
224 | "a file dialog will be shown.</p>" ); |
225 | return true; |
226 | } else if (re_exit.match(subject: cmd).hasMatch()) { |
227 | msg = i18n( |
228 | "<p><b>x/xa — write and quit</b></p>" |
229 | "<p>Usage: <tt><b>x[a]</b></tt></p>" |
230 | "<p>Saves document(s) and quits (e<b>x</b>its). This command " |
231 | "can be called in two ways:<br />" |
232 | " <tt>x</tt> — closes the current view.<br />" |
233 | " <tt>xa</tt> — closes all views, effectively quitting the application.</p>" |
234 | "<p>In all cases, if the view being closed is the last view, the application quits. " |
235 | "If no file name is associated with the document and it should be written to disk, " |
236 | "a file dialog will be shown.</p>" |
237 | "<p>Unlike the 'w' commands, this command only writes the document if it is modified." |
238 | "</p>" ); |
239 | return true; |
240 | } else if (re_split.match(subject: cmd).hasMatch()) { |
241 | msg = i18n( |
242 | "<p><b>sp,split— Split horizontally the current view into two</b></p>" |
243 | "<p>Usage: <tt><b>sp[lit]</b></tt></p>" |
244 | "<p>The result is two views on the same document.</p>" ); |
245 | return true; |
246 | } else if (re_vsplit.match(subject: cmd).hasMatch()) { |
247 | msg = i18n( |
248 | "<p><b>vs,vsplit— Split vertically the current view into two</b></p>" |
249 | "<p>Usage: <tt><b>vs[plit]</b></tt></p>" |
250 | "<p>The result is two views on the same document.</p>" ); |
251 | return true; |
252 | } else if (re_vclose.match(subject: cmd).hasMatch()) { |
253 | msg = i18n( |
254 | "<p><b>clo[se]— Close the current view</b></p>" |
255 | "<p>Usage: <tt><b>clo[se]</b></tt></p>" |
256 | "<p>After executing it, the current view will be closed.</p>" ); |
257 | return true; |
258 | } else if (re_new.match(subject: cmd).hasMatch()) { |
259 | msg = i18n( |
260 | "<p><b>[v]new — split view and create new document</b></p>" |
261 | "<p>Usage: <tt><b>[v]new</b></tt></p>" |
262 | "<p>Splits the current view and opens a new document in the new view." |
263 | " This command can be called in two ways:<br />" |
264 | " <tt>new</tt> — splits the view horizontally and opens a new document.<br />" |
265 | " <tt>vnew</tt> — splits the view vertically and opens a new document.<br />" |
266 | "</p>" ); |
267 | return true; |
268 | } else if (re_edit.match(subject: cmd).hasMatch()) { |
269 | msg = i18n( |
270 | "<p><b>e[dit] — reload current document</b></p>" |
271 | "<p>Usage: <tt><b>e[dit]</b></tt></p>" |
272 | "<p>Starts <b>e</b>diting the current document again. This is useful to re-edit" |
273 | " the current file, when it was modified on disk.</p>" ); |
274 | return true; |
275 | } |
276 | |
277 | return false; |
278 | } |
279 | |
280 | KTextEditor::View *AppCommands::findViewInDifferentSplitView(KTextEditor::MainWindow *window, KTextEditor::View *view) |
281 | { |
282 | const auto views = window->views(); |
283 | for (auto it : views) { |
284 | if (!window->viewsInSameSplitView(view1: it, view2: view)) { |
285 | return it; |
286 | } |
287 | } |
288 | return nullptr; |
289 | } |
290 | |
291 | void AppCommands::closeDocuments(const QList<KTextEditor::Document *> &documents) |
292 | { |
293 | auto app = KTextEditor::Editor::instance()->application(); |
294 | QTimer::singleShot(interval: 0, receiver: app, slot: [app, documents]() { |
295 | app->closeDocuments(documents); |
296 | }); |
297 | } |
298 | |
299 | void AppCommands::closeCurrentDocument() |
300 | { |
301 | auto app = KTextEditor::Editor::instance()->application(); |
302 | auto mw = app->activeMainWindow(); |
303 | if (auto view = mw->activeView()) { |
304 | auto doc = view->document(); |
305 | QTimer::singleShot(interval: 0, receiver: doc, slot: [app, doc]() { |
306 | app->closeDocument(document: doc); |
307 | }); |
308 | } |
309 | } |
310 | |
311 | void AppCommands::closeCurrentView() |
312 | { |
313 | auto app = KTextEditor::Editor::instance()->application(); |
314 | auto mw = app->activeMainWindow(); |
315 | if (auto view = mw->activeView()) { |
316 | mw->closeView(view); |
317 | } |
318 | } |
319 | |
320 | void AppCommands::closeCurrentSplitView() |
321 | { |
322 | auto app = KTextEditor::Editor::instance()->application(); |
323 | auto mw = app->activeMainWindow(); |
324 | if (auto view = mw->activeView()) { |
325 | mw->closeSplitView(view); |
326 | } |
327 | } |
328 | |
329 | void AppCommands::closeOtherSplitViews() |
330 | { |
331 | auto app = KTextEditor::Editor::instance()->application(); |
332 | auto mw = app->activeMainWindow(); |
333 | if (auto view = mw->activeView()) { |
334 | while (KTextEditor::View *viewToRemove = findViewInDifferentSplitView(window: mw, view)) { |
335 | mw->closeSplitView(view: viewToRemove); |
336 | } |
337 | } |
338 | } |
339 | |
340 | void AppCommands::quit() |
341 | { |
342 | KTextEditor::Editor::instance()->application()->quit(); |
343 | } |
344 | |
345 | // END AppCommands |
346 | |
347 | // BEGIN KateViBufferCommand |
348 | BufferCommands *BufferCommands::m_instance = nullptr; |
349 | |
350 | BufferCommands::BufferCommands() |
351 | : KTextEditor::Command({QStringLiteral("ls" ), |
352 | QStringLiteral("b" ), |
353 | QStringLiteral("buffer" ), |
354 | QStringLiteral("bn" ), |
355 | QStringLiteral("bnext" ), |
356 | QStringLiteral("bp" ), |
357 | QStringLiteral("bprevious" ), |
358 | QStringLiteral("tabn" ), |
359 | QStringLiteral("tabnext" ), |
360 | QStringLiteral("tabp" ), |
361 | QStringLiteral("tabprevious" ), |
362 | QStringLiteral("bf" ), |
363 | QStringLiteral("bfirst" ), |
364 | QStringLiteral("bl" ), |
365 | QStringLiteral("blast" ), |
366 | QStringLiteral("tabf" ), |
367 | QStringLiteral("tabfirst" ), |
368 | QStringLiteral("tabl" ), |
369 | QStringLiteral("tablast" )}) |
370 | { |
371 | } |
372 | |
373 | BufferCommands::~BufferCommands() |
374 | { |
375 | m_instance = nullptr; |
376 | } |
377 | |
378 | bool BufferCommands::exec(KTextEditor::View *view, const QString &cmd, QString &, const KTextEditor::Range &) |
379 | { |
380 | // create list of args |
381 | QStringList args(cmd.split(sep: QLatin1Char(' '), behavior: Qt::KeepEmptyParts)); |
382 | QString command = args.takeFirst(); // same as cmd if split failed |
383 | QString argument = args.join(sep: QLatin1Char(' ')); |
384 | |
385 | if (command == QLatin1String("ls" )) { |
386 | // TODO: open quickview |
387 | } else if (command == QLatin1String("b" ) || command == QLatin1String("buffer" )) { |
388 | switchDocument(view, doc: argument); |
389 | } else if (command == QLatin1String("bp" ) || command == QLatin1String("bprevious" )) { |
390 | prevBuffer(view); |
391 | } else if (command == QLatin1String("bn" ) || command == QLatin1String("bnext" )) { |
392 | nextBuffer(view); |
393 | } else if (command == QLatin1String("bf" ) || command == QLatin1String("bfirst" )) { |
394 | firstBuffer(view); |
395 | } else if (command == QLatin1String("bl" ) || command == QLatin1String("blast" )) { |
396 | lastBuffer(view); |
397 | } else if (command == QLatin1String("tabn" ) || command == QLatin1String("tabnext" )) { |
398 | nextTab(view); |
399 | } else if (command == QLatin1String("tabp" ) || command == QLatin1String("tabprevious" )) { |
400 | prevTab(view); |
401 | } else if (command == QLatin1String("tabf" ) || command == QLatin1String("tabfirst" )) { |
402 | firstTab(view); |
403 | } else if (command == QLatin1String("tabl" ) || command == QLatin1String("tablast" )) { |
404 | lastTab(view); |
405 | } |
406 | return true; |
407 | } |
408 | |
409 | void BufferCommands::switchDocument(KTextEditor::View *view, const QString &address) |
410 | { |
411 | if (address.isEmpty()) { |
412 | // no argument: switch to the previous document |
413 | prevBuffer(view); |
414 | return; |
415 | } |
416 | |
417 | const int idx = address.toInt(); |
418 | QList<KTextEditor::Document *> docs = documents(); |
419 | |
420 | if (idx > 0 && idx <= docs.size()) { |
421 | // numerical argument: switch to the nth document |
422 | activateDocument(view, docs.at(i: idx - 1)); |
423 | } else { |
424 | // string argument: switch to the given file |
425 | KTextEditor::Document *doc = nullptr; |
426 | |
427 | for (KTextEditor::Document *it : docs) { |
428 | if (it->documentName() == address) { |
429 | doc = it; |
430 | break; |
431 | } |
432 | } |
433 | |
434 | if (doc) { |
435 | activateDocument(view, doc); |
436 | } |
437 | } |
438 | } |
439 | |
440 | void BufferCommands::prevBuffer(KTextEditor::View *view) |
441 | { |
442 | const QList<KTextEditor::Document *> docs = documents(); |
443 | const int idx = docs.indexOf(t: view->document()); |
444 | |
445 | if (idx > 0) { |
446 | activateDocument(view, docs.at(i: idx - 1)); |
447 | } else if (!docs.isEmpty()) { // wrap |
448 | activateDocument(view, docs.last()); |
449 | } |
450 | } |
451 | |
452 | void BufferCommands::nextBuffer(KTextEditor::View *view) |
453 | { |
454 | QList<KTextEditor::Document *> docs = documents(); |
455 | const int idx = docs.indexOf(t: view->document()); |
456 | |
457 | if (idx + 1 < docs.size()) { |
458 | activateDocument(view, docs.at(i: idx + 1)); |
459 | } else if (!docs.isEmpty()) { // wrap |
460 | activateDocument(view, docs.first()); |
461 | } |
462 | } |
463 | |
464 | void BufferCommands::firstBuffer(KTextEditor::View *view) |
465 | { |
466 | auto docs = documents(); |
467 | if (!docs.isEmpty()) { |
468 | activateDocument(view, documents().at(i: 0)); |
469 | } |
470 | } |
471 | |
472 | void BufferCommands::lastBuffer(KTextEditor::View *view) |
473 | { |
474 | auto docs = documents(); |
475 | if (!docs.isEmpty()) { |
476 | activateDocument(view, documents().last()); |
477 | } |
478 | } |
479 | |
480 | void BufferCommands::prevTab(KTextEditor::View *view) |
481 | { |
482 | prevBuffer(view); // TODO: implement properly, when interface is added |
483 | } |
484 | |
485 | void BufferCommands::nextTab(KTextEditor::View *view) |
486 | { |
487 | nextBuffer(view); // TODO: implement properly, when interface is added |
488 | } |
489 | |
490 | void BufferCommands::firstTab(KTextEditor::View *view) |
491 | { |
492 | firstBuffer(view); // TODO: implement properly, when interface is added |
493 | } |
494 | |
495 | void BufferCommands::lastTab(KTextEditor::View *view) |
496 | { |
497 | lastBuffer(view); // TODO: implement properly, when interface is added |
498 | } |
499 | |
500 | void BufferCommands::activateDocument(KTextEditor::View *view, KTextEditor::Document *doc) |
501 | { |
502 | KTextEditor::MainWindow *mainWindow = view->mainWindow(); |
503 | QTimer::singleShot(interval: 0, slot: [mainWindow, doc]() { |
504 | mainWindow->activateView(document: doc); |
505 | }); |
506 | } |
507 | |
508 | QList<KTextEditor::Document *> BufferCommands::documents() |
509 | { |
510 | KTextEditor::Application *app = KTextEditor::Editor::instance()->application(); |
511 | return app->documents(); |
512 | } |
513 | |
514 | bool BufferCommands::help(KTextEditor::View * /*view*/, const QString &cmd, QString &msg) |
515 | { |
516 | if (cmd == QLatin1String("b" ) || cmd == QLatin1String("buffer" )) { |
517 | msg = i18n( |
518 | "<p><b>b,buffer — Edit document N from the document list</b></p>" |
519 | "<p>Usage: <tt><b>b[uffer] [N]</b></tt></p>" ); |
520 | return true; |
521 | } else if (cmd == QLatin1String("bp" ) || cmd == QLatin1String("bprevious" ) || cmd == QLatin1String("tabp" ) || cmd == QLatin1String("tabprevious" )) { |
522 | msg = i18n( |
523 | "<p><b>bp,bprev — previous buffer</b></p>" |
524 | "<p>Usage: <tt><b>bp[revious] [N]</b></tt></p>" |
525 | "<p>Goes to <b>[N]</b>th previous document (\"<b>b</b>uffer\") in document list. </p>" |
526 | "<p> <b>[N]</b> defaults to one. </p>" |
527 | "<p>Wraps around the start of the document list.</p>" ); |
528 | return true; |
529 | } else if (cmd == QLatin1String("bn" ) || cmd == QLatin1String("bnext" ) || cmd == QLatin1String("tabn" ) || cmd == QLatin1String("tabnext" )) { |
530 | msg = i18n( |
531 | "<p><b>bn,bnext — switch to next document</b></p>" |
532 | "<p>Usage: <tt><b>bn[ext] [N]</b></tt></p>" |
533 | "<p>Goes to <b>[N]</b>th next document (\"<b>b</b>uffer\") in document list." |
534 | "<b>[N]</b> defaults to one. </p>" |
535 | "<p>Wraps around the end of the document list.</p>" ); |
536 | return true; |
537 | } else if (cmd == QLatin1String("bf" ) || cmd == QLatin1String("bfirst" ) || cmd == QLatin1String("tabf" ) || cmd == QLatin1String("tabfirst" )) { |
538 | msg = i18n( |
539 | "<p><b>bf,bfirst — first document</b></p>" |
540 | "<p>Usage: <tt><b>bf[irst]</b></tt></p>" |
541 | "<p>Goes to the <b>f</b>irst document (\"<b>b</b>uffer\") in document list.</p>" ); |
542 | return true; |
543 | } else if (cmd == QLatin1String("bl" ) || cmd == QLatin1String("blast" ) || cmd == QLatin1String("tabl" ) || cmd == QLatin1String("tablast" )) { |
544 | msg = i18n( |
545 | "<p><b>bl,blast — last document</b></p>" |
546 | "<p>Usage: <tt><b>bl[ast]</b></tt></p>" |
547 | "<p>Goes to the <b>l</b>ast document (\"<b>b</b>uffer\") in document list.</p>" ); |
548 | return true; |
549 | } else if (cmd == QLatin1String("ls" )) { |
550 | msg = i18n( |
551 | "<p><b>ls</b></p>" |
552 | "<p>list current buffers<p>" ); |
553 | } |
554 | |
555 | return false; |
556 | } |
557 | // END KateViBufferCommand |
558 | |