1/*
2 SPDX-FileCopyrightText: 2001-2004 Christoph Cullmann <cullmann@kde.org>
3 SPDX-FileCopyrightText: 2001 Joseph Wenninger <jowenn@kde.org>
4 SPDX-FileCopyrightText: 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
5 SPDX-FileCopyrightText: 2006 Hamish Rodda <rodda@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef _KATE_DOCUMENT_H_
11#define _KATE_DOCUMENT_H_
12
13#include <QPointer>
14#include <QStack>
15#include <QTimer>
16
17#include <ktexteditor/document.h>
18#include <ktexteditor/mainwindow.h>
19#include <ktexteditor/movingrangefeedback.h>
20
21#include "katetextline.h"
22#include <ktexteditor_export.h>
23
24class KJob;
25class KateTemplateHandler;
26namespace KTextEditor
27{
28class Plugin;
29class Attribute;
30class TemplateScript;
31}
32
33namespace KIO
34{
35class TransferJob;
36}
37
38namespace Kate
39{
40class SwapFile;
41}
42
43class KateBuffer;
44namespace KTextEditor
45{
46class Message;
47class ViewPrivate;
48}
49class KateDocumentConfig;
50class KateHighlighting;
51class KateUndoManager;
52class KateOnTheFlyChecker;
53class KateDocumentTest;
54
55class KateAutoIndent;
56class KateModOnHdPrompt;
57class KToggleAction;
58
59/**
60 * @brief Backend of KTextEditor::Document related public KTextEditor interfaces.
61 *
62 * @warning This file is @e private API and not part of the public
63 * KTextEditor interfaces.
64 */
65class KTEXTEDITOR_EXPORT KTextEditor::DocumentPrivate final : public KTextEditor::Document, private KTextEditor::MovingRangeFeedback
66{
67 Q_OBJECT
68
69 friend class KTextEditor::Document;
70 friend class ::KateDocumentTest;
71 friend class ::KateBuffer;
72
73public:
74 explicit DocumentPrivate(const KPluginMetaData &data,
75 bool bSingleViewMode = false,
76 bool bReadOnly = false,
77 QWidget *parentWidget = nullptr,
78 QObject * = nullptr);
79 explicit DocumentPrivate(bool bSingleViewMode = false, bool bReadOnly = false, QWidget *parentWidget = nullptr, QObject * = nullptr)
80 : DocumentPrivate(KPluginMetaData(), bSingleViewMode, bReadOnly, parentWidget)
81 {
82 }
83 ~DocumentPrivate() override;
84
85 using ReadWritePart::closeUrl;
86 bool closeUrl() override;
87
88 bool openUrl(const QUrl &url) override;
89
90 KTextEditor::Range rangeOnLine(KTextEditor::Range range, int line) const;
91
92private:
93 KTEXTEDITOR_NO_EXPORT
94 void showAndSetOpeningErrorAccess();
95 /*
96 * Overload this to have on-demand view creation
97 */
98public:
99 /**
100 * @return The widget defined by this part, set by setWidget().
101 */
102 QWidget *widget() override;
103
104public:
105 bool readOnly() const
106 {
107 return m_bReadOnly;
108 }
109 bool singleViewMode() const
110 {
111 return m_bSingleViewMode;
112 }
113
114private:
115 // only to make part work, don't change it !
116 const bool m_bSingleViewMode;
117 const bool m_bReadOnly;
118
119 //
120 // KTextEditor::Document stuff
121 //
122public:
123 KTextEditor::View *createView(QWidget *parent, KTextEditor::MainWindow *mainWindow = nullptr) override;
124
125 QList<KTextEditor::View *> views() const override
126 {
127 return m_views;
128 }
129
130 KTextEditor::View *activeView() const
131 {
132 return m_activeView;
133 }
134
135private:
136 KTextEditor::View *m_activeView = nullptr;
137
138 //
139 // KTextEditor::EditInterface stuff
140 //
141public Q_SLOTS:
142 bool setText(const QString &) override;
143 bool setText(const QStringList &text) override;
144 bool clear() override;
145
146 bool insertText(KTextEditor::Cursor position, const QString &s, bool block = false) override;
147 bool insertText(KTextEditor::Cursor position, const QStringList &text, bool block = false) override;
148
149 bool insertLine(int line, const QString &s) override;
150 bool insertLines(int line, const QStringList &s) override;
151
152 bool removeText(KTextEditor::Range range, bool block = false) override;
153 bool removeLine(int line) override;
154
155 bool replaceText(KTextEditor::Range range, const QString &s, bool block = false) override;
156
157 // unhide method...
158 bool replaceText(KTextEditor::Range r, const QStringList &l, bool b) override
159 {
160 return KTextEditor::Document::replaceText(range: r, text: l, block: b);
161 }
162
163public:
164 bool isEditingTransactionRunning() const override;
165 QString text(KTextEditor::Range range, bool blockwise = false) const override;
166 QStringList textLines(KTextEditor::Range range, bool block = false) const override;
167 QString text() const override;
168 QString line(int line) const override;
169 QChar characterAt(KTextEditor::Cursor position) const override;
170 QString wordAt(KTextEditor::Cursor cursor) const override;
171 KTextEditor::Range wordRangeAt(KTextEditor::Cursor cursor) const override;
172 bool isValidTextPosition(KTextEditor::Cursor cursor) const override;
173 int lines() const override;
174 bool isLineModified(int line) const override;
175 bool isLineSaved(int line) const override;
176 bool isLineTouched(int line) const override;
177 KTextEditor::Cursor documentEnd() const override;
178 qsizetype totalCharacters() const override;
179 int lineLength(int line) const override;
180 qsizetype cursorToOffset(KTextEditor::Cursor c) const override;
181 KTextEditor::Cursor offsetToCursor(qsizetype offset) const override;
182
183Q_SIGNALS:
184 void charactersSemiInteractivelyInserted(KTextEditor::Cursor position, const QString &text);
185
186 /**
187 * The \p document emits this signal whenever text was inserted. The
188 * insertion occurred at range.start(), and new text now occupies up to
189 * range.end().
190 * \param document document which emitted this signal
191 * \param range range that the newly inserted text occupies
192 * \see insertText(), insertLine()
193 */
194 void textInsertedRange(KTextEditor::Document *document, KTextEditor::Range range);
195
196 /**
197 * The \p document emits this signal whenever \p range was removed, i.e.
198 * text was removed.
199 * \param document document which emitted this signal
200 * \param range range that the removed text previously occupied
201 * \param oldText the text that has been removed
202 * \see removeText(), removeLine(), clear()
203 */
204 void textRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText);
205
206public:
207 // BEGIN editStart/editEnd (start, end, undo, cursor update, view update)
208 /**
209 * Enclose editor actions with @p editStart() and @p editEnd() to group
210 * them.
211 */
212 bool editStart();
213
214 /**
215 * End a editor operation.
216 * @see editStart()
217 */
218 bool editEnd();
219
220 void pushEditState();
221 void popEditState();
222
223 // END editStart/editEnd
224
225 void inputMethodStart();
226 void inputMethodEnd();
227
228 // BEGIN LINE BASED INSERT/REMOVE STUFF (editStart() and editEnd() included)
229 /**
230 * Add a string in the given line/column
231 * @param line line number
232 * @param col column
233 * @param s string to be inserted
234 * @return true on success
235 */
236 bool editInsertText(int line, int col, const QString &s, bool notify = true);
237
238 /**
239 * Remove a string in the given line/column
240 * @param line line number
241 * @param col column
242 * @param len length of text to be removed
243 * @return true on success
244 */
245 bool editRemoveText(int line, int col, int len);
246
247 /**
248 * Mark @p line as @p autowrapped. This is necessary if static word warp is
249 * enabled, because we have to know whether to insert a new line or add the
250 * wrapped words to the following line.
251 * @param line line number
252 * @param autowrapped autowrapped?
253 * @return true on success
254 */
255 bool editMarkLineAutoWrapped(int line, bool autowrapped);
256
257 /**
258 * Wrap @p line. If @p newLine is true, ignore the textline's flag
259 * KateTextLine::flagAutoWrapped and force a new line. Whether a new line
260 * was needed/added you can grab with @p newLineAdded.
261 * @param line line number
262 * @param col column
263 * @param newLine if true, force a new line
264 * @param newLineAdded return value is true, if new line was added (may be 0)
265 * @return true on success
266 */
267 bool editWrapLine(int line, int col, bool newLine = true, bool *newLineAdded = nullptr, bool notify = true);
268
269 /**
270 * Unwrap @p line. If @p removeLine is true, we force to join the lines. If
271 * @p removeLine is true, @p length is ignored (eg not needed).
272 * @param line line number
273 * @param removeLine if true, force to remove the next line
274 * @return true on success
275 */
276 bool editUnWrapLine(int line, bool removeLine = true, int length = 0);
277
278 /**
279 * Insert a string at the given line.
280 * @param line line number
281 * @param s string to insert
282 * @return true on success
283 */
284 bool editInsertLine(int line, const QString &s, bool notify = true);
285
286 /**
287 * Remove a line
288 * @param line line number
289 * @return true on success
290 */
291 bool editRemoveLine(int line);
292
293 bool editRemoveLines(int from, int to);
294
295 /**
296 * Warp a line
297 * @param startLine line to begin wrapping
298 * @param endLine line to stop wrapping
299 * @return true on success
300 */
301 bool wrapText(int startLine, int endLine);
302
303 /**
304 * Wrap lines touched by the selection with respect of existing paragraphs.
305 * To do so will the paragraph prior to the wrap joined as one single line
306 * which cause an almost perfect wrapped paragraph as long as there are no
307 * unneeded spaces exist or some formatting like this comment block.
308 * Without any selection the current line is wrapped.
309 * Empty lines around each paragraph are untouched.
310 * @param first line to begin wrapping
311 * @param last line to stop wrapping
312 * @return true on success
313 */
314 bool wrapParagraph(int first, int last);
315 // END LINE BASED INSERT/REMOVE STUFF
316
317Q_SIGNALS:
318 /**
319 * Emitted when text from @p line was wrapped at position pos onto line @p nextLine.
320 */
321 void editLineWrapped(int line, int col, int len);
322
323 /**
324 * Emitted each time text from @p nextLine was upwrapped onto @p line.
325 */
326 void editLineUnWrapped(int line, int col);
327
328public:
329 bool isEditRunning() const;
330
331 void setUndoMergeAllEdits(bool merge);
332
333 enum EditingPositionKind { Previous, Next };
334
335 /**
336 *Returns the next or previous position cursor in this document from the stack depending on the argument passed.
337 *@return cursor invalid if m_editingStack empty
338 */
339 KTextEditor::Cursor lastEditingPosition(EditingPositionKind nextOrPrevious, KTextEditor::Cursor);
340
341private:
342 int editSessionNumber = 0;
343 QStack<int> editStateStack;
344 bool editIsRunning = false;
345 bool m_undoMergeAllEdits = false;
346 KTextEditor::Cursor m_editLastChangeStartCursor = KTextEditor::Cursor::invalid();
347 QStack<std::shared_ptr<KTextEditor::MovingCursor>> m_editingStack;
348 int m_editingStackPosition = -1;
349
350 //
351 // KTextEditor::UndoInterface stuff
352 //
353public Q_SLOTS:
354 void undo();
355 void redo();
356
357 /**
358 * Removes all the elements in m_editingStack of the respective document.
359 */
360 void clearEditingPosStack();
361
362 /**
363 * Saves the editing positions into the stack.
364 * If the consecutive editings happens in the same line, then remove
365 * the previous and add the new one with updated column no.
366 */
367 void saveEditingPositions(const KTextEditor::Cursor cursor);
368
369public:
370 uint undoCount() const;
371 uint redoCount() const;
372
373 KateUndoManager *undoManager()
374 {
375 return m_undoManager;
376 }
377
378protected:
379 KateUndoManager *const m_undoManager;
380
381Q_SIGNALS:
382 void undoChanged();
383
384public:
385 QList<KTextEditor::Range> searchText(KTextEditor::Range range, const QString &pattern, const KTextEditor::SearchOptions options) const;
386
387private:
388 /**
389 * Return a widget suitable to be used as a dialog parent.
390 */
391 KTEXTEDITOR_NO_EXPORT
392 QWidget *dialogParent();
393
394 /**
395 * Wrapper around QFileDialog::getSaveFileUrl, will use proper dialogParent
396 * and try it's best to find a good directory as start
397 * @param dialogTitle dialog title string
398 * @return url to save to or empty url if aborted
399 */
400 KTEXTEDITOR_NO_EXPORT
401 QUrl getSaveFileUrl(const QString &dialogTitle);
402
403 /*
404 * Access to the mode/highlighting subsystem
405 */
406public:
407 /**
408 * @copydoc KTextEditor::Document::defaultStyleAt()
409 */
410 KSyntaxHighlighting::Theme::TextStyle defaultStyleAt(KTextEditor::Cursor position) const override;
411
412 /**
413 * Return the name of the currently used mode
414 * \return name of the used mode
415 */
416 QString mode() const override;
417
418 /**
419 * Return the name of the currently used mode
420 * \return name of the used mode
421 */
422 QString highlightingMode() const override;
423
424 /**
425 * Return a list of the names of all possible modes
426 * \return list of mode names
427 */
428 QStringList modes() const override;
429
430 /**
431 * Return a list of the names of all possible modes
432 * \return list of mode names
433 */
434 QStringList highlightingModes() const override;
435
436 /**
437 * Set the current mode of the document by giving its name
438 * \param name name of the mode to use for this document
439 * \return \e true on success, otherwise \e false
440 */
441 bool setMode(const QString &name) override;
442
443 /**
444 * Set the current mode of the document by giving its name
445 * \param name name of the mode to use for this document
446 * \return \e true on success, otherwise \e false
447 */
448 bool setHighlightingMode(const QString &name) override;
449 /**
450 * Returns the name of the section for a highlight given its @p index in the highlight
451 * list (as returned by highlightModes()).
452 * You can use this function to build a tree of the highlight names, organized in sections.
453 * \param index in the highlight list for which to find the section name.
454 */
455 QString highlightingModeSection(int index) const override;
456
457 /**
458 * Returns the name of the section for a mode given its @p index in the highlight
459 * list (as returned by modes()).
460 * You can use this function to build a tree of the mode names, organized in sections.
461 * \param index index in the highlight list for which to find the section name.
462 */
463 QString modeSection(int index) const override;
464
465 /*
466 * Helpers....
467 */
468public:
469 void bufferHlChanged();
470
471 /**
472 * allow to mark, that we changed hl on user wish and should not reset it
473 * atm used for the user visible menu to select highlightings
474 */
475 void setDontChangeHlOnSave();
476
477 /**
478 * Set that the BOM marker is forced via the tool menu
479 */
480 void bomSetByUser();
481
482public:
483 /**
484 * Read session settings from the given \p config.
485 *
486 * Known flags:
487 * "SkipUrl" => don't save/restore the file
488 * "SkipMode" => don't save/restore the mode
489 * "SkipHighlighting" => don't save/restore the highlighting
490 * "SkipEncoding" => don't save/restore the encoding
491 *
492 * \param config read the session settings from this KConfigGroup
493 * \param flags additional flags
494 * \see writeSessionConfig()
495 */
496 void readSessionConfig(const KConfigGroup &config, const QSet<QString> &flags = QSet<QString>()) override;
497
498 /**
499 * Write session settings to the \p config.
500 * See readSessionConfig() for more details.
501 *
502 * \param config write the session settings to this KConfigGroup
503 * \param flags additional flags
504 * \see readSessionConfig()
505 */
506 void writeSessionConfig(KConfigGroup &config, const QSet<QString> &flags = QSet<QString>()) override;
507
508 //
509 // KTextEditor::MarkInterface
510 //
511public Q_SLOTS:
512 void setMark(int line, uint markType) override;
513 void clearMark(int line) override;
514
515 void addMark(int line, uint markType) override;
516 void removeMark(int line, uint markType) override;
517
518 void clearMarks() override;
519
520 void requestMarkTooltip(int line, QPoint position);
521
522 /// Returns true if the click on the mark should not be further processed
523 bool handleMarkClick(int line);
524
525 /// Returns true if the context-menu event should not further be processed
526 bool handleMarkContextMenu(int line, QPoint position);
527
528 void setMarkDescription(Document::MarkTypes, const QString &) override;
529
530 void setEditableMarks(uint markMask) override;
531 void setMarkIcon(Document::MarkTypes markType, const QIcon &icon) override;
532
533public:
534 uint mark(int line) override;
535 const QHash<int, KTextEditor::Mark *> &marks() override;
536 QString markDescription(Document::MarkTypes) const override;
537 virtual QColor markColor(Document::MarkTypes) const;
538 uint editableMarks() const override;
539 QIcon markIcon(Document::MarkTypes markType) const override;
540
541private:
542 QHash<int, KTextEditor::Mark *> m_marks;
543 QHash<int, QIcon> m_markIcons; // QPixmap or QIcon, KF6: remove QPixmap support
544 QHash<int, QString> m_markDescriptions;
545 uint m_editableMarks = markType01;
546
547 //
548 // KTextEditor::PrintInterface
549 //
550public Q_SLOTS:
551 bool print() override;
552 void printPreview() override;
553
554 //
555 // KTextEditor::DocumentInfoInterface ( ### unfinished )
556 //
557public:
558 /**
559 * Tries to detect mime-type based on file name and content of buffer.
560 *
561 * @return the name of the mimetype for the document.
562 */
563 QString mimeType() override;
564
565 //
566 // once was KTextEditor::VariableInterface
567 //
568public:
569 /**
570 * Returns the value for the variable @p name.
571 * If the Document does not have a variable called @p name,
572 * an empty QString() is returned.
573 *
574 * // TODO KF6: expose in KTextEditor::Document?
575 *
576 * @param name variable to query
577 * @return value of the variable @p name
578 * @see setVariable()
579 */
580 virtual QString variable(const QString &name) const;
581
582 /**
583 * Set the variable @p name to @p value. Setting and changing a variable
584 * has immediate effect on the Document. For instance, setting the variable
585 * @e indent-mode to @e cstyle will immediately cause the Document to load
586 * the C Style indenter.
587 *
588 * // TODO KF6: expose in KTextEditor::Document?
589 *
590 * @param name the variable name
591 * @param value the value to be set
592 * @see variable()
593 */
594 virtual void setVariable(const QString &name, const QString &value);
595
596private:
597 std::map<QString, QString> m_storedVariables;
598
599 //
600 // MovingInterface API
601 //
602public:
603 /**
604 * Create a new moving cursor for this document.
605 * @param position position of the moving cursor to create
606 * @param insertBehavior insertion behavior
607 * @return new moving cursor for the document
608 */
609 KTextEditor::MovingCursor *newMovingCursor(KTextEditor::Cursor position,
610 KTextEditor::MovingCursor::InsertBehavior insertBehavior = KTextEditor::MovingCursor::MoveOnInsert) override;
611
612 /**
613 * Create a new moving range for this document.
614 * @param range range of the moving range to create
615 * @param insertBehaviors insertion behaviors
616 * @param emptyBehavior behavior on becoming empty
617 * @return new moving range for the document
618 */
619 KTextEditor::MovingRange *newMovingRange(KTextEditor::Range range,
620 KTextEditor::MovingRange::InsertBehaviors insertBehaviors = KTextEditor::MovingRange::DoNotExpand,
621 KTextEditor::MovingRange::EmptyBehavior emptyBehavior = KTextEditor::MovingRange::AllowEmpty) override;
622
623 /**
624 * Current revision
625 * @return current revision
626 */
627 qint64 revision() const override;
628
629 /**
630 * Last revision the buffer got successful saved
631 * @return last revision buffer got saved, -1 if none
632 */
633 qint64 lastSavedRevision() const override;
634
635 /**
636 * Lock a revision, this will keep it around until released again.
637 * But all revisions will always be cleared on buffer clear() (and therefor load())
638 * @param revision revision to lock
639 */
640 void lockRevision(qint64 revision) override;
641
642 /**
643 * Release a revision.
644 * @param revision revision to release
645 */
646 void unlockRevision(qint64 revision) override;
647
648 /**
649 * Transform a cursor from one revision to an other.
650 * @param cursor cursor to transform
651 * @param insertBehavior behavior of this cursor on insert of text at its position
652 * @param fromRevision from this revision we want to transform
653 * @param toRevision to this revision we want to transform, default of -1 is current revision
654 */
655 void transformCursor(KTextEditor::Cursor &cursor,
656 KTextEditor::MovingCursor::InsertBehavior insertBehavior,
657 qint64 fromRevision,
658 qint64 toRevision = -1) override;
659
660 /**
661 * Transform a cursor from one revision to an other.
662 * @param line line number of the cursor to transform
663 * @param column column number of the cursor to transform
664 * @param insertBehavior behavior of this cursor on insert of text at its position
665 * @param fromRevision from this revision we want to transform
666 * @param toRevision to this revision we want to transform, default of -1 is current revision
667 */
668 void
669 transformCursor(int &line, int &column, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision = -1) override;
670
671 /**
672 * Transform a range from one revision to an other.
673 * @param range range to transform
674 * @param insertBehaviors behavior of this range on insert of text at its position
675 * @param emptyBehavior behavior on becoming empty
676 * @param fromRevision from this revision we want to transform
677 * @param toRevision to this revision we want to transform, default of -1 is current revision
678 */
679 void transformRange(KTextEditor::Range &range,
680 KTextEditor::MovingRange::InsertBehaviors insertBehaviors,
681 KTextEditor::MovingRange::EmptyBehavior emptyBehavior,
682 qint64 fromRevision,
683 qint64 toRevision = -1) override;
684
685 //
686 // Annotation Interface
687 //
688public:
689 void setAnnotationModel(KTextEditor::AnnotationModel *model) override;
690 KTextEditor::AnnotationModel *annotationModel() const override;
691
692Q_SIGNALS:
693 void annotationModelChanged(KTextEditor::AnnotationModel *, KTextEditor::AnnotationModel *);
694
695private:
696 KTextEditor::AnnotationModel *m_annotationModel = nullptr;
697
698 //
699 // KParts::ReadWrite stuff
700 //
701public:
702 /**
703 * open the file obtained by the kparts framework
704 * the framework abstracts the loading of remote files
705 * @return success
706 */
707 bool openFile() override;
708
709 /**
710 * save the file obtained by the kparts framework
711 * the framework abstracts the uploading of remote files
712 * @return success
713 */
714 bool saveFile() override;
715
716 void setReadWrite(bool rw = true) override;
717
718 void setModified(bool m) override;
719
720 bool isAutoReload();
721 KToggleAction *autoReloadToggleAction()
722 {
723 return m_autoReloadMode;
724 };
725 void delayAutoReload();
726
727private Q_SLOTS:
728 void autoReloadToggled(bool b);
729
730private:
731 KTEXTEDITOR_NO_EXPORT
732 void activateDirWatch(const QString &useFileName = QString());
733 KTEXTEDITOR_NO_EXPORT
734 void deactivateDirWatch();
735
736 QString m_dirWatchFile;
737
738 /**
739 * Make backup copy during saveFile, if configured that way.
740 * @return success? else saveFile should return false and not write the file
741 */
742 KTEXTEDITOR_NO_EXPORT
743 bool createBackupFile();
744
745public:
746 /**
747 * Type chars in a view.
748 * Characters are filtered in KateViewInternal::isAcceptableInput() before calling typeChars.
749 *
750 * @param view view that received the input
751 * @param chars characters to type
752 */
753 void typeChars(KTextEditor::ViewPrivate *view, QString chars);
754
755 /**
756 * gets the last line number (lines() - 1)
757 */
758 inline int lastLine() const
759 {
760 return lines() - 1;
761 }
762
763 // Repaint all of all of the views
764 void repaintViews(bool paintOnlyDirty = true);
765
766 KateHighlighting *highlight() const;
767
768public Q_SLOTS:
769 void tagLines(KTextEditor::LineRange lineRange);
770 void tagLine(int line);
771
772private Q_SLOTS:
773 void internalHlChanged();
774
775public:
776 void addView(KTextEditor::View *);
777 /** removes the view from the list of views. The view is *not* deleted.
778 * That's your job. Or, easier, just delete the view in the first place.
779 * It will remove itself. TODO: this could be converted to a private slot
780 * connected to the view's destroyed() signal. It is not currently called
781 * anywhere except from the KTextEditor::ViewPrivate destructor.
782 */
783 void removeView(KTextEditor::View *);
784 void setActiveView(KTextEditor::View *);
785
786 bool ownedView(KTextEditor::ViewPrivate *);
787
788 int toVirtualColumn(int line, int column) const;
789 int toVirtualColumn(const KTextEditor::Cursor) const;
790 int fromVirtualColumn(int line, int column) const;
791 int fromVirtualColumn(const KTextEditor::Cursor) const;
792
793 enum NewLineIndent { Indent, NoIndent };
794 enum NewLinePos { Normal, Above, Below };
795
796 void newLine(KTextEditor::ViewPrivate *view, NewLineIndent indent = NewLineIndent::Indent, NewLinePos newLinePos = Normal); // Changes input
797 void backspace(KTextEditor::ViewPrivate *view);
798 void del(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor);
799 void transpose(const KTextEditor::Cursor);
800 void swapTextRanges(KTextEditor::Range firstWord, KTextEditor::Range secondWord);
801 bool multiPaste(KTextEditor::ViewPrivate *view, const QStringList &texts);
802 void paste(KTextEditor::ViewPrivate *view, const QString &text);
803
804public:
805 enum CommentType {
806 UnComment = -1,
807 ToggleComment = 0,
808 Comment = 1,
809 };
810
811private:
812 // Helper function for use with multiple cursors
813 KTEXTEDITOR_NO_EXPORT
814 KTextEditor::Cursor backspaceAtCursor(KTextEditor::ViewPrivate *v, KTextEditor::Cursor c);
815 void commentSelection(KTextEditor::Range selection, KTextEditor::Cursor c, bool blockSelect, CommentType changeType);
816 // exported for katedocument_test
817 KTEXTEDITOR_NO_EXPORT
818 bool skipAutoBrace(QChar closingBracket, KTextEditor::Cursor pos);
819
820public:
821 void indent(KTextEditor::Range range, int change);
822 void comment(KTextEditor::ViewPrivate *view, uint line, uint column, CommentType change);
823 void align(KTextEditor::ViewPrivate *view, KTextEditor::Range range);
824 void alignOn(KTextEditor::Range range, const QString &pattern, bool blockwise);
825 void insertTab(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor);
826
827 enum TextTransform { Uppercase, Lowercase, Capitalize };
828
829 /**
830 Handling uppercase, lowercase and capitalize for the view.
831
832 If there is a selection, that is transformed, otherwise for uppercase or
833 lowercase the character right of the cursor is transformed, for capitalize
834 the word under the cursor is transformed.
835 */
836 void transform(KTextEditor::ViewPrivate *view, KTextEditor::Cursor, TextTransform);
837 /**
838 Unwrap a range of lines.
839 */
840 void joinLines(uint first, uint last);
841
842private:
843 KTEXTEDITOR_NO_EXPORT
844 void transformCursorOrRange(KTextEditor::ViewPrivate *view, const KTextEditor::Cursor, KTextEditor::Range selection, TextTransform);
845
846 KTEXTEDITOR_NO_EXPORT
847 bool removeStringFromBeginning(int line, const QString &str);
848 KTEXTEDITOR_NO_EXPORT
849 bool removeStringFromEnd(int line, const QString &str);
850
851 /**
852 Expand tabs to spaces in typed text, if enabled.
853 @param cursorPos The current cursor position for the inserted characters.
854 @param str The typed characters to expand.
855 */
856 KTEXTEDITOR_NO_EXPORT
857 QString eventuallyReplaceTabs(const KTextEditor::Cursor cursorPos, const QString &str) const;
858
859 /**
860 Find the position (line and col) of the next char
861 that is not a space. If found line and col point to the found character.
862 Otherwise they have both the value -1.
863 @param line Line of the character which is examined first.
864 @param col Column of the character which is examined first.
865 @return True if the specified or a following character is not a space
866 Otherwise false.
867 */
868 KTEXTEDITOR_NO_EXPORT
869 bool nextNonSpaceCharPos(int &line, int &col);
870
871 /**
872 Find the position (line and col) of the previous char
873 that is not a space. If found line and col point to the found character.
874 Otherwise they have both the value -1.
875 @return True if the specified or a preceding character is not a space.
876 Otherwise false.
877 */
878 KTEXTEDITOR_NO_EXPORT
879 bool previousNonSpaceCharPos(int &line, int &col);
880
881 /**
882 * Sets a comment marker as defined by the language providing the attribute
883 * @p attrib on the line @p line
884 */
885 KTEXTEDITOR_NO_EXPORT
886 void addStartLineCommentToSingleLine(int line, int attrib = 0);
887 /**
888 * Removes a comment marker as defined by the language providing the attribute
889 * @p attrib on the line @p line
890 */
891 KTEXTEDITOR_NO_EXPORT
892 bool removeStartLineCommentFromSingleLine(int line, int attrib = 0);
893
894 /**
895 * @see addStartLineCommentToSingleLine.
896 */
897 KTEXTEDITOR_NO_EXPORT
898 void addStartStopCommentToSingleLine(int line, int attrib = 0);
899 /**
900 *@see removeStartLineCommentFromSingleLine.
901 */
902 KTEXTEDITOR_NO_EXPORT
903 bool removeStartStopCommentFromSingleLine(int line, int attrib = 0);
904 /**
905 *@see removeStartLineCommentFromSingleLine.
906 */
907 KTEXTEDITOR_NO_EXPORT
908 bool removeStartStopCommentFromRegion(const KTextEditor::Cursor start, const KTextEditor::Cursor end, int attrib = 0);
909
910 /**
911 * Add a comment marker as defined by the language providing the attribute
912 * @p attrib to each line in the selection.
913 */
914 KTEXTEDITOR_NO_EXPORT
915 void addStartStopCommentToSelection(KTextEditor::Range, bool blockSelection, int attrib = 0);
916 /**
917 * @see addStartStopCommentToSelection.
918 */
919 KTEXTEDITOR_NO_EXPORT
920 void addStartLineCommentToSelection(KTextEditor::Range, int attrib = 0);
921
922 /**
923 * Removes comment markers relevant to the language providing
924 * the attribute @p attrib from each line in the selection.
925 *
926 * @return whether the operation succeeded.
927 */
928 KTEXTEDITOR_NO_EXPORT
929 bool removeStartStopCommentFromSelection(KTextEditor::Range, int attrib = 0);
930 /**
931 * @see removeStartStopCommentFromSelection.
932 */
933 KTEXTEDITOR_NO_EXPORT
934 bool removeStartLineCommentFromSelection(KTextEditor::Range, int attrib, bool toggleComment);
935
936public:
937 KTextEditor::Range findMatchingBracket(const KTextEditor::Cursor start, int maxLines);
938
939public:
940 QString documentName() const override
941 {
942 return m_docName;
943 }
944
945private:
946 KTEXTEDITOR_NO_EXPORT
947 void updateDocName();
948 KTEXTEDITOR_NO_EXPORT
949 static void uniquifyDocNames(const std::vector<KTextEditor::DocumentPrivate *> &docs);
950
951public:
952 /**
953 * @return whether the document is modified on disk since last saved
954 */
955 bool isModifiedOnDisc()
956 {
957 return m_modOnHd;
958 }
959
960 void setModifiedOnDisk(ModifiedOnDiskReason reason) override;
961
962 void setModifiedOnDiskWarning(bool on) override;
963
964public Q_SLOTS:
965 /**
966 * Ask the user what to do, if the file has been modified on disk.
967 * Reimplemented from KTextEditor::Document.
968 */
969 virtual void slotModifiedOnDisk(KTextEditor::View *v = nullptr);
970
971 /**
972 * Reloads the current document from disk if possible
973 */
974 bool documentReload() override;
975
976 bool documentSave() override;
977 bool documentSaveAs() override;
978 bool documentSaveAsWithEncoding(const QString &encoding);
979 void documentSaveCopyAs();
980
981 bool save() override;
982
983public:
984 bool saveAs(const QUrl &url) override;
985
986private:
987 // helper to handle the embedded notification for externally modified files
988 QPointer<KateModOnHdPrompt> m_modOnHdHandler;
989
990private Q_SLOTS:
991 void onModOnHdSaveAs();
992 void onModOnHdClose();
993 void onModOnHdReload();
994 void onModOnHdAutoReload();
995 void onModOnHdIgnore();
996
997public:
998 bool setEncoding(const QString &e) override;
999 QString encoding() const override;
1000
1001public Q_SLOTS:
1002 void setWordWrap(bool on);
1003 void setWordWrapAt(uint col);
1004
1005public:
1006 bool wordWrap() const;
1007 uint wordWrapAt() const;
1008
1009public Q_SLOTS:
1010 void setPageUpDownMovesCursor(bool on);
1011
1012public:
1013 bool pageUpDownMovesCursor() const;
1014
1015 // code folding
1016public:
1017 /**
1018 * Same as plainKateTextLine(), except that it is made sure
1019 * the line is highlighted.
1020 */
1021 Kate::TextLine kateTextLine(int i);
1022
1023 //! @copydoc KateBuffer::plainLine()
1024 Kate::TextLine plainKateTextLine(int i);
1025
1026Q_SIGNALS:
1027 void aboutToRemoveText(KTextEditor::Range);
1028
1029private Q_SLOTS:
1030 void slotModOnHdDirty(const QString &path);
1031 void slotModOnHdCreated(const QString &path);
1032 void slotModOnHdDeleted(const QString &path);
1033 void slotDelayedHandleModOnHd();
1034
1035private:
1036 /**
1037 * Create a git compatible sha1 checksum of the file, if it is a local file.
1038 * The result can be accessed through KateBuffer::digest().
1039 *
1040 * @return whether the operation was attempted and succeeded.
1041 */
1042 bool createDigest();
1043 // exported for katedocument_test
1044
1045 /**
1046 * create a string for the modonhd warnings, giving the reason.
1047 */
1048 KTEXTEDITOR_NO_EXPORT
1049 QString reasonedMOHString() const;
1050
1051 /**
1052 * Removes all trailing whitespace in the document and add new line at eof
1053 * if configured that way.
1054 */
1055 KTEXTEDITOR_NO_EXPORT
1056 void removeTrailingSpacesAndAddNewLineAtEof();
1057
1058public:
1059 /**
1060 * This function doesn't check for config and is
1061 * available for use all the time via an action
1062 */
1063 void removeAllTrailingSpaces();
1064
1065 /**
1066 * Returns a git compatible sha1 checksum of this document on disk.
1067 * @return checksum for this document on disk
1068 */
1069 QByteArray checksum() const override;
1070
1071 /**
1072 * @return false if @p newType is an invalid mode.
1073 */
1074 bool updateFileType(const QString &newType, bool user = false);
1075
1076 QString fileType() const
1077 {
1078 return m_fileType;
1079 }
1080
1081 /**
1082 * Get access to buffer of this document.
1083 * Is needed to create cursors and ranges for example.
1084 * @return document buffer
1085 */
1086 KateBuffer &buffer()
1087 {
1088 return *m_buffer;
1089 }
1090
1091 /**
1092 * set indentation mode by user
1093 * this will remember that a user did set it and will avoid reset on save
1094 */
1095 void rememberUserDidSetIndentationMode()
1096 {
1097 m_indenterSetByUser = true;
1098 }
1099
1100 /**
1101 * User did set encoding for next reload => enforce it!
1102 */
1103 void userSetEncodingForNextReload()
1104 {
1105 m_userSetEncodingForNextReload = true;
1106 }
1107
1108 //
1109 // REALLY internal data ;)
1110 //
1111private:
1112 // text buffer
1113 KateBuffer *const m_buffer;
1114
1115 // indenter
1116 KateAutoIndent *const m_indenter;
1117
1118 bool m_hlSetByUser = false;
1119 bool m_bomSetByUser = false;
1120 bool m_indenterSetByUser = false;
1121 bool m_userSetEncodingForNextReload = false;
1122
1123 bool m_modOnHd = false;
1124 KToggleAction *m_autoReloadMode;
1125 QTimer m_autoReloadThrottle;
1126 ModifiedOnDiskReason m_modOnHdReason = OnDiskUnmodified;
1127 ModifiedOnDiskReason m_prevModOnHdReason = OnDiskUnmodified;
1128
1129 QString m_docName;
1130 int m_docNameNumber = 0;
1131
1132 // file type !!!
1133 QString m_fileType;
1134 bool m_fileTypeSetByUser = false;
1135
1136 /**
1137 * document is still reloading a file
1138 */
1139 bool m_reloading = false;
1140
1141public Q_SLOTS:
1142 void slotQueryClose_save(bool *handled, bool *abortClosing);
1143
1144public:
1145 bool queryClose() override;
1146
1147 /**
1148 * Configuration
1149 */
1150public:
1151 KateDocumentConfig *config()
1152 {
1153 return m_config.get();
1154 }
1155 KateDocumentConfig *config() const
1156 {
1157 return m_config.get();
1158 }
1159
1160 void updateConfig();
1161
1162private:
1163 KTEXTEDITOR_NO_EXPORT
1164 void makeAttribs(bool needInvalidate = true);
1165
1166 std::unique_ptr<KateDocumentConfig> const m_config;
1167
1168 /**
1169 * Variable Reader
1170 * TODO add register functionality/ktexteditor interface
1171 */
1172private:
1173 /**
1174 * read dir config file
1175 */
1176 KTEXTEDITOR_NO_EXPORT
1177 void readDirConfig();
1178
1179 /**
1180 Reads all the variables in the document.
1181 Called when opening/saving a document
1182 Returns true if variables were read
1183 */
1184 bool readVariables(bool onlyViewAndRenderer = false);
1185 // exported for katedocument_test
1186
1187 /**
1188 Reads and applies the variables in a single line
1189 TODO registered variables gets saved in a [map]
1190 */
1191 void readVariableLine(const QString &t, bool onlyViewAndRenderer = false);
1192 // exported for katedocument_test
1193 /**
1194 Sets a view variable in all the views.
1195 */
1196 KTEXTEDITOR_NO_EXPORT
1197 void setViewVariable(const QString &var, const QString &val);
1198 /**
1199 @return weather a string value could be converted
1200 to a bool value as supported.
1201 The value is put in *result.
1202 */
1203 KTEXTEDITOR_NO_EXPORT
1204 static bool checkBoolValue(QString value, bool *result);
1205 /**
1206 @return weather a string value could be converted
1207 to a integer value.
1208 The value is put in *result.
1209 */
1210 KTEXTEDITOR_NO_EXPORT
1211 static bool checkIntValue(const QString &value, int *result);
1212 /**
1213 Feeds value into @p col using QColor::fromString() and returns
1214 whether the color is valid
1215 */
1216 KTEXTEDITOR_NO_EXPORT
1217 static bool checkColorValue(const QString &value, QColor &col);
1218
1219 bool m_fileChangedDialogsActivated = false;
1220
1221 //
1222 // KTextEditor::ConfigInterface
1223 //
1224public:
1225 QStringList configKeys() const override;
1226 QVariant configValue(const QString &key) override;
1227 void setConfigValue(const QString &key, const QVariant &value) override;
1228
1229 //
1230 // KTextEditor::RecoveryInterface
1231 //
1232public:
1233 bool isDataRecoveryAvailable() const override;
1234 void recoverData() override;
1235 void discardDataRecovery() override;
1236
1237 //
1238 // Highlighting information
1239 //
1240public:
1241 QStringList embeddedHighlightingModes() const override;
1242 QString highlightingModeAt(KTextEditor::Cursor position) override;
1243
1244 //
1245 // BEGIN: KTextEditor::MessageInterface
1246 //
1247public:
1248 bool postMessage(KTextEditor::Message *message) override;
1249
1250public Q_SLOTS:
1251 void messageDestroyed(KTextEditor::Message *message);
1252
1253private:
1254 QHash<KTextEditor::Message *, QList<std::shared_ptr<QAction>>> m_messageHash;
1255 // END KTextEditor::MessageInterface
1256
1257public:
1258 QString defaultDictionary() const;
1259 QList<QPair<KTextEditor::MovingRange *, QString>> dictionaryRanges() const;
1260 bool isOnTheFlySpellCheckingEnabled() const;
1261 KateOnTheFlyChecker *onTheFlySpellChecker() const
1262 {
1263 return m_onTheFlyChecker;
1264 }
1265
1266 QString dictionaryForMisspelledRange(KTextEditor::Range range) const;
1267 void clearMisspellingForWord(const QString &word);
1268
1269public Q_SLOTS:
1270 void clearDictionaryRanges();
1271 void setDictionary(const QString &dict, KTextEditor::Range range, bool blockmode);
1272 void setDictionary(const QString &dict, KTextEditor::Range range);
1273 void setDefaultDictionary(const QString &dict);
1274 void onTheFlySpellCheckingEnabled(bool enable);
1275 void refreshOnTheFlyCheck(KTextEditor::Range range = KTextEditor::Range::invalid());
1276
1277Q_SIGNALS:
1278 void dictionaryRangesPresent(bool yesNo);
1279 void defaultDictionaryChanged(KTextEditor::DocumentPrivate *document);
1280
1281public:
1282 bool containsCharacterEncoding(KTextEditor::Range range);
1283
1284 typedef QList<QPair<int, int>> OffsetList;
1285
1286 static int computePositionWrtOffsets(const OffsetList &offsetList, int pos);
1287
1288 /**
1289 * The first OffsetList is from decoded to encoded, and the second OffsetList from
1290 * encoded to decoded.
1291 **/
1292 QString decodeCharacters(KTextEditor::Range range,
1293 KTextEditor::DocumentPrivate::OffsetList &decToEncOffsetList,
1294 KTextEditor::DocumentPrivate::OffsetList &encToDecOffsetList);
1295 void replaceCharactersByEncoding(KTextEditor::Range range);
1296
1297protected:
1298 KateOnTheFlyChecker *m_onTheFlyChecker = nullptr;
1299 QString m_defaultDictionary;
1300 QList<QPair<KTextEditor::MovingRange *, QString>> m_dictionaryRanges;
1301
1302 // from KTextEditor::MovingRangeFeedback
1303 void rangeInvalid(KTextEditor::MovingRange *movingRange) override;
1304 void rangeEmpty(KTextEditor::MovingRange *movingRange) override;
1305
1306 void deleteDictionaryRange(KTextEditor::MovingRange *movingRange);
1307
1308private:
1309 Kate::SwapFile *m_swapfile;
1310
1311public:
1312 Kate::SwapFile *swapFile();
1313
1314 // helpers for scripting and codefolding
1315 KSyntaxHighlighting::Theme::TextStyle defStyleNum(int line, int column);
1316 bool isComment(int line, int column);
1317
1318public:
1319 /**
1320 * Find the next modified/saved line, starting at @p startLine. If @p down
1321 * is \e true, the search is performed downwards, otherwise upwards.
1322 * @return the touched line in the requested search direction, or -1 if not found
1323 */
1324 int findTouchedLine(int startLine, bool down);
1325
1326private Q_SLOTS:
1327 /**
1328 * watch for all started io jobs to remember if file is perhaps loading atm
1329 * @param job started job
1330 */
1331 void slotStarted(KIO::Job *job);
1332 void slotCompleted();
1333 void slotCanceled();
1334
1335 /**
1336 * trigger display of loading message, after 1000 ms
1337 */
1338 void slotTriggerLoadingMessage();
1339
1340 /**
1341 * Abort loading
1342 */
1343 void slotAbortLoading();
1344
1345 void slotUrlChanged(const QUrl &url);
1346
1347private:
1348 /**
1349 * different possible states
1350 */
1351 enum DocumentStates {
1352 /**
1353 * Idle
1354 */
1355 DocumentIdle,
1356
1357 /**
1358 * Loading
1359 */
1360 DocumentLoading,
1361
1362 /**
1363 * Saving
1364 */
1365 DocumentSaving,
1366
1367 /**
1368 * Pre Saving As, this is between ::saveAs is called and ::save
1369 */
1370 DocumentPreSavingAs,
1371
1372 /**
1373 * Saving As
1374 */
1375 DocumentSavingAs
1376 };
1377
1378 /**
1379 * current state
1380 */
1381 DocumentStates m_documentState = DocumentIdle;
1382
1383 /**
1384 * read-write state before loading started
1385 */
1386 bool m_readWriteStateBeforeLoading = false;
1387
1388 /**
1389 * if the document is untitled
1390 */
1391 bool m_isUntitled = true;
1392 /**
1393 * loading job, we want to cancel with cancel in the loading message
1394 */
1395 QPointer<KJob> m_loadingJob;
1396
1397 /**
1398 * message to show during loading
1399 */
1400 QPointer<KTextEditor::Message> m_loadingMessage;
1401
1402 /**
1403 * Was there any open error on last file loading?
1404 */
1405 bool m_openingError = false;
1406
1407public:
1408 /**
1409 * reads the line length limit from config, if it is not overridden
1410 */
1411 int lineLengthLimit() const;
1412
1413public Q_SLOTS:
1414 void openWithLineLengthLimitOverride();
1415
1416private:
1417 /**
1418 * timer for delayed handling of mod on hd
1419 */
1420 QTimer m_modOnHdTimer;
1421
1422private:
1423 /**
1424 * currently active template handler; there can be only one
1425 */
1426 QPointer<KateTemplateHandler> m_activeTemplateHandler;
1427
1428private:
1429 /**
1430 * current autobrace range
1431 */
1432 std::unique_ptr<KTextEditor::MovingRange> m_currentAutobraceRange;
1433 /**
1434 * current autobrace closing character (e.g. ']')
1435 */
1436 QChar m_currentAutobraceClosingChar;
1437
1438private Q_SLOTS:
1439 void checkCursorForAutobrace(KTextEditor::View *view, const KTextEditor::Cursor newPos);
1440
1441public:
1442 void setActiveTemplateHandler(KateTemplateHandler *handler);
1443
1444Q_SIGNALS:
1445 void loaded(KTextEditor::DocumentPrivate *document);
1446
1447private:
1448 QList<KTextEditor::View *> m_views;
1449 QTimer m_autoSaveTimer;
1450};
1451
1452#endif
1453

source code of ktexteditor/src/document/katedocument.h