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

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