15#include "katedocument.h"
17#include "kateabstractinputmode.h"
18#include "kateautoindent.h"
19#include "katebuffer.h"
20#include "katecompletionwidget.h"
21#include "kateconfig.h"
22#include "katedialogs.h"
23#include "kateglobal.h"
24#include "katehighlight.h"
25#include "kateindentdetecter.h"
26#include "katemodemanager.h"
27#include "katepartdebug.h"
28#include "kateplaintextsearch.h"
29#include "kateregexpsearch.h"
30#include "katerenderer.h"
31#include "katescriptmanager.h"
32#include "kateswapfile.h"
33#include "katesyntaxmanager.h"
34#include "katetemplatehandler.h"
35#include "kateundomanager.h"
36#include "katevariableexpansionmanager.h"
38#include "printing/kateprinter.h"
39#include "spellcheck/ontheflycheck.h"
40#include "spellcheck/prefixstore.h"
41#include "spellcheck/spellcheck.h"
46#include "editorconfig.h"
49#include <KTextEditor/Attribute>
50#include <KTextEditor/DocumentCursor>
51#include <ktexteditor/message.h>
53#include <KConfigGroup>
56#include <KIO/FileCopyJob>
57#include <KIO/JobUiDelegate>
62#include <KNetworkMounts>
63#include <KParts/OpenUrlArguments>
64#include <KStringHandler>
65#include <KToggleAction>
66#include <KXMLGUIFactory>
68#include <QApplication>
70#include <QCryptographicHash>
74#include <QMimeDatabase>
76#include <QRegularExpression>
77#include <QStandardPaths>
78#include <QTemporaryFile>
86#define EDIT_DEBUG qCDebug(LOG_KTE)
93template<
class C,
class E>
94static int indexOf(
const std::initializer_list<C> &list,
const E &entry)
100template<
class C,
class E>
101static bool contains(
const std::initializer_list<C> &list,
const E &entry)
103 return indexOf(list, entry) >= 0;
106static inline QChar matchingStartBracket(
const QChar c)
119static inline QChar matchingEndBracket(
const QChar c,
bool withQuotes =
true)
136static inline QChar matchingBracket(
const QChar c)
138 QChar bracket = matchingStartBracket(c);
140 bracket = matchingEndBracket(c,
false);
145static inline bool isStartBracket(
const QChar c)
147 return !matchingEndBracket(c,
false).
isNull();
150static inline bool isEndBracket(
const QChar c)
152 return !matchingStartBracket(c).
isNull();
155static inline bool isBracket(
const QChar c)
157 return isStartBracket(c) || isEndBracket(c);
164KTextEditor::DocumentPrivate::DocumentPrivate(
const KPluginMetaData &data,
bool bSingleViewMode,
bool bReadOnly,
QWidget *parentWidget,
QObject *parent)
166 , m_bSingleViewMode(bSingleViewMode)
167 , m_bReadOnly(bReadOnly)
177 m_docName(QStringLiteral(
"need init"))
180 m_fileType(QStringLiteral(
"Normal"))
183 m_config(new KateDocumentConfig(this))
187 const auto &aboutData = EditorPrivate::self()->aboutData();
188 setComponentName(aboutData.componentName(), aboutData.displayName());
192 setProgressInfoEnabled(
false);
198 m_buffer->setHighlight(0);
201 m_swapfile = (config()->swapFileMode() == KateDocumentConfig::DisableSwapFile) ?
nullptr : new Kate::SwapFile(this);
207 connect(KateHlManager::self(), &KateHlManager::changed,
this, &KTextEditor::DocumentPrivate::internalHlChanged);
217 m_modOnHdTimer.setSingleShot(
true);
218 m_modOnHdTimer.setInterval(200);
219 connect(&m_modOnHdTimer, &
QTimer::timeout,
this, &KTextEditor::DocumentPrivate::slotDelayedHandleModOnHd);
223 m_autoReloadMode->setWhatsThis(
i18n(
"Automatic reload the document when it was changed on disk"));
226 m_autoReloadThrottle.setSingleShot(
true);
228 m_autoReloadThrottle.setInterval(QStandardPaths::isTestModeEnabled() ? 50 : 3000);
245 if (m_bSingleViewMode && parentWidget) {
247 insertChildClient(view);
252 connect(m_undoManager, &KateUndoManager::undoChanged,
this, &KTextEditor::DocumentPrivate::undoChanged);
261 onTheFlySpellCheckingEnabled(config()->onTheFlySpellCheck());
266 m_autoSaveTimer.setSingleShot(
true);
268 if (isModified() && url().isLocalFile()) {
277KTextEditor::DocumentPrivate::~DocumentPrivate()
284 delete m_modOnHdHandler;
290 delete m_onTheFlyChecker;
291 m_onTheFlyChecker =
nullptr;
293 clearDictionaryRanges();
301 deactivateDirWatch();
312 for (
auto &
mark : std::as_const(m_marks)) {
327 if (m_editingStackPosition != m_editingStack.size() - 1) {
328 m_editingStack.resize(m_editingStackPosition);
332 std::shared_ptr<KTextEditor::MovingCursor> mc;
335 if (!m_editingStack.isEmpty() && cursor.
line() == m_editingStack.top()->line()) {
336 mc = m_editingStack.pop();
341 const int editingStackSizeLimit = 32;
342 if (m_editingStack.size() >= editingStackSizeLimit) {
344 m_editingStack.removeFirst();
346 mc = m_editingStack.takeFirst();
352 mc->setPosition(cursor);
354 mc = std::shared_ptr<KTextEditor::MovingCursor>(newMovingCursor(cursor));
358 m_editingStack.push(mc);
359 m_editingStackPosition = m_editingStack.size() - 1;
364 if (m_editingStack.isEmpty()) {
367 auto targetPos = m_editingStack.at(m_editingStackPosition)->toCursor();
368 if (targetPos == currentCursor) {
369 if (nextOrPrev == Previous) {
370 m_editingStackPosition--;
372 m_editingStackPosition++;
374 m_editingStackPosition = qBound(0, m_editingStackPosition, m_editingStack.size() - 1);
376 return m_editingStack.at(m_editingStackPosition)->toCursor();
381 m_editingStack.clear();
382 m_editingStackPosition = -1;
389 if (!singleViewMode()) {
400 insertChildClient(view);
410 KTextEditor::ViewPrivate *newView =
new KTextEditor::ViewPrivate(
this, parent, mainWindow);
412 if (m_fileChangedDialogsActivated) {
416 Q_EMIT viewCreated(
this, newView);
419 const auto keys = m_messageHash.keys();
421 if (!message->view()) {
422 newView->postMessage(message, m_messageHash[message]);
431 const int col1 = toVirtualColumn(range.
start());
432 const int col2 = toVirtualColumn(range.
end());
433 return KTextEditor::Range(line, fromVirtualColumn(line, col1), line, fromVirtualColumn(line, col2));
440 return editSessionNumber > 0;
445 return m_buffer->text();
451 qCWarning(LOG_KTE) <<
"Text requested for invalid range" << range;
465 for (
int i = range.
start().
line(); (i <= range.
end().
line()) && (i < m_buffer->lines()); ++i) {
470 }
else if (i == range.
end().
line()) {
492 return textLine.
at(position.
column());
497 return text(wordRangeAt(cursor));
503 const int line = cursor.
line();
507 const int lineLenth = textLine.
length();
508 if (cursor.
column() > lineLenth) {
518 while (end < lineLenth && highlight()->isInWord(textLine.
at(end), textLine.
attribute(end))) {
527 const int ln = cursor.
line();
528 const int col = cursor.
column();
530 if (ln < 0 || col < 0 || ln >= lines() || col > lineLength(ln)) {
535 Q_ASSERT(str.
length() >= col);
538 const int len = lineLength(ln);
539 if (col == 0 || col == len) {
552 qCWarning(LOG_KTE) <<
"Text requested for invalid range" << range;
561 Q_ASSERT(range.
start() <= range.
end());
566 for (
int i = range.
start().
line(); (i <= range.
end().
line()) && (i < m_buffer->lines()); ++i) {
571 }
else if (i == range.
end().
line()) {
574 ret << textLine.
text();
592bool KTextEditor::DocumentPrivate::setText(
const QString &s)
594 if (!isReadWrite()) {
598 std::vector<KTextEditor::Mark> msave;
599 msave.reserve(m_marks.size());
600 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(msave), [](
KTextEditor::Mark *mark) {
604 for (
auto v : std::as_const(m_views)) {
605 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
618 for (
auto v : std::as_const(m_views)) {
619 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
623 setMark(mark.line, mark.type);
629bool KTextEditor::DocumentPrivate::setText(
const QStringList &text)
631 if (!isReadWrite()) {
635 std::vector<KTextEditor::Mark> msave;
636 msave.reserve(m_marks.size());
637 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(msave), [](
KTextEditor::Mark *mark) {
641 for (
auto v : std::as_const(m_views)) {
642 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
655 for (
auto v : std::as_const(m_views)) {
656 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
660 setMark(mark.line, mark.type);
666bool KTextEditor::DocumentPrivate::clear()
668 if (!isReadWrite()) {
672 for (
auto view : std::as_const(m_views)) {
673 static_cast<ViewPrivate *
>(view)->
clear();
674 static_cast<ViewPrivate *
>(view)->tagAll();
680 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
681 m_buffer->invalidateRanges();
683 Q_EMIT aboutToRemoveText(documentRange());
685 return editRemoveLines(0, lastLine());
690 if (!isReadWrite()) {
704 auto insertStart = position;
705 int currentLine = position.
line();
706 int currentLineStart = 0;
707 const int totalLength = text.
length();
708 int insertColumn = position.
column();
711 if (position.
line() > lines()) {
713 while (line <= position.
line()) {
714 editInsertLine(line,
QString(),
false);
717 if (insertStart == position) {
718 insertStart = m_editLastChangeStartCursor;
726 int positionColumnExpanded = insertColumn;
727 const int tabWidth = config()->tabWidth();
729 if (currentLine < lines()) {
730 positionColumnExpanded = plainKateTextLine(currentLine).toVirtualColumn(insertColumn, tabWidth);
736 for (; pos < totalLength; pos++) {
737 const QChar &ch = text.
at(pos);
741 if (currentLineStart < pos) {
742 editInsertText(currentLine, insertColumn, text.
mid(currentLineStart, pos - currentLineStart), notify);
743 endCol = insertColumn + (pos - currentLineStart);
748 const auto wrapColumn = insertColumn + pos - currentLineStart;
749 const auto currentLineLength = lineLength(currentLine);
750 if (wrapColumn > currentLineLength) {
751 editInsertText(currentLine, currentLineLength,
QString(wrapColumn - currentLineLength,
QLatin1Char(
' ')), notify);
755 editWrapLine(currentLine, wrapColumn,
true,
nullptr, notify);
763 auto l = currentLine < lines();
764 if (currentLine == lastLine() + 1) {
765 editInsertLine(currentLine,
QString(), notify);
768 insertColumn = positionColumnExpanded;
770 insertColumn = plainKateTextLine(currentLine).fromVirtualColumn(insertColumn, tabWidth);
774 currentLineStart = pos + 1;
779 if (currentLineStart < pos) {
780 editInsertText(currentLine, insertColumn, text.
mid(currentLineStart, pos - currentLineStart), notify);
781 endCol = insertColumn + (pos - currentLineStart);
786 Q_EMIT textInsertedRange(
this, insertedRange);
794 if (!isReadWrite()) {
806 if (!isReadWrite()) {
818 Q_EMIT aboutToRemoveText(range);
824 if (range.
end().
line() > lastLine()) {
835 if (to <= lastLine()) {
836 editRemoveText(to, 0, range.
end().
column());
845 editRemoveLines(from + 1, to - 1);
849 editRemoveText(from, range.
start().
column(), m_buffer->plainLine(from).length() - range.
start().
column());
850 editUnWrapLine(from);
855 int startLine = qMax(0, range.
start().
line());
856 int vc1 = toVirtualColumn(range.
start());
857 int vc2 = toVirtualColumn(range.
end());
858 for (
int line = qMin(range.
end().
line(), lastLine()); line >= startLine; --line) {
859 int col1 = fromVirtualColumn(line, vc1);
860 int col2 = fromVirtualColumn(line, vc2);
861 editRemoveText(line, qMin(col1, col2), qAbs(col2 - col1));
869bool KTextEditor::DocumentPrivate::insertLine(
int l,
const QString &str)
871 if (!isReadWrite()) {
875 if (l < 0 || l > lines()) {
879 return editInsertLine(l, str);
882bool KTextEditor::DocumentPrivate::insertLines(
int line,
const QStringList &text)
884 if (!isReadWrite()) {
888 if (line < 0 || line > lines()) {
893 for (
const QString &
string : text) {
894 success &= editInsertLine(line++,
string);
900bool KTextEditor::DocumentPrivate::removeLine(
int line)
902 if (!isReadWrite()) {
906 if (line < 0 || line > lastLine()) {
910 return editRemoveLine(line);
916 for (
int i = 0; i < m_buffer->lines(); ++i) {
917 l += m_buffer->lineLength(i);
924 return m_buffer->lines();
929 return m_buffer->lineLength(line);
934 return m_buffer->cursorToOffset(c);
939 return m_buffer->offsetToCursor(offset);
944 if (line < 0 || line >= lines()) {
949 return l.markedAsModified();
954 if (line < 0 || line >= lines()) {
959 return l.markedAsSavedOnDisk();
964 if (line < 0 || line >= lines()) {
969 return l.markedAsModified() || l.markedAsSavedOnDisk();
981 if (editSessionNumber > 1) {
985 editIsRunning =
true;
990 m_undoManager->editStart();
992 for (
auto view : std::as_const(m_views)) {
993 static_cast<ViewPrivate *
>(view)->editStart();
996 m_buffer->editStart();
1005 if (editSessionNumber == 0) {
1011 if (m_buffer->editChanged() && (editSessionNumber == 1)) {
1012 if (m_undoManager->isActive() && config()->wordWrap()) {
1013 wrapText(m_buffer->editTagStart(), m_buffer->editTagEnd());
1017 editSessionNumber--;
1019 if (editSessionNumber > 0) {
1025 m_buffer->editEnd();
1027 m_undoManager->editEnd();
1030 for (
auto view : std::as_const(m_views)) {
1031 static_cast<ViewPrivate *
>(view)->editEnd(m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
1034 if (m_buffer->editChanged()) {
1036 Q_EMIT textChanged(
this);
1042 if (m_editLastChangeStartCursor.isValid()) {
1043 saveEditingPositions(m_editLastChangeStartCursor);
1046 if (config()->autoSave() && config()->autoSaveInterval() > 0) {
1047 m_autoSaveTimer.start();
1050 editIsRunning =
false;
1054void KTextEditor::DocumentPrivate::pushEditState()
1056 editStateStack.push(editSessionNumber);
1059void KTextEditor::DocumentPrivate::popEditState()
1061 if (editStateStack.isEmpty()) {
1065 int count = editStateStack.pop() - editSessionNumber;
1076void KTextEditor::DocumentPrivate::inputMethodStart()
1078 m_undoManager->inputMethodStart();
1081void KTextEditor::DocumentPrivate::inputMethodEnd()
1083 m_undoManager->inputMethodEnd();
1088 if (startLine < 0 || endLine < 0) {
1092 if (!isReadWrite()) {
1096 int col = config()->wordWrapAt();
1104 for (
int line = startLine; (line <= endLine) && (line < lines()); line++) {
1110 bool nextlValid = line + 1 < lines();
1115 int eolPosition = l.
length() - 1;
1121 for (; z2 < l.
length(); z2++) {
1123 if (t.
at(z2) == tabChar) {
1124 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
1134 const int colInChars = qMin(z2, l.
length() - 1);
1135 int searchStart = colInChars;
1139 if (searchStart == eolPosition && t.
at(searchStart).
isSpace()) {
1151 for (z = searchStart; z >= 0; z--) {
1155 if ((nw < 0) && highlight()->canBreakAt(t.
at(z), l.
attribute(z))) {
1171 if ((nw >= 0) && nw < colInChars) {
1174 z = (nw >= 0) ? nw : colInChars;
1178 editWrapLine(line, z,
true);
1179 editMarkLineAutoWrapped(line + 1,
true);
1184 editInsertText(line + 1, 0, QStringLiteral(
" "));
1187 bool newLineAdded =
false;
1188 editWrapLine(line, z,
false, &newLineAdded);
1190 editMarkLineAutoWrapped(line + 1,
true);
1204 if (first == last) {
1205 return wrapText(first, last);
1208 if (first < 0 || last < first) {
1212 if (last >= lines() || first > last) {
1216 if (!isReadWrite()) {
1223 std::unique_ptr<KTextEditor::MovingRange> range(newMovingRange(
KTextEditor::Range(first, 0, last, 0)));
1224 std::unique_ptr<KTextEditor::MovingCursor> curr(newMovingCursor(
KTextEditor::Cursor(range->start())));
1227 for (
int line = first; line <= range->end().line(); ++line) {
1229 if (plainKateTextLine(first).firstChar() < 0) {
1232 curr->setPosition(curr->line() + 1, 0);
1237 if (plainKateTextLine(line).firstChar() < 0) {
1238 curr->setPosition(line, 0);
1239 joinLines(first, line - 1);
1242 wrapText(first, first);
1244 first = curr->line() + 1;
1250 bool needWrap = (curr->line() != range->end().line());
1251 if (needWrap && plainKateTextLine(first).firstChar() != -1) {
1252 joinLines(first, range->end().line());
1255 wrapText(first, first);
1266 EDIT_DEBUG <<
"editInsertText" << line << col << s;
1268 if (line < 0 || col < 0) {
1277 if (!isReadWrite()) {
1281 auto l = plainKateTextLine(line);
1282 int length = l.length();
1291 if (col2 > length) {
1296 m_undoManager->slotTextInserted(line, col2, s2, l);
1302 m_buffer->insertText(m_editLastChangeStartCursor, s2);
1315 EDIT_DEBUG <<
"editRemoveText" << line << col << len;
1317 if (line < 0 || line >= lines() || col < 0 || len < 0) {
1321 if (!isReadWrite()) {
1338 len = qMin(len, l.
text().
size() - col);
1344 m_undoManager->slotTextRemoved(line, col, oldText, l);
1362 EDIT_DEBUG <<
"editMarkLineAutoWrapped" << line << autowrapped;
1364 if (line < 0 || line >= lines()) {
1368 if (!isReadWrite()) {
1374 m_undoManager->slotMarkLineAutoWrapped(line, autowrapped);
1378 m_buffer->setLineMetaData(line, l);
1388 EDIT_DEBUG <<
"editWrapLine" << line << col << newLine;
1390 if (line < 0 || line >= lines() || col < 0) {
1394 if (!isReadWrite()) {
1398 const auto tl = plainKateTextLine(line);
1402 const bool nextLineValid = lineLength(line + 1) >= 0;
1404 m_undoManager->slotLineWrapped(line, col, tl.length() - col, (!nextLineValid || newLine), tl);
1406 if (!nextLineValid || newLine) {
1410 for (
const auto &mark : std::as_const(m_marks)) {
1411 if (mark->line >= line) {
1412 if ((col == 0) || (mark->line > line)) {
1418 for (
const auto &mark : list) {
1419 m_marks.take(mark->line);
1422 for (
const auto &mark : list) {
1424 m_marks.insert(mark->line, mark);
1427 if (!list.
empty()) {
1428 Q_EMIT marksChanged(
this);
1433 (*newLineAdded) =
true;
1437 m_buffer->unwrapLine(line + 2);
1441 (*newLineAdded) =
false;
1460 EDIT_DEBUG <<
"editUnWrapLine" << line << removeLine << length;
1462 if (line < 0 || line >= lines() || line + 1 >= lines() || length < 0) {
1466 if (!isReadWrite()) {
1476 m_undoManager->slotLineUnWrapped(line, col, length, removeLine, tl, nextLine);
1479 m_buffer->unwrapLine(line + 1);
1482 m_buffer->unwrapLine(line + 1);
1486 for (
const auto &mark : std::as_const(m_marks)) {
1487 if (mark->line >= line + 1) {
1491 if (mark->line == line + 1) {
1492 auto m = m_marks.take(line);
1494 mark->type |= m->type;
1500 for (
const auto &mark : list) {
1501 m_marks.take(mark->line);
1504 for (
const auto &mark : list) {
1506 m_marks.insert(mark->line, mark);
1510 Q_EMIT marksChanged(
this);
1516 Q_EMIT textRemoved(
this,
KTextEditor::Range(line, col, line + 1, 0), QStringLiteral(
"\n"));
1526 EDIT_DEBUG <<
"editInsertLine" << line << s;
1532 if (!isReadWrite()) {
1536 if (line > lines()) {
1542 m_undoManager->slotLineInserted(line, s);
1556 for (
const auto &mark : std::as_const(m_marks)) {
1557 if (mark->line >= line) {
1562 for (
const auto &mark : list) {
1563 m_marks.take(mark->line);
1566 for (
const auto &mark : list) {
1568 m_marks.insert(mark->line, mark);
1572 Q_EMIT marksChanged(
this);
1578 int prevLineLength = lineLength(line - 1);
1585 m_editLastChangeStartCursor = rangeInserted.
start();
1588 Q_EMIT textInsertedRange(
this, rangeInserted);
1598 return editRemoveLines(line, line);
1601bool KTextEditor::DocumentPrivate::editRemoveLines(
int from,
int to)
1604 EDIT_DEBUG <<
"editRemoveLines" << from << to;
1606 if (to < from || from < 0 || to > lastLine()) {
1610 if (!isReadWrite()) {
1615 return editRemoveText(0, 0, lineLength(0));
1622 for (
int line = to; line >= from; --line) {
1625 m_undoManager->slotLineRemoved(line, l.
text(), l);
1631 for (
int line = to; line >= from; --line) {
1633 if (line + 1 < m_buffer->lines()) {
1634 m_buffer->unwrapLine(line + 1);
1636 m_buffer->unwrapLine(line);
1644 int line = mark->line;
1647 }
else if (line >= from) {
1652 for (
int line : rmark) {
1653 delete m_marks.take(line);
1656 for (
auto mark :
list) {
1657 m_marks.take(mark->line);
1660 for (
auto mark :
list) {
1661 mark->line -= to - from + 1;
1662 m_marks.insert(mark->line, mark);
1666 Q_EMIT marksChanged(
this);
1671 if (to == lastLine() + to - from + 1) {
1674 int prevLineLength = lineLength(from - 1);
1680 m_editLastChangeStartCursor = rangeRemoved.start();
1691uint KTextEditor::DocumentPrivate::undoCount()
const
1693 return m_undoManager->undoCount();
1696uint KTextEditor::DocumentPrivate::redoCount()
const
1698 return m_undoManager->redoCount();
1701void KTextEditor::DocumentPrivate::undo()
1703 m_undoManager->undo();
1706void KTextEditor::DocumentPrivate::redo()
1708 m_undoManager->redo();
1730 return searcher.search(pattern, range, backwards, patternOptions);
1733 if (escapeSequences) {
1753QWidget *KTextEditor::DocumentPrivate::dialogParent()
1770QUrl KTextEditor::DocumentPrivate::getSaveFileUrl(
const QString &dialogTitle)
1773 QUrl startUrl = url();
1783 const auto views = mainWindow->views();
1784 for (
auto view : views) {
1800 return updateFileType(name);
1819 for (KateFileType *type : modeList) {
1828 int mode = KateHlManager::self()->nameFind(name);
1832 m_buffer->setHighlight(mode);
1838 return highlight()->name();
1843 const auto modeList = KateHlManager::self()->modeList();
1846 for (
const auto &hl : modeList) {
1854 return KateHlManager::self()->modeList().at(index).section();
1862void KTextEditor::DocumentPrivate::bufferHlChanged()
1868 m_indenter->checkRequiredStyle();
1870 Q_EMIT highlightingModeChanged(
this);
1875 m_hlSetByUser =
true;
1880 m_bomSetByUser =
true;
1887 if (!flags.
contains(QStringLiteral(
"SkipEncoding"))) {
1890 if (!tmpenc.
isEmpty() && (tmpenc != encoding())) {
1891 setEncoding(tmpenc);
1895 if (!flags.
contains(QStringLiteral(
"SkipUrl"))) {
1909 if (!flags.
contains(QStringLiteral(
"SkipMode"))) {
1913 if (kconfig.
hasKey(
"Mode Set By User")) {
1915 m_fileTypeSetByUser =
true;
1916 updateFileType(kconfig.
readEntry(
"Mode"));
1920 if (!flags.
contains(QStringLiteral(
"SkipHighlighting"))) {
1922 if (kconfig.
hasKey(
"Highlighting Set By User")) {
1923 const int mode = KateHlManager::self()->nameFind(kconfig.
readEntry(
"Highlighting"));
1924 m_hlSetByUser =
true;
1927 m_buffer->setHighlight(mode);
1934 if (!userSetIndentMode.
isEmpty()) {
1935 config()->setIndentationMode(userSetIndentMode);
1940 for (
int i = 0; i < marks.
count(); i++) {
1950 if (this->url().isLocalFile()) {
1951 const QString path = this->url().toLocalFile();
1957 if (!flags.
contains(QStringLiteral(
"SkipUrl"))) {
1959 kconfig.
writeEntry(
"URL", this->url().toString());
1963 if (encoding() !=
QLatin1String(
"UTF-8") && !m_buffer->brokenEncoding() && !flags.
contains(QStringLiteral(
"SkipEncoding"))) {
1968 if (m_fileTypeSetByUser && !flags.
contains(QStringLiteral(
"SkipMode"))) {
1972 kconfig.
writeEntry(
"Mode Set By User", m_fileTypeSetByUser);
1975 if (m_hlSetByUser && !flags.
contains(QStringLiteral(
"SkipHighlighting"))) {
1977 kconfig.
writeEntry(
"Highlighting", highlight()->name());
1980 kconfig.
writeEntry(
"Highlighting Set By User", m_hlSetByUser);
1984 if (m_indenterSetByUser) {
1985 kconfig.
writeEntry(
"Indentation Mode", config()->indentationMode());
1990 for (
const auto &mark : std::as_const(m_marks)) {
2013void KTextEditor::DocumentPrivate::setMark(
int line, uint markType)
2016 addMark(line, markType);
2019void KTextEditor::DocumentPrivate::clearMark(
int line)
2021 if (line < 0 || line > lastLine()) {
2025 if (
auto mark = m_marks.take(line)) {
2026 Q_EMIT markChanged(
this, *mark, MarkRemoved);
2027 Q_EMIT marksChanged(
this);
2034void KTextEditor::DocumentPrivate::addMark(
int line, uint markType)
2038 if (line < 0 || line > lastLine()) {
2042 if (markType == 0) {
2046 if ((mark = m_marks.value(line))) {
2048 markType &= ~mark->type;
2050 if (markType == 0) {
2055 mark->
type |= markType;
2059 mark->
type = markType;
2060 m_marks.insert(line, mark);
2066 temp.
type = markType;
2067 Q_EMIT markChanged(
this, temp, MarkAdded);
2069 Q_EMIT marksChanged(
this);
2074void KTextEditor::DocumentPrivate::removeMark(
int line, uint markType)
2076 if (line < 0 || line > lastLine()) {
2080 auto it = m_marks.find(line);
2081 if (it == m_marks.end()) {
2087 markType &= mark->
type;
2089 if (markType == 0) {
2094 mark->
type &= ~markType;
2099 temp.
type = markType;
2100 Q_EMIT markChanged(
this, temp, MarkRemoved);
2102 if (mark->
type == 0) {
2107 Q_EMIT marksChanged(
this);
2117void KTextEditor::DocumentPrivate::requestMarkTooltip(
int line,
QPoint position)
2124 bool handled =
false;
2125 Q_EMIT markToolTipRequested(
this, *mark, position, handled);
2130 bool handled =
false;
2135 Q_EMIT markClicked(
this, *mark, handled);
2143 bool handled =
false;
2148 Q_EMIT markContextMenuRequested(
this, *mark, position, handled);
2163 for (
const auto &m : marksCopy) {
2164 Q_EMIT markChanged(
this, *m, MarkRemoved);
2169 Q_EMIT marksChanged(
this);
2175 m_markDescriptions.insert(type, description);
2181 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
2182 return KateRendererConfig::global()->lineMarkerColor(type);
2190 return m_markDescriptions.value(type,
QString());
2193void KTextEditor::DocumentPrivate::setEditableMarks(uint markMask)
2195 m_editableMarks = markMask;
2200 return m_editableMarks;
2206 m_markIcons.insert(markType, icon);
2211 return m_markIcons.value(markType,
QIcon());
2215bool KTextEditor::DocumentPrivate::print()
2217 return KatePrinter::print(
this);
2220void KTextEditor::DocumentPrivate::printPreview()
2222 KatePrinter::printPreview(
this);
2229 if (!m_modOnHd && url().isLocalFile()) {
2237 for (
int i = 0; (i < lines()) && (buf.
size() <= 4096); ++i) {
2238 buf.
append(line(i).toUtf8());
2243 if (!url().path().isEmpty()) {
2253void KTextEditor::DocumentPrivate::showAndSetOpeningErrorAccess()
2256 i18n(
"The file %1 could not be loaded, as it was not possible to read from it.<br />Check if you have read access to this file.",
2259 message->setWordWrap(
true);
2261 i18nc(
"translators: you can also translate 'Try Again' with 'Reload'",
"Try Again"),
2266 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
2269 message->addAction(tryAgainAction);
2270 message->addAction(closeAction);
2273 postMessage(message);
2276 m_openingError =
true;
2280void KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride()
2283 const int longestLine = m_buffer->longestLineLoaded();
2284 int newLimit = pow(2, ceil(log2(longestLine)));
2285 if (newLimit <= longestLine) {
2290 config()->setLineLengthLimit(newLimit);
2295 if (!m_openingError) {
2297 m_readWriteStateBeforeLoading =
true;
2303 return config()->lineLengthLimit();
2310 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
2313 m_openingError =
false;
2319 QString currentEncoding = encoding();
2324 QString mimeType = arguments().mimeType();
2326 if (pos != -1 && !(m_reloading && m_userSetEncodingForNextReload)) {
2327 setEncoding(mimeType.
mid(pos + 1));
2338 if (m_reloading && m_userSetEncodingForNextReload && (currentEncoding != encoding())) {
2339 setEncoding(currentEncoding);
2342 bool success = m_buffer->openFile(localFilePath(), (m_reloading && m_userSetEncodingForNextReload));
2355 for (
auto view : std::as_const(m_views)) {
2358 static_cast<ViewPrivate *
>(view)->updateView(
true);
2362 Q_EMIT textChanged(
this);
2363 Q_EMIT loaded(
this);
2370 m_modOnHdReason = OnDiskUnmodified;
2371 m_prevModOnHdReason = OnDiskUnmodified;
2372 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
2377 if (!isEmpty() && config()->autoDetectIndent() && !config()->isSet(KateDocumentConfig::IndentationWidth)
2378 && !config()->isSet(KateDocumentConfig::ReplaceTabsWithSpaces)) {
2380 auto result = detecter.detect(config()->indentationWidth(), config()->replaceTabsDyn());
2381 config()->setIndentationWidth(result.indentWidth);
2382 config()->setReplaceTabsDyn(result.indentUsingSpaces);
2389 showAndSetOpeningErrorAccess();
2393 if (m_buffer->brokenEncoding()) {
2395 setReadWrite(
false);
2396 m_readWriteStateBeforeLoading =
false;
2398 i18n(
"The file %1 was opened with %2 encoding but contained invalid characters.<br />"
2399 "It is set to read-only mode, as saving might destroy its content.<br />"
2400 "Either reopen the file with the correct encoding chosen or enable the read-write mode again in the tools menu to be able to edit it.",
2402 m_buffer->textCodec()),
2404 message->setWordWrap(
true);
2405 postMessage(message);
2408 m_openingError =
true;
2412 if (m_buffer->tooLongLinesWrapped()) {
2414 setReadWrite(
false);
2415 m_readWriteStateBeforeLoading =
false;
2417 new KTextEditor::Message(
i18n(
"The file %1 was opened and contained lines longer than the configured Line Length Limit (%2 characters).<br />"
2418 "The longest of those lines was %3 characters long<br/>"
2419 "Those lines were wrapped and the document is set to read-only mode, as saving will modify its content.",
2421 config()->lineLengthLimit(),
2422 m_buffer->longestLineLoaded()),
2424 QAction *increaseAndReload =
new QAction(
i18n(
"Temporarily raise limit and reload file"), message);
2425 connect(increaseAndReload, &
QAction::triggered,
this, &KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride);
2426 message->addAction(increaseAndReload,
true);
2427 message->addAction(
new QAction(
i18n(
"Close"), message),
true);
2428 message->setWordWrap(
true);
2429 postMessage(message);
2432 m_openingError =
true;
2444 delete m_modOnHdHandler;
2447 if (!url().isEmpty()) {
2448 if (m_fileChangedDialogsActivated && m_modOnHd) {
2451 if (!isModified()) {
2454 str +
i18n(
"Do you really want to save this unmodified file? You could overwrite changed data in the file on disk."),
2455 i18n(
"Trying to Save Unmodified File"),
2465 "Do you really want to save this file? Both your open file and the file on disk were changed. There could be some data lost."),
2466 i18n(
"Possible Data Loss"),
2478 if (!m_buffer->canEncode()
2480 i18n(
"The selected encoding cannot encode every Unicode character in this document. Do you really want to save "
2481 "it? There could be some data lost."),
2482 i18n(
"Possible Data Loss"),
2490 if (!createBackupFile()) {
2495 QString oldPath = m_dirWatchFile;
2498 if (oldPath != localFilePath()) {
2501 if (url().isLocalFile()) {
2508 const bool variablesWereRead = readVariables();
2514 if (!variablesWereRead) {
2515 for (
auto *view : std::as_const(m_views)) {
2516 auto v =
static_cast<ViewPrivate *
>(view);
2517 if (v->isVisible()) {
2518 const auto range = v->visibleRange();
2520 bool repaint =
false;
2522 if (isLineModified(i)) {
2529 v->updateView(
true);
2536 deactivateDirWatch();
2541 removeTrailingSpacesAndAddNewLineAtEof();
2546 if (!m_buffer->saveFile(localFilePath())) {
2548 activateDirWatch(oldPath);
2550 i18n(
"The document could not be saved, as it was not possible to write to %1.\nCheck that you have write access to this file or "
2551 "that enough disk space is available.\nThe original file may be lost or damaged. "
2552 "Don't quit the application until the file is successfully written.",
2568 m_modOnHdReason = OnDiskUnmodified;
2569 m_prevModOnHdReason = OnDiskUnmodified;
2570 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
2575 m_undoManager->undoSafePoint();
2576 m_undoManager->updateLineModifications();
2584bool KTextEditor::DocumentPrivate::createBackupFile()
2587 const bool backupLocalFiles = config()->backupOnSaveLocal();
2588 const bool backupRemoteFiles = config()->backupOnSaveRemote();
2592 if (!backupLocalFiles && !backupRemoteFiles) {
2599 bool needBackup = backupLocalFiles && backupRemoteFiles;
2601 bool slowOrRemoteFile = !u.isLocalFile();
2602 if (!slowOrRemoteFile) {
2606 slowOrRemoteFile = (mountPoint && mountPoint->probablySlow());
2608 needBackup = (!slowOrRemoteFile && backupLocalFiles) || (slowOrRemoteFile && backupRemoteFiles);
2619 if (backupPrefix.isEmpty() && backupSuffix.isEmpty()) {
2626 u.setPath(backupPrefix + u.fileName() + backupSuffix);
2629 const QString fileName = u.fileName();
2631 u.setPath(u.path() + backupPrefix + fileName + backupSuffix);
2634 qCDebug(LOG_KTE) <<
"backup src file name: " << url();
2635 qCDebug(LOG_KTE) <<
"backup dst file name: " << u;
2638 bool backupSuccess =
false;
2641 if (u.isLocalFile()) {
2644 QFile backupFile(u.toLocalFile());
2645 if (backupFile.exists()) {
2646 backupFile.remove();
2649 backupSuccess =
QFile::copy(url().toLocalFile(), u.toLocalFile());
2651 backupSuccess =
true;
2657 if (statJob->
exec()) {
2662 backupSuccess = job->
exec();
2664 backupSuccess =
true;
2671 i18n(
"For file %1 no backup copy could be created before saving."
2672 " If an error occurs while saving, you might lose the data of this file."
2673 " A reason could be that the media you write to is full or the directory of the file is read-only for you.",
2675 i18n(
"Failed to create backup copy."),
2678 QStringLiteral(
"Backup Failed Warning"))
2686void KTextEditor::DocumentPrivate::readDirConfig()
2696 while (!seenDirectories.
contains(
dir.absolutePath())) {
2698 seenDirectories.
insert(
dir.absolutePath());
2706 QString line = stream.readLine();
2707 while ((linesRead < 32) && !line.
isNull()) {
2708 readVariableLine(line);
2710 line = stream.readLine();
2724#if EDITORCONFIG_FOUND
2728 EditorConfig editorConfig(
this);
2729 editorConfig.parse();
2733void KTextEditor::DocumentPrivate::activateDirWatch(
const QString &useFileName)
2735 QString fileToUse = useFileName;
2737 fileToUse = localFilePath();
2751 if (fileToUse == m_dirWatchFile) {
2756 deactivateDirWatch();
2759 if (url().isLocalFile() && !fileToUse.
isEmpty()) {
2761 m_dirWatchFile = fileToUse;
2765void KTextEditor::DocumentPrivate::deactivateDirWatch()
2767 if (!m_dirWatchFile.isEmpty()) {
2771 m_dirWatchFile.clear();
2774bool KTextEditor::DocumentPrivate::openUrl(
const QUrl &url)
2778 m_fileTypeSetByUser =
false;
2785bool KTextEditor::DocumentPrivate::closeUrl()
2790 if (!m_reloading && !url().isEmpty()) {
2791 if (m_fileChangedDialogsActivated && m_modOnHd) {
2793 delete m_modOnHdHandler;
2795 QWidget *parentWidget(dialogParent());
2798 +
i18n(
"Do you really want to continue to close this file? Data loss may occur."),
2799 i18n(
"Possible Data Loss"),
2802 QStringLiteral(
"kate_close_modonhd_%1").arg(m_modOnHdReason))
2805 m_reloading =
false;
2816 m_reloading =
false;
2822 Q_EMIT aboutToClose(
this);
2826 if (!m_messageHash.isEmpty()) {
2827 const auto keys = m_messageHash.keys();
2834 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
2837 deactivateDirWatch();
2848 m_modOnHdReason = OnDiskUnmodified;
2849 m_prevModOnHdReason = OnDiskUnmodified;
2850 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
2860 m_undoManager->clearUndo();
2861 m_undoManager->clearRedo();
2867 m_buffer->setHighlight(0);
2870 for (
auto view : std::as_const(m_views)) {
2871 static_cast<ViewPrivate *
>(view)->clearSelection();
2872 static_cast<ViewPrivate *
>(view)->
clear();
2877 m_swapfile->fileClosed();
2886 return m_swapfile && m_swapfile->shouldRecover();
2891 if (isDataRecoveryAvailable()) {
2892 m_swapfile->recover();
2898 if (isDataRecoveryAvailable()) {
2899 m_swapfile->discard();
2903void KTextEditor::DocumentPrivate::setReadWrite(
bool rw)
2905 if (isReadWrite() == rw) {
2911 for (
auto v : std::as_const(m_views)) {
2912 auto view =
static_cast<ViewPrivate *
>(v);
2913 view->slotUpdateUndo();
2914 view->slotReadWriteChanged();
2917 Q_EMIT readWriteChanged(
this);
2922 if (isModified() != m) {
2925 for (
auto view : std::as_const(m_views)) {
2926 static_cast<ViewPrivate *
>(view)->slotUpdateUndo();
2929 Q_EMIT modifiedChanged(
this);
2932 m_undoManager->setModified(m);
2938void KTextEditor::DocumentPrivate::makeAttribs(
bool needInvalidate)
2940 for (
auto view : std::as_const(m_views)) {
2941 static_cast<ViewPrivate *
>(view)->renderer()->updateAttributes();
2944 if (needInvalidate) {
2945 m_buffer->invalidateHighlighting();
2948 for (
auto v : std::as_const(m_views)) {
2949 auto view =
static_cast<ViewPrivate *
>(v);
2951 view->updateView(
true);
2956void KTextEditor::DocumentPrivate::internalHlChanged()
2963 Q_ASSERT(!m_views.contains(view));
2964 m_views.append(view);
2967 if (!m_fileType.isEmpty()) {
2972 readVariables(
true);
2974 setActiveView(view);
2979 Q_ASSERT(m_views.contains(view));
2980 m_views.removeAll(view);
2982 if (activeView() == view) {
2983 setActiveView(
nullptr);
2989 if (m_activeView == view) {
2993 m_activeView =
static_cast<KTextEditor::ViewPrivate *
>(view);
2996bool KTextEditor::DocumentPrivate::ownedView(KTextEditor::ViewPrivate *view)
2999 return (m_views.contains(view));
3002int KTextEditor::DocumentPrivate::toVirtualColumn(
int line,
int column)
const
3010 return toVirtualColumn(cursor.
line(), cursor.
column());
3013int KTextEditor::DocumentPrivate::fromVirtualColumn(
int line,
int column)
const
3019int KTextEditor::DocumentPrivate::fromVirtualColumn(
const KTextEditor::Cursor cursor)
const
3021 return fromVirtualColumn(cursor.
line(), cursor.
column());
3030 bool skipAutobrace = closingBracket ==
QLatin1Char(
'\'');
3031 if (highlight() && skipAutobrace) {
3033 skipAutobrace = highlight()->spellCheckingRequiredForLocation(
this, pos - Cursor{0, 1});
3036 if (!skipAutobrace && (closingBracket ==
QLatin1Char(
'\''))) {
3042 skipAutobrace = (count % 2 == 0) ?
true : false;
3044 if (!skipAutobrace && (closingBracket ==
QLatin1Char(
'\"'))) {
3049 skipAutobrace = (count % 2 == 0) ?
true : false;
3051 return skipAutobrace;
3062 QChar closingBracket;
3063 if (view->config()->autoBrackets()) {
3065 const QChar typedChar = chars.
at(0);
3066 const QChar openBracket = matchingStartBracket(typedChar);
3067 if (!openBracket.
isNull()) {
3069 if ((characterAt(curPos) == typedChar) && findMatchingBracket(curPos, 123 ).isValid()) {
3071 view->cursorRight();
3077 if (chars.
size() == 1) {
3079 closingBracket = matchingEndBracket(typedChar);
3082 if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) {
3084 m_currentAutobraceRange.reset(
nullptr);
3085 view->cursorRight();
3092 if (view->selection() && closingBracket.
isNull() && view->config()->encloseSelectionInChars()) {
3093 const QChar typedChar = chars.
at(0);
3094 if (view->config()->charsToEncloseSelection().
contains(typedChar)) {
3103 if (view->selection() && !closingBracket.
isNull()) {
3104 std::unique_ptr<KTextEditor::MovingRange> selectionRange(newMovingRange(view->selectionRange()));
3105 const int startLine = qMax(0, selectionRange->start().line());
3106 const int endLine = qMin(selectionRange->end().line(), lastLine());
3107 const bool blockMode = view->blockSelection() && (startLine != endLine);
3109 if (selectionRange->start().column() > selectionRange->end().column()) {
3115 const int startColumn = qMin(selectionRange->start().column(), selectionRange->end().column());
3116 const int endColumn = qMax(selectionRange->start().column(), selectionRange->end().column());
3118 for (
int line = startLine; line <= endLine; ++line) {
3120 insertText(r.
end(),
QString(closingBracket));
3121 view->slotTextInserted(view, r.
end(),
QString(closingBracket));
3122 insertText(r.
start(), chars);
3123 view->slotTextInserted(view, r.
start(), chars);
3127 for (
const auto &cursor : view->secondaryCursors()) {
3128 if (!cursor.range) {
3131 const auto &currSelectionRange = cursor.range;
3132 auto expandBehaviour = currSelectionRange->insertBehaviors();
3134 insertText(currSelectionRange->end(),
QString(closingBracket));
3135 insertText(currSelectionRange->start(), chars);
3136 currSelectionRange->setInsertBehaviors(expandBehaviour);
3137 cursor.pos->setPosition(currSelectionRange->end());
3138 auto mutableCursor =
const_cast<KTextEditor::ViewPrivate::SecondaryCursor *
>(&cursor);
3139 mutableCursor->anchor = currSelectionRange->start().toCursor();
3143 insertText(selectionRange->end(),
QString(closingBracket));
3144 view->slotTextInserted(view, selectionRange->end(),
QString(closingBracket));
3145 insertText(selectionRange->start(), chars);
3146 view->slotTextInserted(view, selectionRange->start(), chars);
3150 view->setSelection(selectionRange->toRange());
3151 view->setCursorPosition(selectionRange->end());
3158 if (!view->config()->persistentSelection() && view->selection()) {
3159 view->removeSelectedText();
3164 const bool multiLineBlockMode = view->blockSelection() && view->selection();
3165 if (view->currentInputMode()->overwrite()) {
3168 const int startLine = multiLineBlockMode ? qMax(0, selectionRange.
start().
line()) : view->cursorPosition().
line();
3169 const int endLine = multiLineBlockMode ? qMin(selectionRange.
end().
line(), lastLine()) : startLine;
3170 const int virtualColumn = toVirtualColumn(multiLineBlockMode ? selectionRange.
end() : view->cursorPosition());
3172 for (
int line = endLine; line >= startLine; --line) {
3174 const int column = fromVirtualColumn(line, virtualColumn);
3178 if (oldCur.
column() < lineLength(line)) {
3180 view->currentInputMode()->overwrittenChar(removed);
3187 chars = eventuallyReplaceTabs(view->cursorPosition(), chars);
3189 if (multiLineBlockMode) {
3191 const int startLine = qMax(0, selectionRange.
start().
line());
3192 const int endLine = qMin(selectionRange.
end().
line(), lastLine());
3193 const int column = toVirtualColumn(selectionRange.
end());
3194 for (
int line = endLine; line >= startLine; --line) {
3195 editInsertText(line, fromVirtualColumn(line, column), chars);
3197 int newSelectionColumn = toVirtualColumn(view->cursorPosition());
3200 view->setSelection(selectionRange);
3205 view->completionWidget()->setIgnoreBufferSignals(
true);
3206 const auto &sc = view->secondaryCursors();
3207 const bool hasClosingBracket = !closingBracket.
isNull();
3208 const QString closingChar = closingBracket;
3209 for (
const auto &c : sc) {
3210 insertText(c.cursor(), chars);
3211 const auto pos = c.cursor();
3212 const auto nextChar = view->document()->
text({pos, pos +
Cursor{0, 1}}).trimmed();
3213 if (hasClosingBracket && !skipAutoBrace(closingBracket, pos) && (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber())) {
3214 insertText(c.cursor(), closingChar);
3215 c.pos->setPosition(pos);
3218 view->completionWidget()->setIgnoreBufferSignals(
false);
3220 insertText(view->cursorPosition(), chars);
3227 if (!closingBracket.
isNull() && !skipAutoBrace(closingBracket, view->cursorPosition())) {
3229 const auto cursorPos = view->cursorPosition();
3230 const auto nextChar = view->document()->
text({cursorPos, cursorPos +
Cursor{0, 1}}).trimmed();
3231 if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) {
3232 insertText(view->cursorPosition(),
QString(closingBracket));
3233 const auto insertedAt(view->cursorPosition());
3234 view->setCursorPosition(cursorPos);
3239 chars.
append(closingBracket);
3241 m_currentAutobraceClosingChar = closingBracket;
3248 const auto &secondaryCursors = view->secondaryCursors();
3249 for (
const auto &c : secondaryCursors) {
3250 m_indenter->userTypedChar(view, c.cursor(), chars.
isEmpty() ?
QChar() : chars.
at(chars.
length() - 1));
3258 view->slotTextInserted(view, oldCur, chars);
3263 if (m_currentAutobraceRange && !m_currentAutobraceRange->toRange().contains(newPos)) {
3264 m_currentAutobraceRange.reset();
3268void KTextEditor::DocumentPrivate::newLine(KTextEditor::ViewPrivate *v, KTextEditor::DocumentPrivate::NewLineIndent indent, NewLinePos newLinePos)
3272 if (!v->config()->persistentSelection() && v->selection()) {
3273 v->removeSelectedText();
3274 v->clearSelection();
3278 if (c.line() > lastLine()) {
3279 c.setLine(lastLine());
3288 int len = lineLength(ln);
3290 if (c.column() > len) {
3295 editWrapLine(c.line(), c.column());
3298 m_buffer->updateHighlighting();
3305 bool moveCursorToTop =
false;
3306 if (newLinePos == Above) {
3307 if (pos.
line() <= 0) {
3310 moveCursorToTop =
true;
3315 }
else if (newLinePos == Below) {
3316 int lastCol = lineLength(pos.
line());
3319 return std::pair{pos, moveCursorToTop};
3323 const auto &secondaryCursors = v->secondaryCursors();
3324 if (!secondaryCursors.empty()) {
3327 for (
const auto &c : secondaryCursors) {
3328 const auto [newPos, moveCursorToTop] = adjustCusorPos(c.cursor());
3329 c.pos->setPosition(newPos);
3330 insertNewLine(c.cursor());
3331 if (moveCursorToTop) {
3332 c.pos->setPosition({0, 0});
3335 if (indent == KTextEditor::DocumentPrivate::Indent) {
3339 v->setCursorPosition(c.cursor());
3340 m_indenter->userTypedChar(v, c.cursor(),
QLatin1Char(
'\n'));
3342 c.pos->setPosition(v->cursorPosition());
3346 v->setCursorPosition(savedPrimary.toCursor());
3349 const auto [newPos, moveCursorToTop] = adjustCusorPos(v->cursorPosition());
3350 v->setCursorPosition(newPos);
3351 insertNewLine(v->cursorPosition());
3352 if (moveCursorToTop) {
3353 v->setCursorPosition({0, 0});
3356 if (indent == KTextEditor::DocumentPrivate::Indent) {
3357 m_indenter->userTypedChar(v, v->cursorPosition(),
QLatin1Char(
'\n'));
3366 if (textLine.
length() < 2) {
3370 uint col = cursor.
column();
3376 if ((textLine.
length() - col) < 2) {
3380 uint line = cursor.
line();
3391 editRemoveText(line, col, 2);
3392 editInsertText(line, col, s);
3399 Q_ASSERT(!firstWord.
overlaps(secondWord));
3407 const QString tempString = text(secondWord);
3410 replaceText(secondWord, text(firstWord));
3411 replaceText(firstWord, tempString);
3417 int col = qMax(c.
column(), 0);
3418 int line = qMax(c.
line(), 0);
3419 if ((col == 0) && (line == 0)) {
3422 if (line >= lines()) {
3429 bool useNextBlock =
false;
3430 if (config()->backspaceIndents()) {
3437 if (pos < 0 || pos >= (
int)colX) {
3439 if ((
int)col > textLine.
length()) {
3445 useNextBlock =
true;
3448 if (!config()->backspaceIndents() || useNextBlock) {
3451 if (!view->config()->backspaceRemoveComposed()) {
3452 beginCursor.setColumn(col - 1);
3454 if (!isValidTextPosition(beginCursor)) {
3456 beginCursor.setColumn(col - 2);
3459 if (
auto l = view->textLayout(c)) {
3460 beginCursor.setColumn(l->previousCursorPosition(c.
column()));
3475 if (config()->wordWrap() && textLine.
endsWith(QStringLiteral(
" "))) {
3488void KTextEditor::DocumentPrivate::backspace(KTextEditor::ViewPrivate *view)
3490 if (!view->config()->persistentSelection() && view->hasSelections()) {
3494 if (view->blockSelection() && view->selection() && range.
start().
column() > 0 && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3497 view->setSelection(range);
3499 view->removeSelectedText();
3500 view->ensureUniqueCursors();
3508 const auto &multiCursors = view->secondaryCursors();
3509 view->completionWidget()->setIgnoreBufferSignals(
true);
3510 for (
const auto &c : multiCursors) {
3511 const auto newPos = backspaceAtCursor(view, c.cursor());
3516 view->completionWidget()->setIgnoreBufferSignals(
false);
3519 auto newPos = backspaceAtCursor(view, view->cursorPosition());
3521 view->setCursorPosition(newPos);
3524 view->ensureUniqueCursors();
3529 if (m_currentAutobraceRange) {
3530 const auto r = m_currentAutobraceRange->toRange();
3531 if (r.columnWidth() == 1 && view->cursorPosition() == r.
start()) {
3533 del(view, view->cursorPosition());
3534 m_currentAutobraceRange.reset();
3539void KTextEditor::DocumentPrivate::del(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor c)
3541 if (!view->config()->persistentSelection() && view->selection()) {
3544 if (view->blockSelection() && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3547 view->setSelection(range);
3549 view->removeSelectedText();
3554 if (c.
column() < m_buffer->lineLength(c.
line())) {
3557 }
else if (c.
line() < lastLine()) {
3562bool KTextEditor::DocumentPrivate::multiPaste(KTextEditor::ViewPrivate *view,
const QStringList &texts)
3564 if (texts.
isEmpty() || view->isMulticursorNotAllowed() || view->secondaryCursors().size() + 1 != (
size_t)texts.
size()) {
3568 m_undoManager->undoSafePoint();
3571 if (view->selection()) {
3572 view->removeSelectedText();
3575 auto plainSecondaryCursors = view->plainSecondaryCursors();
3576 KTextEditor::ViewPrivate::PlainSecondaryCursor primary;
3577 primary.pos = view->cursorPosition();
3578 primary.range = view->selectionRange();
3579 plainSecondaryCursors.append(primary);
3580 std::sort(plainSecondaryCursors.begin(), plainSecondaryCursors.end());
3584 for (
int i = texts.
size() - 1; i >= 0; --i) {
3586 text.
replace(re, QStringLiteral(
"\n"));
3589 insertText(pos, text,
false);
3597void KTextEditor::DocumentPrivate::paste(KTextEditor::ViewPrivate *view,
const QString &text)
3610 const bool isSingleLine = lines == 0;
3612 m_undoManager->undoSafePoint();
3618 bool skipIndentOnPaste =
false;
3620 const int length = lineLength(pos.
line());
3622 skipIndentOnPaste = length > 0;
3625 if (!view->config()->persistentSelection() && view->selection()) {
3626 pos = view->selectionRange().
start();
3627 if (view->blockSelection()) {
3628 pos = rangeOnLine(view->selectionRange(), pos.
line()).
start();
3635 view->removeSelectedText();
3638 if (config()->ovr()) {
3641 if (!view->blockSelection()) {
3642 int endColumn = (pasteLines.count() == 1 ? pos.
column() : 0) + pasteLines.last().length();
3645 int maxi = qMin(pos.
line() + pasteLines.count(), this->lines());
3647 for (
int i = pos.
line(); i < maxi; ++i) {
3648 int pasteLength = pasteLines.at(i - pos.
line()).length();
3654 insertText(pos, s, view->blockSelection());
3661 if (view->blockSelection()) {
3662 view->setCursorPositionInternal(pos);
3665 if (config()->indentPastedText()) {
3667 if (!skipIndentOnPaste) {
3668 m_indenter->indent(view, range);
3672 if (!view->blockSelection()) {
3673 Q_EMIT charactersSemiInteractivelyInserted(pos, s);
3675 m_undoManager->undoSafePoint();
3680 if (!isReadWrite()) {
3685 m_indenter->changeIndent(range, change);
3689void KTextEditor::DocumentPrivate::align(KTextEditor::ViewPrivate *view,
KTextEditor::Range range)
3691 m_indenter->indent(view, range);
3698 if (lines.
size() < 2) {
3704 int selectionStartColumn = range.
start().
column();
3706 for (
const auto &line : lines) {
3708 if (!
match.hasMatch()) {
3709 patternStartColumns.
append(-1);
3710 }
else if (
match.lastCapturedIndex() == 0) {
3711 patternStartColumns.
append(
match.capturedStart(0) + (blockwise ? selectionStartColumn : 0));
3713 patternStartColumns.
append(
match.capturedStart(1) + (blockwise ? selectionStartColumn : 0));
3716 if (!blockwise && patternStartColumns[0] != -1) {
3717 patternStartColumns[0] += selectionStartColumn;
3720 int maxColumn = *std::max_element(patternStartColumns.
cbegin(), patternStartColumns.
cend());
3723 for (
int i = 0; i < lines.
size(); ++i) {
3724 if (patternStartColumns[i] != -1) {
3731void KTextEditor::DocumentPrivate::insertTab(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor)
3733 if (!isReadWrite()) {
3737 int lineLen = line(view->cursorPosition().
line()).length();
3742 if (!view->config()->persistentSelection() && view->selection()) {
3743 view->removeSelectedText();
3744 }
else if (view->currentInputMode()->overwrite() && c.
column() < lineLen) {
3749 view->currentInputMode()->overwrittenChar(removed);
3753 c = view->cursorPosition();
3754 editInsertText(c.
line(), c.
column(), QStringLiteral(
"\t"));
3763bool KTextEditor::DocumentPrivate::removeStringFromBeginning(
int line,
const QString &str)
3787bool KTextEditor::DocumentPrivate::removeStringFromEnd(
int line,
const QString &str)
3792 bool there = textline.
endsWith(str);
3814 const bool replacetabs = config()->replaceTabsDyn();
3818 const int indentWidth = config()->indentationWidth();
3821 int column = cursorPos.
column();
3827 for (
const QChar ch : str) {
3828 if (ch == tabChar) {
3831 int spacesToInsert = indentWidth - (column % indentWidth);
3833 column += spacesToInsert;
3846void KTextEditor::DocumentPrivate::addStartLineCommentToSingleLine(
int line,
int attrib)
3848 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) +
QLatin1Char(
' ');
3851 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3862bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSingleLine(
int line,
int attrib)
3864 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
3870 bool removed = (removeStringFromBeginning(line, longCommentMark) || removeStringFromBeginning(line, shortCommentMark));
3881void KTextEditor::DocumentPrivate::addStartStopCommentToSingleLine(
int line,
int attrib)
3883 const QString startCommentMark = highlight()->getCommentStart(attrib) +
QLatin1Char(
' ');
3884 const QString stopCommentMark =
QLatin1Char(
' ') + highlight()->getCommentEnd(attrib);
3892 const int col = m_buffer->lineLength(line);
3904bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSingleLine(
int line,
int attrib)
3906 const QString shortStartCommentMark = highlight()->getCommentStart(attrib);
3908 const QString shortStopCommentMark = highlight()->getCommentEnd(attrib);
3914 const bool removedStart = (removeStringFromBeginning(line, longStartCommentMark) || removeStringFromBeginning(line, shortStartCommentMark));
3917 const bool removedStop = removedStart && (removeStringFromEnd(line, longStopCommentMark) || removeStringFromEnd(line, shortStopCommentMark));
3921 return (removedStart || removedStop);
3928void KTextEditor::DocumentPrivate::addStartStopCommentToSelection(
KTextEditor::Range selection,
bool blockSelection,
int attrib)
3930 const QString startComment = highlight()->getCommentStart(attrib);
3931 const QString endComment = highlight()->getCommentEnd(attrib);
3941 if (!blockSelection) {
3942 insertText(range.
end(), endComment);
3943 insertText(range.
start(), startComment);
3945 for (
int line = range.
start().
line(); line <= range.
end().
line(); line++) {
3947 insertText(subRange.
end(), endComment);
3948 insertText(subRange.
start(), startComment);
3959void KTextEditor::DocumentPrivate::addStartLineCommentToSelection(
KTextEditor::Range selection,
int attrib)
3962 int el = selection.
end().
line();
3965 if ((selection.
end().
column() == 0) && (el > 0)) {
3969 if (sl < 0 || el < 0 || sl >= lines() || el >= lines()) {
3975 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) +
QLatin1Char(
' ');
3978 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3986 col = std::numeric_limits<int>::max();
3988 for (
int l = el; l >= sl; l--) {
3989 const auto line = plainKateTextLine(l);
3990 if (line.length() == 0) {
3993 col = qMin(col, qMax(0, line.firstChar()));
4000 if (col == std::numeric_limits<int>::max()) {
4007 for (
int l = el; l >= sl; l--) {
4014bool KTextEditor::DocumentPrivate::nextNonSpaceCharPos(
int &line,
int &col)
4016 for (; line >= 0 && line < m_buffer->lines(); line++) {
4030bool KTextEditor::DocumentPrivate::previousNonSpaceCharPos(
int &line,
int &col)
4032 while (line >= 0 && line < m_buffer->lines()) {
4054bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSelection(
KTextEditor::Range selection,
int attrib)
4056 const QString startComment = highlight()->getCommentStart(attrib);
4057 const QString endComment = highlight()->getCommentEnd(attrib);
4059 int sl = qMax<int>(0, selection.
start().
line());
4060 int el = qMin<int>(selection.
end().
line(), lastLine());
4067 }
else if (el > 0) {
4069 ec = m_buffer->lineLength(el) - 1;
4072 const int startCommentLen = startComment.
length();
4073 const int endCommentLen = endComment.
length();
4077 bool remove = nextNonSpaceCharPos(sl, sc) && m_buffer->plainLine(sl).matchesAt(sc, startComment) && previousNonSpaceCharPos(el, ec)
4078 && ((ec - endCommentLen + 1) >= 0) && m_buffer->plainLine(el).matchesAt(ec - endCommentLen + 1, endComment);
4095 const QString startComment = highlight()->getCommentStart(attrib);
4096 const QString endComment = highlight()->getCommentEnd(attrib);
4097 const int startCommentLen = startComment.
length();
4098 const int endCommentLen = endComment.
length();
4100 const bool remove = m_buffer->plainLine(
start.line()).matchesAt(
start.column(), startComment)
4101 && m_buffer->plainLine(
end.line()).matchesAt(
end.column() - endCommentLen, endComment);
4115bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSelection(
KTextEditor::Range selection,
int attrib,
bool toggleComment)
4117 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
4120 const int startLine = selection.
start().
line();
4121 int endLine = selection.
end().
line();
4123 if ((selection.
end().
column() == 0) && (endLine > 0)) {
4127 bool removed =
false;
4133 if (toggleComment) {
4134 bool allLinesAreCommented =
true;
4135 for (
int line = endLine; line >= startLine; line--) {
4136 const auto ln = m_buffer->plainLine(line);
4137 const QString &text = ln.text();
4144 textView = textView.trimmed();
4145 if (!textView.startsWith(shortCommentMark) && !textView.startsWith(longCommentMark)) {
4146 allLinesAreCommented =
false;
4150 if (!allLinesAreCommented) {
4158 for (
int z = endLine; z >= startLine; z--) {
4160 removed = (removeStringFromBeginning(z, longCommentMark) || removeStringFromBeginning(z, shortCommentMark) || removed);
4171 const bool hasSelection = !selection.
isEmpty();
4172 int selectionCol = 0;
4177 const int line = c.
line();
4179 int startAttrib = 0;
4182 if (selectionCol < ln.
length()) {
4183 startAttrib = ln.
attribute(selectionCol);
4188 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart(startAttrib).isEmpty());
4189 bool hasStartStopCommentMark = (!(highlight()->getCommentStart(startAttrib).isEmpty()) && !(highlight()->getCommentEnd(startAttrib).isEmpty()));
4191 if (changeType == Comment) {
4192 if (!hasSelection) {
4193 if (hasStartLineCommentMark) {
4194 addStartLineCommentToSingleLine(line, startAttrib);
4195 }
else if (hasStartStopCommentMark) {
4196 addStartStopCommentToSingleLine(line, startAttrib);
4207 if (hasStartStopCommentMark
4208 && (!hasStartLineCommentMark
4211 addStartStopCommentToSelection(selection, blockSelect, startAttrib);
4212 }
else if (hasStartLineCommentMark) {
4213 addStartLineCommentToSelection(selection, startAttrib);
4217 bool removed =
false;
4218 const bool toggleComment = changeType == ToggleComment;
4219 if (!hasSelection) {
4220 removed = (hasStartLineCommentMark && removeStartLineCommentFromSingleLine(line, startAttrib))
4221 || (hasStartStopCommentMark && removeStartStopCommentFromSingleLine(line, startAttrib));
4224 removed = (hasStartStopCommentMark && removeStartStopCommentFromSelection(selection, startAttrib))
4225 || (hasStartLineCommentMark && removeStartLineCommentFromSelection(selection, startAttrib, toggleComment));
4229 if (!removed && toggleComment) {
4230 commentSelection(selection, c, blockSelect, Comment);
4239void KTextEditor::DocumentPrivate::comment(KTextEditor::ViewPrivate *v, uint line, uint column, CommentType change)
4242 const bool skipWordWrap = wordWrap();
4249 if (v->selection()) {
4250 const auto &cursors = v->secondaryCursors();
4251 for (
const auto &c : cursors) {
4255 commentSelection(c.range->toRange(), c.cursor(),
false, change);
4258 commentSelection(v->selectionRange(), c, v->blockSelection(), change);
4260 const auto &cursors = v->secondaryCursors();
4261 for (
const auto &c : cursors) {
4262 commentSelection({}, c.cursor(),
false, change);
4274void KTextEditor::DocumentPrivate::transformCursorOrRange(KTextEditor::ViewPrivate *v,
4277 KTextEditor::DocumentPrivate::TextTransform t)
4279 if (v->selection()) {
4291 if (range.
start().
line() == selection.
end().
line() || v->blockSelection()) {
4296 int swapCol =
start;
4306 if (t == Uppercase) {
4309 }
else if (t == Lowercase) {
4322 && !highlight()->isInWord(l.
at(range.
start().
column() - 1)))
4323 || (p && !highlight()->isInWord(s.
at(p - 1)))) {
4332 insertText(range.
start(), s);
4367 insertText(cursor, s);
4377 if (v->selection()) {
4378 const auto &cursors = v->secondaryCursors();
4379 for (
const auto &c : cursors) {
4383 auto pos = c.pos->toCursor();
4384 transformCursorOrRange(v, c.anchor, c.range->toRange(), t);
4388 const auto selRange = v->selectionRange();
4389 transformCursorOrRange(v, c, v->selectionRange(), t);
4390 v->setSelection(selRange);
4391 v->setCursorPosition(c);
4393 const auto &secondaryCursors = v->secondaryCursors();
4394 for (
const auto &c : secondaryCursors) {
4395 transformCursorOrRange(v, c.cursor(), {}, t);
4397 transformCursorOrRange(v, c, {}, t);
4408 while (first < last) {
4409 if (line >= lines() || line + 1 >= lines()) {
4425 editRemoveText(line + 1, 0, pos);
4428 editInsertText(line + 1, 0, QStringLiteral(
" "));
4432 editRemoveText(line + 1, 0, tl.
length());
4435 editUnWrapLine(line);
4443 for (
auto view : std::as_const(m_views)) {
4444 static_cast<ViewPrivate *
>(view)->tagLines(lineRange,
true);
4448void KTextEditor::DocumentPrivate::tagLine(
int line)
4450 tagLines({line, line});
4453void KTextEditor::DocumentPrivate::repaintViews(
bool paintOnlyDirty)
4455 for (
auto view : std::as_const(m_views)) {
4456 static_cast<ViewPrivate *
>(view)->repaintText(paintOnlyDirty);
4469 if (maxLines < 0 ||
start.line() < 0 ||
start.line() >= lines()) {
4479 if (config()->ovr()) {
4480 if (isBracket(right)) {
4485 }
else if (isBracket(right)) {
4487 }
else if (isBracket(left)) {
4494 const QChar opposite = matchingBracket(bracket);
4499 const int searchDir = isStartBracket(bracket) ? 1 : -1;
4502 const int minLine = qMax(range.
start().
line() - maxLines, 0);
4503 const int maxLine = qMin(range.
start().
line() + maxLines, documentEnd().line());
4508 int validAttr = kateTextLine(cursor.
line()).attribute(cursor.
column());
4510 while (cursor.
line() >= minLine && cursor.
line() <= maxLine) {
4511 if (!cursor.move(searchDir)) {
4519 if (c == opposite) {
4521 if (searchDir > 0) {
4522 range.
setEnd(cursor.toCursor());
4529 }
else if (c == bracket) {
4545void KTextEditor::DocumentPrivate::updateDocName()
4548 if (!url().isEmpty() && (m_docName == removeNewLines(url().fileName()) || m_docName.
startsWith(removeNewLines(url().fileName()) +
QLatin1String(
" (")))) {
4554 std::vector<KTextEditor::DocumentPrivate *> docsWithSameName;
4559 if ((doc !=
this) && (doc->url().fileName() == url().
fileName())) {
4560 if (doc->m_docNameNumber > count) {
4561 count = doc->m_docNameNumber;
4563 docsWithSameName.push_back(doc);
4567 m_docNameNumber = count + 1;
4570 m_docName = removeNewLines(url().fileName());
4572 m_isUntitled = m_docName.isEmpty();
4574 if (!m_isUntitled && !docsWithSameName.empty()) {
4575 docsWithSameName.push_back(
this);
4576 uniquifyDocNames(docsWithSameName);
4581 m_docName =
i18n(
"Untitled");
4584 if (m_docNameNumber > 0) {
4589 if (oldName != m_docName) {
4590 Q_EMIT documentNameChanged(
this);
4608 int lastSlash = url.lastIndexOf(
QLatin1Char(
'/'));
4609 if (lastSlash == -1) {
4613 int fileNameStart = lastSlash;
4616 lastSlash = url.lastIndexOf(
QLatin1Char(
'/'), lastSlash);
4617 if (lastSlash == -1) {
4620 return url.mid(lastSlash, fileNameStart);
4625 urlv = urlv.
mid(lastSlash);
4627 for (
size_t i = 0; i < urls.size(); ++i) {
4628 if (urls[i] == url) {
4632 if (urls[i].endsWith(urlv)) {
4633 lastSlash = url.lastIndexOf(
QLatin1Char(
'/'), lastSlash - 1);
4634 if (lastSlash <= 0) {
4636 return url.mid(0, fileNameStart);
4639 urlv = urlView.
mid(lastSlash);
4644 return url.mid(lastSlash + 1, fileNameStart - (lastSlash + 1));
4647void KTextEditor::DocumentPrivate::uniquifyDocNames(
const std::vector<KTextEditor::DocumentPrivate *> &docs)
4649 std::vector<QString> paths;
4650 paths.reserve(docs.size());
4652 return d->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
4655 for (
const auto doc : docs) {
4656 const QString prefix = shortestPrefix(paths, doc);
4658 const QString oldName = doc->m_docName;
4661 doc->m_docName = fileName + QStringLiteral(
" - ") + prefix;
4663 doc->m_docName = fileName;
4666 if (doc->m_docName != oldName) {
4674 if (url().isEmpty() || !m_modOnHd) {
4678 if (!isModified() && isAutoReload()) {
4679 onModOnHdAutoReload();
4683 if (!m_fileChangedDialogsActivated || m_modOnHdHandler) {
4688 if (m_modOnHdReason == m_prevModOnHdReason) {
4691 m_prevModOnHdReason = m_modOnHdReason;
4693 m_modOnHdHandler =
new KateModOnHdPrompt(
this, m_modOnHdReason, reasonedMOHString());
4694 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::saveAsTriggered,
this, &DocumentPrivate::onModOnHdSaveAs);
4695 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::closeTriggered,
this, &DocumentPrivate::onModOnHdClose);
4696 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::reloadTriggered,
this, &DocumentPrivate::onModOnHdReload);
4697 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::autoReloadTriggered,
this, &DocumentPrivate::onModOnHdAutoReload);
4698 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::ignoreTriggered,
this, &DocumentPrivate::onModOnHdIgnore);
4701void KTextEditor::DocumentPrivate::onModOnHdSaveAs()
4704 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
4710 delete m_modOnHdHandler;
4711 m_prevModOnHdReason = OnDiskUnmodified;
4712 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4719void KTextEditor::DocumentPrivate::onModOnHdClose()
4722 m_fileChangedDialogsActivated =
false;
4735void KTextEditor::DocumentPrivate::onModOnHdReload()
4738 m_prevModOnHdReason = OnDiskUnmodified;
4739 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4745 m_undoManager->clearUndo();
4746 m_undoManager->clearRedo();
4749 delete m_modOnHdHandler;
4752void KTextEditor::DocumentPrivate::autoReloadToggled(
bool b)
4754 m_autoReloadMode->setChecked(b);
4758 disconnect(&m_modOnHdTimer, &
QTimer::timeout,
this, &DocumentPrivate::onModOnHdAutoReload);
4762bool KTextEditor::DocumentPrivate::isAutoReload()
4764 return m_autoReloadMode->isChecked();
4767void KTextEditor::DocumentPrivate::delayAutoReload()
4769 if (isAutoReload()) {
4770 m_autoReloadThrottle.start();
4774void KTextEditor::DocumentPrivate::onModOnHdAutoReload()
4776 if (m_modOnHdHandler) {
4777 delete m_modOnHdHandler;
4778 autoReloadToggled(
true);
4781 if (!isAutoReload()) {
4785 if (m_modOnHd && !m_reloading && !m_autoReloadThrottle.isActive()) {
4787 m_prevModOnHdReason = OnDiskUnmodified;
4788 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4792 m_undoManager->clearUndo();
4793 m_undoManager->clearRedo();
4796 m_autoReloadThrottle.start();
4800void KTextEditor::DocumentPrivate::onModOnHdIgnore()
4803 delete m_modOnHdHandler;
4808 m_modOnHdReason = reason;
4809 m_modOnHd = (reason != OnDiskUnmodified);
4810 Q_EMIT modifiedOnDisk(
this, (reason != OnDiskUnmodified), reason);
4813class KateDocumentTmpMark
4822 m_fileChangedDialogsActivated = on;
4827 if (url().isEmpty()) {
4839 m_undoManager->clearUndo();
4840 m_undoManager->clearRedo();
4845 delete m_modOnHdHandler;
4847 Q_EMIT aboutToReload(
this);
4851 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(tmp), [
this](
KTextEditor::Mark *mark) {
4852 return KateDocumentTmpMark{.line=line(mark->line), .mark=*mark};
4856 const QString oldMode = mode();
4857 const bool modeByUser = m_fileTypeSetByUser;
4858 const QString oldHlMode = highlightingMode();
4859 const bool hlByUser = m_hlSetByUser;
4861 m_storedVariables.clear();
4865 std::transform(m_views.cbegin(), m_views.cend(), std::back_inserter(cursorPositions), [](
KTextEditor::View *v) {
4866 return std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor>(static_cast<ViewPrivate *>(v), v->cursorPosition());
4871 for (
auto *view : m_views) {
4872 static_cast<ViewPrivate *
>(view)->clearSecondaryCursors();
4875 static_cast<ViewPrivate *
>(view)->clearFoldingState();
4880 KTextEditor::DocumentPrivate::openUrl(url());
4883 m_userSetEncodingForNextReload =
false;
4886 for (
auto v : std::as_const(m_views)) {
4888 auto it = std::find_if(cursorPositions.
cbegin(), cursorPositions.
cend(), [v](
const std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor> &p) {
4889 return p.first == v;
4891 v->setCursorPosition(it->second);
4897 const int lines = this->lines();
4898 for (
const auto &tmpMark : tmp) {
4899 if (tmpMark.mark.line < lines) {
4900 if (tmpMark.line == line(tmpMark.mark.line)) {
4901 setMark(tmpMark.mark.line, tmpMark.mark.type);
4908 updateFileType(oldMode,
true);
4911 setHighlightingMode(oldHlMode);
4914 Q_EMIT reloaded(
this);
4919bool KTextEditor::DocumentPrivate::documentSave()
4921 if (!url().
isValid() || !isReadWrite()) {
4922 return documentSaveAs();
4928bool KTextEditor::DocumentPrivate::documentSaveAs()
4930 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4938bool KTextEditor::DocumentPrivate::documentSaveAsWithEncoding(
const QString &encoding)
4940 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4945 setEncoding(encoding);
4949void KTextEditor::DocumentPrivate::documentSaveCopyAs()
4951 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save Copy of File"));
4957 if (!file->
open()) {
4961 if (!m_buffer->saveFile(file->
fileName())) {
4963 i18n(
"The document could not be saved, as it was not possible to write to %1.\n\nCheck that you have write access to this file or "
4964 "that enough disk space is available.",
4972 const auto url = this->url();
4974 if (
auto sj = qobject_cast<KIO::StatJob *>(j)) {
4985void KTextEditor::DocumentPrivate::setWordWrap(
bool on)
4987 config()->setWordWrap(on);
4990bool KTextEditor::DocumentPrivate::wordWrap()
const
4992 return config()->wordWrap();
4995void KTextEditor::DocumentPrivate::setWordWrapAt(uint col)
4997 config()->setWordWrapAt(col);
5000unsigned int KTextEditor::DocumentPrivate::wordWrapAt()
const
5002 return config()->wordWrapAt();
5005void KTextEditor::DocumentPrivate::setPageUpDownMovesCursor(
bool on)
5007 config()->setPageUpDownMovesCursor(on);
5010bool KTextEditor::DocumentPrivate::pageUpDownMovesCursor()
const
5012 return config()->pageUpDownMovesCursor();
5018 return m_config->setEncoding(e);
5023 return m_config->encoding();
5026void KTextEditor::DocumentPrivate::updateConfig()
5028 m_undoManager->updateConfig();
5031 m_indenter->setMode(m_config->indentationMode());
5032 m_indenter->updateConfig();
5035 m_buffer->setTabWidth(config()->tabWidth());
5038 for (
auto view : std::as_const(m_views)) {
5039 static_cast<ViewPrivate *
>(view)->updateDocumentConfig();
5043 if (m_onTheFlyChecker) {
5044 m_onTheFlyChecker->updateConfig();
5047 if (config()->autoSave()) {
5048 int interval = config()->autoSaveInterval();
5049 if (interval == 0) {
5050 m_autoSaveTimer.stop();
5052 m_autoSaveTimer.setInterval(interval * 1000);
5054 m_autoSaveTimer.start();
5059 Q_EMIT configChanged(
this);
5069bool KTextEditor::DocumentPrivate::readVariables(
bool onlyViewAndRenderer)
5071 const bool hasVariableline = [
this] {
5074 for (
int i = qMax(10, lines() - 10); i < lines(); ++i) {
5075 if (line(i).contains(s)) {
5080 for (
int i = 0; i < qMin(9, lines()); ++i) {
5081 if (line(i).contains(s)) {
5087 if (!hasVariableline) {
5091 if (!onlyViewAndRenderer) {
5092 m_config->configStart();
5096 for (
auto view : std::as_const(m_views)) {
5097 auto v =
static_cast<ViewPrivate *
>(view);
5102 for (
int i = 0; i < qMin(9, lines()); ++i) {
5103 readVariableLine(line(i), onlyViewAndRenderer);
5106 for (
int i = qMax(10, lines() - 10); i < lines(); i++) {
5107 readVariableLine(line(i), onlyViewAndRenderer);
5111 if (!onlyViewAndRenderer) {
5112 m_config->configEnd();
5115 for (
auto view : std::as_const(m_views)) {
5116 auto v =
static_cast<ViewPrivate *
>(view);
5123void KTextEditor::DocumentPrivate::readVariableLine(
const QString &t,
bool onlyViewAndRenderer)
5126 static const QRegularExpression kvLineWildcard(QStringLiteral(
"kate-wildcard\\((.*)\\):(.*)"));
5127 static const QRegularExpression kvLineMime(QStringLiteral(
"kate-mimetype\\((.*)\\):(.*)"));
5140 auto match = kvLine.match(t);
5141 if (
match.hasMatch()) {
5142 s =
match.captured(1);
5145 }
else if ((match = kvLineWildcard.match(t)).hasMatch()) {
5151 for (
const QString &pattern : wildcards) {
5158 found = wildcard.
match(matchPath ? pathOfFile : nameOfFile).hasMatch();
5169 s =
match.captured(2);
5172 }
else if ((match = kvLineMime.match(t)).hasMatch()) {
5180 s =
match.captured(2);
5188 static const auto vvl = {
5212 int spaceIndent = -1;
5213 bool replaceTabsSet =
false;
5218 while ((match = kvVar.match(s, startPos)).hasMatch()) {
5219 startPos =
match.capturedEnd(0);
5220 var =
match.captured(1);
5221 val =
match.captured(2).trimmed();
5226 if (onlyViewAndRenderer) {
5227 if (contains(vvl, var)) {
5228 setViewVariable(var, val);
5232 if (var ==
QLatin1String(
"word-wrap") && checkBoolValue(val, &state)) {
5237 else if (var ==
QLatin1String(
"backspace-indents") && checkBoolValue(val, &state)) {
5238 m_config->setBackspaceIndents(state);
5239 }
else if (var ==
QLatin1String(
"indent-pasted-text") && checkBoolValue(val, &state)) {
5240 m_config->setIndentPastedText(state);
5241 }
else if (var ==
QLatin1String(
"replace-tabs") && checkBoolValue(val, &state)) {
5242 m_config->setReplaceTabsDyn(state);
5243 replaceTabsSet =
true;
5244 }
else if (var ==
QLatin1String(
"remove-trailing-space") && checkBoolValue(val, &state)) {
5245 qCWarning(LOG_KTE) <<
i18n(
5246 "Using deprecated modeline 'remove-trailing-space'. "
5247 "Please replace with 'remove-trailing-spaces modified;', see "
5248 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5249 m_config->setRemoveSpaces(state ? 1 : 0);
5250 }
else if (var ==
QLatin1String(
"replace-trailing-space-save") && checkBoolValue(val, &state)) {
5251 qCWarning(LOG_KTE) <<
i18n(
5252 "Using deprecated modeline 'replace-trailing-space-save'. "
5253 "Please replace with 'remove-trailing-spaces all;', see "
5254 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5255 m_config->setRemoveSpaces(state ? 2 : 0);
5256 }
else if (var ==
QLatin1String(
"overwrite-mode") && checkBoolValue(val, &state)) {
5257 m_config->setOvr(state);
5258 }
else if (var ==
QLatin1String(
"keep-extra-spaces") && checkBoolValue(val, &state)) {
5259 m_config->setKeepExtraSpaces(state);
5260 }
else if (var ==
QLatin1String(
"tab-indents") && checkBoolValue(val, &state)) {
5261 m_config->setTabIndents(state);
5262 }
else if (var ==
QLatin1String(
"show-tabs") && checkBoolValue(val, &state)) {
5263 m_config->setShowTabs(state);
5264 }
else if (var ==
QLatin1String(
"show-trailing-spaces") && checkBoolValue(val, &state)) {
5265 m_config->setShowSpaces(state ? KateDocumentConfig::Trailing : KateDocumentConfig::
None);
5266 }
else if (var ==
QLatin1String(
"space-indent") && checkBoolValue(val, &state)) {
5268 spaceIndent = state;
5269 }
else if (var ==
QLatin1String(
"smart-home") && checkBoolValue(val, &state)) {
5270 m_config->setSmartHome(state);
5271 }
else if (var ==
QLatin1String(
"newline-at-eof") && checkBoolValue(val, &state)) {
5272 m_config->setNewLineAtEof(state);
5276 else if (var ==
QLatin1String(
"tab-width") && checkIntValue(val, &n)) {
5277 m_config->setTabWidth(n);
5278 }
else if (var ==
QLatin1String(
"indent-width") && checkIntValue(val, &n)) {
5279 m_config->setIndentationWidth(n);
5281 m_config->setIndentationMode(val);
5282 }
else if (var ==
QLatin1String(
"word-wrap-column") && checkIntValue(val, &n) && n > 0) {
5283 m_config->setWordWrapAt(n);
5289 if ((n = indexOf(l, val.
toLower())) != -1) {
5292 m_config->setEol(n);
5293 m_config->setAllowEolDetection(
false);
5296 if (checkBoolValue(val, &state)) {
5297 m_config->setBom(state);
5299 }
else if (var ==
QLatin1String(
"remove-trailing-spaces")) {
5302 m_config->setRemoveSpaces(1);
5304 m_config->setRemoveSpaces(2);
5306 m_config->setRemoveSpaces(0);
5309 setHighlightingMode(val);
5315 setDefaultDictionary(val);
5316 }
else if (var ==
QLatin1String(
"automatic-spell-checking") && checkBoolValue(val, &state)) {
5317 onTheFlySpellCheckingEnabled(state);
5321 else if (contains(vvl, var)) {
5322 setViewVariable(var, val);
5324 m_storedVariables[var] = val;
5336 if (!replaceTabsSet && spaceIndent >= 0) {
5337 m_config->setReplaceTabsDyn(spaceIndent > 0);
5341void KTextEditor::DocumentPrivate::setViewVariable(
const QString &var,
const QString &val)
5346 for (
auto view : std::as_const(m_views)) {
5347 auto v =
static_cast<ViewPrivate *
>(view);
5350 if (checkBoolValue(val, &state)) {
5353 if (v->config()->
setValue(var, help)) {
5354 }
else if (v->rendererConfig()->
setValue(var, help)) {
5356 }
else if (var ==
QLatin1String(
"dynamic-word-wrap") && checkBoolValue(val, &state)) {
5357 v->config()->setDynWordWrap(state);
5358 }
else if (var ==
QLatin1String(
"block-selection") && checkBoolValue(val, &state)) {
5359 v->setBlockSelection(state);
5362 }
else if (var ==
QLatin1String(
"icon-bar-color") && checkColorValue(val, c)) {
5363 v->rendererConfig()->setIconBarColor(c);
5366 else if (var ==
QLatin1String(
"background-color") && checkColorValue(val, c)) {
5367 v->rendererConfig()->setBackgroundColor(c);
5368 }
else if (var ==
QLatin1String(
"selection-color") && checkColorValue(val, c)) {
5369 v->rendererConfig()->setSelectionColor(c);
5370 }
else if (var ==
QLatin1String(
"current-line-color") && checkColorValue(val, c)) {
5371 v->rendererConfig()->setHighlightedLineColor(c);
5372 }
else if (var ==
QLatin1String(
"bracket-highlight-color") && checkColorValue(val, c)) {
5373 v->rendererConfig()->setHighlightedBracketColor(c);
5374 }
else if (var ==
QLatin1String(
"word-wrap-marker-color") && checkColorValue(val, c)) {
5375 v->rendererConfig()->setWordWrapMarkerColor(c);
5381 _f.setFixedPitch(
QFont(val).fixedPitch());
5386 v->rendererConfig()->setFont(_f);
5388 v->rendererConfig()->setSchema(val);
5393bool KTextEditor::DocumentPrivate::checkBoolValue(
QString val,
bool *result)
5397 if (contains(trueValues, val)) {
5403 if (contains(falseValues, val)) {
5410bool KTextEditor::DocumentPrivate::checkIntValue(
const QString &val,
int *result)
5413 *result = val.
toInt(&ret);
5417bool KTextEditor::DocumentPrivate::checkColorValue(
const QString &val,
QColor &c)
5426 auto it = m_storedVariables.find(name);
5427 if (it == m_storedVariables.end()) {
5435 QString s = QStringLiteral(
"kate: ");
5439 readVariableLine(s);
5444void KTextEditor::DocumentPrivate::slotModOnHdDirty(
const QString &path)
5446 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskModified)) {
5448 m_modOnHdReason = OnDiskModified;
5450 if (!m_modOnHdTimer.isActive()) {
5451 m_modOnHdTimer.start();
5456void KTextEditor::DocumentPrivate::slotModOnHdCreated(
const QString &path)
5458 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskCreated)) {
5460 m_modOnHdReason = OnDiskCreated;
5462 if (!m_modOnHdTimer.isActive()) {
5463 m_modOnHdTimer.start();
5468void KTextEditor::DocumentPrivate::slotModOnHdDeleted(
const QString &path)
5470 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskDeleted)) {
5472 m_modOnHdReason = OnDiskDeleted;
5474 if (!m_modOnHdTimer.isActive()) {
5475 m_modOnHdTimer.start();
5480void KTextEditor::DocumentPrivate::slotDelayedHandleModOnHd()
5484 if (!oldDigest.
isEmpty() && !url().isEmpty() && url().isLocalFile()) {
5486 if (m_modOnHdReason != OnDiskDeleted && m_modOnHdReason != OnDiskCreated && createDigest() && oldDigest == checksum()) {
5488 m_modOnHdReason = OnDiskUnmodified;
5489 m_prevModOnHdReason = OnDiskUnmodified;
5496 if (m_modOnHd && !isModified() &&
QFile::exists(url().toLocalFile())
5497 && config()->value(KateDocumentConfig::AutoReloadIfStateIsInVersionControl).toBool()) {
5504 git.
start(fullGitPath, args);
5511 m_modOnHdReason = OnDiskUnmodified;
5512 m_prevModOnHdReason = OnDiskUnmodified;
5522 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
5527 return m_buffer->digest();
5530bool KTextEditor::DocumentPrivate::createDigest()
5534 if (url().isLocalFile()) {
5535 QFile f(url().toLocalFile());
5539 const QString header = QStringLiteral(
"blob %1").
arg(f.size());
5542 digest = crypto.result();
5547 m_buffer->setDigest(digest);
5551QString KTextEditor::DocumentPrivate::reasonedMOHString()
const
5556 switch (m_modOnHdReason) {
5557 case OnDiskModified:
5558 return i18n(
"The file '%1' was modified on disk.", str);
5561 return i18n(
"The file '%1' was created on disk.", str);
5564 return i18n(
"The file '%1' was deleted on disk.", str);
5573void KTextEditor::DocumentPrivate::removeTrailingSpacesAndAddNewLineAtEof()
5576 const int remove = config()->removeSpaces();
5577 const bool newLineAtEof = config()->newLineAtEof();
5578 if (remove == 0 && !newLineAtEof) {
5583 const bool wordWrapEnabled = config()->wordWrap();
5584 if (wordWrapEnabled) {
5591 const int lines = this->lines();
5593 for (
int line = 0; line < lines; ++line) {
5599 if (remove == 2 || textline.markedAsModified() || textline.markedAsSavedOnDisk()) {
5600 const int p = textline.
lastChar() + 1;
5601 const int l = textline.
length() - p;
5603 editRemoveText(line, p, l);
5612 Q_ASSERT(lines > 0);
5613 const auto length = lineLength(lines - 1);
5617 const auto oldEndOfDocumentCursor = documentEnd();
5618 std::vector<KTextEditor::ViewPrivate *> viewsToRestoreCursors;
5619 for (
auto view : std::as_const(m_views)) {
5620 auto v =
static_cast<ViewPrivate *
>(view);
5621 if (v->cursorPosition() == oldEndOfDocumentCursor) {
5622 viewsToRestoreCursors.push_back(v);
5627 editWrapLine(lines - 1, length);
5630 for (
auto v : viewsToRestoreCursors) {
5631 v->setCursorPosition(oldEndOfDocumentCursor);
5639 if (wordWrapEnabled) {
5647 const int lines = this->lines();
5648 for (
int line = 0; line < lines; ++line) {
5650 const int p = textline.
lastChar() + 1;
5651 const int l = textline.
length() - p;
5653 editRemoveText(line, p, l);
5661 if (user || !m_fileTypeSetByUser) {
5667 if (fileType.name.
isEmpty()) {
5672 m_fileTypeSetByUser = user;
5674 m_fileType = newType;
5676 m_config->configStart();
5681 if ((user || !m_hlSetByUser) && !fileType.hl.
isEmpty()) {
5682 int hl(KateHlManager::self()->nameFind(fileType.hl));
5685 m_buffer->setHighlight(hl);
5692 if (!m_indenterSetByUser && !fileType.indenter.
isEmpty()) {
5693 config()->setIndentationMode(fileType.indenter);
5697 for (
auto view : std::as_const(m_views)) {
5698 auto v =
static_cast<ViewPrivate *
>(view);
5703 bool bom_settings =
false;
5704 if (m_bomSetByUser) {
5705 bom_settings = m_config->bom();
5707 readVariableLine(fileType.varLine);
5708 if (m_bomSetByUser) {
5709 m_config->setBom(bom_settings);
5711 m_config->configEnd();
5712 for (
auto view : std::as_const(m_views)) {
5713 auto v =
static_cast<ViewPrivate *
>(view);
5720 Q_EMIT modeChanged(
this);
5724void KTextEditor::DocumentPrivate::slotQueryClose_save(
bool *handled,
bool *abortClosing)
5727 *abortClosing =
true;
5728 if (url().isEmpty()) {
5729 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
5731 *abortClosing =
true;
5735 *abortClosing =
false;
5738 *abortClosing =
false;
5748 return m_config->configKeys();
5754 return m_config->
value(key);
5760 m_config->setValue(key, value);
5774 bool changed = removeText(range, block);
5775 changed |= insertText(range.
start(), s, block);
5780KateHighlighting *KTextEditor::DocumentPrivate::highlight()
const
5782 return m_buffer->highlight();
5787 m_buffer->ensureHighlighted(i);
5788 return m_buffer->plainLine(i);
5793 return m_buffer->plainLine(i);
5796bool KTextEditor::DocumentPrivate::isEditRunning()
const
5798 return editIsRunning;
5801void KTextEditor::DocumentPrivate::setUndoMergeAllEdits(
bool merge)
5803 if (merge && m_undoMergeAllEdits) {
5808 m_undoManager->undoSafePoint();
5809 m_undoManager->setAllowComplexMerge(merge);
5810 m_undoMergeAllEdits =
merge;
5823 return new Kate::TextRange(buffer(), range, insertBehaviors, emptyBehavior);
5828 return m_buffer->history().revision();
5833 return m_buffer->history().lastSavedRevision();
5838 m_buffer->history().lockRevision(revision);
5843 m_buffer->history().unlockRevision(revision);
5849 qint64 fromRevision,
5852 m_buffer->history().transformCursor(line, column, insertBehavior, fromRevision, toRevision);
5857 qint64 fromRevision,
5860 int line = cursor.
line();
5861 int column = cursor.
column();
5862 m_buffer->history().transformCursor(line, column, insertBehavior, fromRevision, toRevision);
5869 qint64 fromRevision,
5872 m_buffer->history().transformRange(range, insertBehaviors, emptyBehavior, fromRevision, toRevision);
5881 m_annotationModel = model;
5882 Q_EMIT annotationModelChanged(oldmodel, m_annotationModel);
5887 return m_annotationModel;
5892bool KTextEditor::DocumentPrivate::queryClose()
5894 if (!isModified() || (isEmpty() && url().isEmpty())) {
5898 QString docName = documentName();
5901 i18n(
"The document \"%1\" has been modified.\n"
5902 "Do you want to save your changes or discard them?",
5904 i18n(
"Close Document"),
5908 bool abortClose =
false;
5909 bool handled =
false;
5913 sigQueryClose(&handled, &abortClose);
5915 if (url().isEmpty()) {
5916 const QUrl url = getSaveFileUrl(
i18n(
"Save File"));
5925 }
else if (abortClose) {
5928 return waitSaveComplete();
5936void KTextEditor::DocumentPrivate::slotStarted(
KIO::Job *job)
5939 if (m_documentState == DocumentIdle) {
5940 m_documentState = DocumentLoading;
5948 if (m_documentState == DocumentLoading) {
5950 m_readWriteStateBeforeLoading = isReadWrite();
5955 setReadWrite(
false);
5965void KTextEditor::DocumentPrivate::slotCompleted()
5969 if (m_documentState == DocumentLoading) {
5970 setReadWrite(m_readWriteStateBeforeLoading);
5971 delete m_loadingMessage;
5975 if (m_documentState == DocumentSaving || m_documentState == DocumentSavingAs) {
5976 Q_EMIT documentSavedOrUploaded(
this, m_documentState == DocumentSavingAs);
5980 m_documentState = DocumentIdle;
5981 m_reloading =
false;
5984void KTextEditor::DocumentPrivate::slotCanceled()
5988 if (m_documentState == DocumentLoading) {
5989 setReadWrite(m_readWriteStateBeforeLoading);
5990 delete m_loadingMessage;
5992 if (!m_openingError) {
5993 showAndSetOpeningErrorAccess();
6000 m_documentState = DocumentIdle;
6001 m_reloading =
false;
6004void KTextEditor::DocumentPrivate::slotTriggerLoadingMessage()
6008 if (m_documentState != DocumentLoading) {
6013 delete m_loadingMessage;
6022 m_loadingMessage->addAction(cancel);
6026 postMessage(m_loadingMessage);
6029void KTextEditor::DocumentPrivate::slotAbortLoading()
6032 if (!m_loadingJob) {
6038 m_loadingJob->kill(KJob::EmitResult);
6039 m_loadingJob =
nullptr;
6042void KTextEditor::DocumentPrivate::slotUrlChanged(
const QUrl &url)
6052 Q_EMIT documentUrlChanged(
this);
6055bool KTextEditor::DocumentPrivate::save()
6059 if ((m_documentState != DocumentIdle) && (m_documentState != DocumentPreSavingAs)) {
6064 if (m_documentState == DocumentIdle) {
6065 m_documentState = DocumentSaving;
6067 m_documentState = DocumentSavingAs;
6071 Q_EMIT aboutToSave(
this);
6077bool KTextEditor::DocumentPrivate::saveAs(
const QUrl &url)
6088 if (m_documentState != DocumentIdle) {
6093 m_documentState = DocumentPreSavingAs;
6099QString KTextEditor::DocumentPrivate::defaultDictionary()
const
6101 return m_defaultDictionary;
6106 return m_dictionaryRanges;
6109void KTextEditor::DocumentPrivate::clearDictionaryRanges()
6111 for (
auto i = m_dictionaryRanges.cbegin(); i != m_dictionaryRanges.cend(); ++i) {
6114 m_dictionaryRanges.clear();
6115 if (m_onTheFlyChecker) {
6116 m_onTheFlyChecker->refreshSpellCheck();
6118 Q_EMIT dictionaryRangesPresent(
false);
6125 setDictionary(newDictionary, rangeOnLine(range, i));
6128 setDictionary(newDictionary, range);
6131 Q_EMIT dictionaryRangesPresent(!m_dictionaryRanges.isEmpty());
6137 if (!newDictionaryRange.
isValid() || newDictionaryRange.
isEmpty()) {
6142 for (
auto i = m_dictionaryRanges.begin(); i != m_dictionaryRanges.end();) {
6143 qCDebug(LOG_KTE) <<
"new iteration" << newDictionaryRange;
6144 if (newDictionaryRange.
isEmpty()) {
6147 QPair<KTextEditor::MovingRange *, QString> pair = *i;
6148 QString dictionarySet = pair.second;
6150 qCDebug(LOG_KTE) << *dictionaryRange << dictionarySet;
6151 if (dictionaryRange->
contains(newDictionaryRange) && newDictionary == dictionarySet) {
6152 qCDebug(LOG_KTE) <<
"dictionaryRange contains newDictionaryRange";
6155 if (newDictionaryRange.
contains(*dictionaryRange)) {
6156 delete dictionaryRange;
6157 i = m_dictionaryRanges.erase(i);
6158 qCDebug(LOG_KTE) <<
"newDictionaryRange contains dictionaryRange";
6164 if (dictionarySet == newDictionary) {
6167 Q_ASSERT(remainingRanges.
size() == 1);
6168 newDictionaryRange = remainingRanges.
first();
6170 qCDebug(LOG_KTE) <<
"dictionarySet == newDictionary";
6174 for (
auto j = remainingRanges.
begin(); j != remainingRanges.
end(); ++j) {
6177 newRanges.
push_back({remainingRange, dictionarySet});
6179 i = m_dictionaryRanges.erase(i);
6180 delete dictionaryRange;
6185 m_dictionaryRanges += newRanges;
6190 m_dictionaryRanges.push_back({newDictionaryMovingRange, newDictionary});
6192 if (m_onTheFlyChecker && !newDictionaryRange.
isEmpty()) {
6193 m_onTheFlyChecker->refreshSpellCheck(newDictionaryRange);
6197void KTextEditor::DocumentPrivate::setDefaultDictionary(
const QString &dict)
6199 if (m_defaultDictionary == dict) {
6203 m_defaultDictionary = dict;
6205 if (m_onTheFlyChecker) {
6206 m_onTheFlyChecker->updateConfig();
6207 refreshOnTheFlyCheck();
6209 Q_EMIT defaultDictionaryChanged(
this);
6212void KTextEditor::DocumentPrivate::onTheFlySpellCheckingEnabled(
bool enable)
6214 if (isOnTheFlySpellCheckingEnabled() == enable) {
6219 Q_ASSERT(m_onTheFlyChecker ==
nullptr);
6220 m_onTheFlyChecker =
new KateOnTheFlyChecker(
this);
6222 delete m_onTheFlyChecker;
6223 m_onTheFlyChecker =
nullptr;
6226 for (
auto view : std::as_const(m_views)) {
6227 static_cast<ViewPrivate *
>(view)->reflectOnTheFlySpellCheckStatus(enable);
6231bool KTextEditor::DocumentPrivate::isOnTheFlySpellCheckingEnabled()
const
6233 return m_onTheFlyChecker !=
nullptr;
6238 if (!m_onTheFlyChecker) {
6241 return m_onTheFlyChecker->dictionaryForMisspelledRange(range);
6245void KTextEditor::DocumentPrivate::clearMisspellingForWord(
const QString &word)
6247 if (m_onTheFlyChecker) {
6248 m_onTheFlyChecker->clearMisspellingForWord(word);
6254 if (m_onTheFlyChecker) {
6255 m_onTheFlyChecker->refreshSpellCheck(range);
6261 deleteDictionaryRange(movingRange);
6266 deleteDictionaryRange(movingRange);
6271 qCDebug(LOG_KTE) <<
"deleting" << movingRange;
6273 auto finder = [=](
const QPair<KTextEditor::MovingRange *, QString> &item) ->
bool {
6274 return item.first == movingRange;
6277 auto it = std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder);
6279 if (it != m_dictionaryRanges.end()) {
6280 m_dictionaryRanges.erase(it);
6284 Q_ASSERT(std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder) == m_dictionaryRanges.end());
6287bool KTextEditor::DocumentPrivate::containsCharacterEncoding(
KTextEditor::Range range)
6289 KateHighlighting *highlighting = highlight();
6291 const int rangeStartLine = range.
start().
line();
6292 const int rangeStartColumn = range.
start().
column();
6293 const int rangeEndLine = range.
end().
line();
6294 const int rangeEndColumn = range.
end().
column();
6296 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6298 const int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6299 const int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6300 for (
int col = startColumn; col < endColumn; ++col) {
6302 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6312int KTextEditor::DocumentPrivate::computePositionWrtOffsets(
const OffsetList &offsetList,
int pos)
6314 int previousOffset = 0;
6315 for (
auto i = offsetList.cbegin(); i != offsetList.cend(); ++i) {
6316 if (i->first > pos) {
6319 previousOffset = i->second;
6321 return pos + previousOffset;
6330 int decToEncCurrentOffset = 0;
6331 int encToDecCurrentOffset = 0;
6335 KateHighlighting *highlighting = highlight();
6338 const int rangeStartLine = range.
start().
line();
6339 const int rangeStartColumn = range.
start().
column();
6340 const int rangeEndLine = range.
end().
line();
6341 const int rangeEndColumn = range.
end().
column();
6343 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6344 textLine = kateTextLine(line);
6345 int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6346 int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.
length();
6347 for (
int col = startColumn; col < endColumn;) {
6349 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6352 if (!matchingPrefix.
isEmpty()) {
6354 const QChar &c = characterEncodingsHash.
value(matchingPrefix);
6355 const bool isNullChar = c.
isNull();
6359 i += matchingPrefix.
length();
6360 col += matchingPrefix.
length();
6362 decToEncCurrentOffset = decToEncCurrentOffset - (isNullChar ? 0 : 1) + matchingPrefix.
length();
6363 encToDecCurrentOffset = encToDecCurrentOffset - matchingPrefix.
length() + (isNullChar ? 0 : 1);
6364 newI += (isNullChar ? 0 : 1);
6365 decToEncOffsetList.
push_back(QPair<int, int>(newI, decToEncCurrentOffset));
6366 encToDecOffsetList.
push_back(QPair<int, int>(i, encToDecCurrentOffset));
6376 if (previous < range.
end()) {
6382void KTextEditor::DocumentPrivate::replaceCharactersByEncoding(
KTextEditor::Range range)
6384 KateHighlighting *highlighting = highlight();
6387 const int rangeStartLine = range.
start().
line();
6388 const int rangeStartColumn = range.
start().
column();
6389 const int rangeEndLine = range.
end().
line();
6390 const int rangeEndColumn = range.
end().
column();
6392 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6393 textLine = kateTextLine(line);
6394 int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6395 int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6396 for (
int col = startColumn; col < endColumn;) {
6398 const QHash<QChar, QString> &reverseCharacterEncodingsHash = highlighting->getReverseCharacterEncodings(attr);
6399 auto it = reverseCharacterEncodingsHash.
find(textLine.
at(col));
6400 if (it != reverseCharacterEncodingsHash.
end()) {
6402 col += (*it).length();
6416 return highlight()->getEmbeddedHighlightingModes();
6421 return highlight()->higlightingModeForLocation(
this, position);
6436 if (line < 0 || line >= lines() || column < 0) {
6437 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6445 if (column < tl.
length()) {
6447 }
else if (column == tl.
length()) {
6451 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6454 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6457 return highlight()->defaultStyleForAttribute(attribute);
6460bool KTextEditor::DocumentPrivate::isComment(
int line,
int column)
6462 return defStyleNum(line, column) == KSyntaxHighlighting::Theme::TextStyle::Comment;
6467 const int offset = down ? 1 : -1;
6468 const int lineCount = lines();
6469 while (startLine >= 0 && startLine < lineCount) {
6471 if (tl.markedAsModified() || tl.markedAsSavedOnDisk()) {
6474 startLine += offset;
6483 delete m_activeTemplateHandler.data();
6484 m_activeTemplateHandler = handler;
6497 qCWarning(LOG_KTE) <<
"trying to post a message to a view of another document:" << message->
text();
6507 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
6513 const auto messageActions = message->
actions();
6514 managedMessageActions.
reserve(messageActions.size());
6515 for (
QAction *action : messageActions) {
6516 action->setParent(
nullptr);
6517 managedMessageActions.
append(std::shared_ptr<QAction>(action));
6519 m_messageHash.insert(message, managedMessageActions);
6522 if (KTextEditor::ViewPrivate *view = qobject_cast<KTextEditor::ViewPrivate *>(message->
view())) {
6523 view->postMessage(message, managedMessageActions);
6525 for (
auto view : std::as_const(m_views)) {
6526 static_cast<ViewPrivate *
>(view)->postMessage(message, managedMessageActions);
6531 connect(message, &
Message::closed,
this, &DocumentPrivate::messageDestroyed);
6539 Q_ASSERT(m_messageHash.contains(message));
6540 m_messageHash.remove(message);
6544#include "moc_katedocument.cpp"
bool hasKey(const char *key) const
void writeEntry(const char *key, const char *value, WriteConfigFlags pFlags=Normal)
void deleteGroup(const QString &group, WriteConfigFlags flags=Normal)
QString readEntry(const char *key, const char *aDefault=nullptr) const
void addFile(const QString &file)
void removeFile(const QString &file)
void deleted(const QString &path)
void dirty(const QString &path)
void created(const QString &path)
mode_t permissions() const
const UDSEntry & statResult() const
virtual Q_SCRIPTABLE void start()=0
Ptr findByDevice(const QString &device) const
static List currentMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
static KNetworkMounts * self()
MediumSideEffectsOptimizations
virtual QWidget * widget()
void setAutoDeletePart(bool autoDeletePart)
void setAutoDeleteWidget(bool autoDeleteWidget)
virtual bool openUrl(const QUrl &url)
void urlChanged(const QUrl &url)
void canceled(const QString &errMsg)
void started(KIO::Job *job)
virtual void setReadWrite(bool readwrite=true)
virtual bool saveAs(const QUrl &url)
void sigQueryClose(bool *handled, bool *abortClosing)
An model for providing line annotation information.
bool closeDocument(KTextEditor::Document *document)
Close the given document.
KTextEditor::MainWindow * activeMainWindow()
Accessor to the active main window.
The Cursor represents a position in a Document.
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
void setColumn(int column) noexcept
Set the cursor column to column.
void setPosition(Cursor position) noexcept
Set the current cursor position to position.
constexpr bool isValid() const noexcept
Returns whether the current position of this cursor is a valid position (line + column must both be >...
static constexpr Cursor start() noexcept
Returns a cursor representing the start of any document - i.e., line 0, column 0.
void setLine(int line) noexcept
Set the cursor line to line.
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
static constexpr Cursor invalid() noexcept
Returns an invalid cursor.
A Cursor which is bound to a specific Document.
Backend of KTextEditor::Document related public KTextEditor interfaces.
bool setEncoding(const QString &e) override
Set the encoding for this document.
bool saveFile() override
save the file obtained by the kparts framework the framework abstracts the uploading of remote files
void transformRange(KTextEditor::Range &range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors, KTextEditor::MovingRange::EmptyBehavior emptyBehavior, qint64 fromRevision, qint64 toRevision=-1) override
Transform a range from one revision to an other.
void lockRevision(qint64 revision) override
Lock a revision, this will keep it around until released again.
void recoverData() override
If recover data is available, calling recoverData() will trigger the recovery of the data.
QString highlightingModeSection(int index) const override
Returns the name of the section for a highlight given its index in the highlight list (as returned by...
bool handleMarkContextMenu(int line, QPoint position)
Returns true if the context-menu event should not further be processed.
void readSessionConfig(const KConfigGroup &config, const QSet< QString > &flags=QSet< QString >()) override
Read session settings from the given config.
QStringList highlightingModes() const override
Return a list of the names of all possible modes.
bool documentReload() override
Reloads the current document from disk if possible.
void setModifiedOnDisk(ModifiedOnDiskReason reason) override
Set the document's modified-on-disk state to reason.
KTextEditor::Cursor documentEnd() const override
End position of the document.
void clearMarks() override
QStringList configKeys() const override
Get a list of all available keys.
bool postMessage(KTextEditor::Message *message) override
Post message to the Document and its Views.
int lineLengthLimit() const
reads the line length limit from config, if it is not overridden
virtual void slotModifiedOnDisk(KTextEditor::View *v=nullptr)
Ask the user what to do, if the file has been modified on disk.
void joinLines(uint first, uint last)
Unwrap a range of lines.
KTextEditor::MovingRange * newMovingRange(KTextEditor::Range range, KTextEditor::MovingRange::InsertBehaviors insertBehaviors=KTextEditor::MovingRange::DoNotExpand, KTextEditor::MovingRange::EmptyBehavior emptyBehavior=KTextEditor::MovingRange::AllowEmpty) override
Create a new moving range for this document.
virtual QString variable(const QString &name) const
Returns the value for the variable name.
bool setHighlightingMode(const QString &name) override
Set the current mode of the document by giving its name.
QStringList textLines(KTextEditor::Range range, bool block=false) const override
Get the document content within the given range.
void clearEditingPosStack()
Removes all the elements in m_editingStack of the respective document.
void transform(KTextEditor::ViewPrivate *view, KTextEditor::Cursor, TextTransform)
Handling uppercase, lowercase and capitalize for the view.
void rangeInvalid(KTextEditor::MovingRange *movingRange) override
The range is now invalid (ie.
void discardDataRecovery() override
If recover data is available, calling discardDataRecovery() will discard the recover data and the rec...
bool updateFileType(const QString &newType, bool user=false)
bool isLineModified(int line) const override
Check whether line currently contains unsaved data.
bool setMode(const QString &name) override
Set the current mode of the document by giving its name.
qsizetype totalCharacters() const override
Get the count of characters in the document.
QString highlightingMode() const override
Return the name of the currently used mode.
QString line(int line) const override
Get a single text line.
KTextEditor::AnnotationModel * annotationModel() const override
returns the currently set AnnotationModel or 0 if there's none set
QString markDescription(Document::MarkTypes) const override
Get the mark's description to text.
qint64 revision() const override
Current revision.
QString mimeType() override
Tries to detect mime-type based on file name and content of buffer.
KTextEditor::MovingCursor * newMovingCursor(KTextEditor::Cursor position, KTextEditor::MovingCursor::InsertBehavior insertBehavior=KTextEditor::MovingCursor::MoveOnInsert) override
Create a new moving cursor for this document.
QChar characterAt(KTextEditor::Cursor position) const override
Get the character at text position cursor.
qsizetype cursorToOffset(KTextEditor::Cursor c) const override
Retrives the offset for the given cursor position NOTE: It will return -1 if the cursor was invalid o...
QStringList modes() const override
Return a list of the names of all possible modes.
void setAnnotationModel(KTextEditor::AnnotationModel *model) override
Sets a new AnnotationModel for this document to provide annotation information for each line.
bool editUnWrapLine(int line, bool removeLine=true, int length=0)
Unwrap line.
bool editInsertText(int line, int col, const QString &s, bool notify=true)
Add a string in the given line/column.
KTextEditor::Cursor offsetToCursor(qsizetype offset) const override
Retrives the cursor position for given offset NOTE: It will return an invalid cursor(-1,...
bool openFile() override
open the file obtained by the kparts framework the framework abstracts the loading of remote files
bool isLineSaved(int line) const override
Check whether line currently contains only saved text.
QWidget * widget() override
void writeSessionConfig(KConfigGroup &config, const QSet< QString > &flags=QSet< QString >()) override
Write session settings to the config.
QByteArray checksum() const override
Returns a git compatible sha1 checksum of this document on disk.
bool isLineTouched(int line) const override
Check whether line was touched since the file was opened.
void rangeEmpty(KTextEditor::MovingRange *movingRange) override
The range is now empty (ie.
QString text() const override
Get the document content.
int lines() const override
Get the count of lines of the document.
bool handleMarkClick(int line)
Returns true if the click on the mark should not be further processed.
KTextEditor::View * createView(QWidget *parent, KTextEditor::MainWindow *mainWindow=nullptr) override
Create a new view attached to parent.
bool isDataRecoveryAvailable() const override
Returns whether a recovery is available for the current document.
void bomSetByUser()
Set that the BOM marker is forced via the tool menu.
bool editStart()
Enclose editor actions with editStart() and editEnd() to group them.
KTextEditor::Cursor lastEditingPosition(EditingPositionKind nextOrPrevious, KTextEditor::Cursor)
Returns the next or previous position cursor in this document from the stack depending on the argumen...
void setConfigValue(const QString &key, const QVariant &value) override
Set a the key's value to value.
KSyntaxHighlighting::Theme::TextStyle defStyleNum(int line, int column)
void setModifiedOnDiskWarning(bool on) override
Control, whether the editor should show a warning dialog whenever a file was modified on disk.
QIcon markIcon(Document::MarkTypes markType) const override
Get the mark's icon.
KSyntaxHighlighting::Theme::TextStyle defaultStyleAt(KTextEditor::Cursor position) const override
Get the default style of the character located at position.
bool editWrapLine(int line, int col, bool newLine=true, bool *newLineAdded=nullptr, bool notify=true)
Wrap line.
void typeChars(KTextEditor::ViewPrivate *view, QString chars)
Type chars in a view.
QString highlightingModeAt(KTextEditor::Cursor position) override
Get the highlight mode used at a given position in the document.
QVariant configValue(const QString &key) override
Get a value for the key.
bool wrapText(int startLine, int endLine)
Warp a line.
bool editRemoveText(int line, int col, int len)
Remove a string in the given line/column.
qint64 lastSavedRevision() const override
Last revision the buffer got successful saved.
void setDontChangeHlOnSave()
allow to mark, that we changed hl on user wish and should not reset it atm used for the user visible ...
QString decodeCharacters(KTextEditor::Range range, KTextEditor::DocumentPrivate::OffsetList &decToEncOffsetList, KTextEditor::DocumentPrivate::OffsetList &encToDecOffsetList)
The first OffsetList is from decoded to encoded, and the second OffsetList from encoded to decoded.
void saveEditingPositions(const KTextEditor::Cursor cursor)
Saves the editing positions into the stack.
uint editableMarks() const override
Get, which marks can be toggled by the user.
Kate::TextLine plainKateTextLine(int i)
Return line lineno.
uint mark(int line) override
Get all marks set on the line.
void unlockRevision(qint64 revision) override
Release a revision.
QString mode() const override
Return the name of the currently used mode.
bool isValidTextPosition(KTextEditor::Cursor cursor) const override
Get whether cursor is a valid text position.
void removeAllTrailingSpaces()
This function doesn't check for config and is available for use all the time via an action.
void transformCursor(KTextEditor::Cursor &cursor, KTextEditor::MovingCursor::InsertBehavior insertBehavior, qint64 fromRevision, qint64 toRevision=-1) override
Transform a cursor from one revision to an other.
QString modeSection(int index) const override
Returns the name of the section for a mode given its index in the highlight list (as returned by mode...
bool editMarkLineAutoWrapped(int line, bool autowrapped)
Mark line as autowrapped.
bool editInsertLine(int line, const QString &s, bool notify=true)
Insert a string at the given line.
QStringList embeddedHighlightingModes() const override
Get all available highlighting modes for the current document.
bool editRemoveLine(int line)
Remove a line.
bool isEditingTransactionRunning() const override
Check whether an editing transaction is currently running.
Kate::TextLine kateTextLine(int i)
Same as plainKateTextLine(), except that it is made sure the line is highlighted.
QString encoding() const override
Get the current chosen encoding.
bool editEnd()
End a editor operation.
virtual void setVariable(const QString &name, const QString &value)
Set the variable name to value.
int findTouchedLine(int startLine, bool down)
Find the next modified/saved line, starting at startLine.
QString wordAt(KTextEditor::Cursor cursor) const override
Get the word at the text position cursor.
int lineLength(int line) const override
Get the length of a given line in characters.
KTextEditor::Range wordRangeAt(KTextEditor::Cursor cursor) const override
Get the text range for the word located under the text position cursor.
const QHash< int, KTextEditor::Mark * > & marks() override
Get a hash holding all marks in the document.
void removeView(KTextEditor::View *)
removes the view from the list of views.
bool wrapParagraph(int first, int last)
Wrap lines touched by the selection with respect of existing paragraphs.
A KParts derived class representing a text document.
void documentNameChanged(KTextEditor::Document *document)
This signal is emitted whenever the document name changes.
void editingFinished(KTextEditor::Document *document)
Editing transaction has finished.
MarkTypes
Predefined mark types.
virtual QString text() const =0
Get the document content.
void aboutToInvalidateMovingInterfaceContent(KTextEditor::Document *document)
This signal is emitted before the ranges of a document are invalidated and the revisions are deleted ...
static int reservedMarkersCount()
Get the number of predefined mark types we have so far.
void editingStarted(KTextEditor::Document *document)
Editing transaction has started.
void aboutToClose(KTextEditor::Document *document)
Warn anyone listening that the current document is about to close.
void aboutToDeleteMovingInterfaceContent(KTextEditor::Document *document)
This signal is emitted before the cursors/ranges/revisions of a document are destroyed as the documen...
ModifiedOnDiskReason
Reasons why a document is modified on disk.
KateModeManager * modeManager()
global mode manager used to manage the modes centrally
void deregisterDocument(KTextEditor::DocumentPrivate *doc)
unregister document at the factory
KTextEditor::Application * application() const override
Current hosting application, if any set.
KDirWatch * dirWatch()
global dirwatch
void registerDocument(KTextEditor::DocumentPrivate *doc)
register document at the factory this allows us to loop over all docs for example on config changes
static KTextEditor::EditorPrivate * self()
Kate Part Internal stuff ;)
QList< KTextEditor::Document * > documents() override
Returns a list of all documents of this editor.
KateVariableExpansionManager * variableExpansionManager()
Returns the variable expansion manager.
static Editor * instance()
Accessor to get the Editor instance.
An object representing lines from a start line to an end line.
This class allows the application that embeds the KTextEditor component to allow it to access parts o...
QWidget * window()
Get the toplevel widget.
uint type
The mark types in the line, combined with logical OR.
int line
The line that contains the mark.
This class holds a Message to display in Views.
@ TopInView
show message as view overlay in the top right corner.
KTextEditor::View * view() const
This function returns the view you set by setView().
int autoHide() const
Returns the auto hide time in milliseconds.
void addAction(QAction *action, bool closeOnTrigger=true)
Adds an action to the message.
QString text() const
Returns the text set in the constructor.
void closed(KTextEditor::Message *message)
This signal is emitted before the message is deleted.
@ Error
error message type
@ Warning
warning message type
void setDocument(KTextEditor::Document *document)
Set the document pointer to document.
QList< QAction * > actions() const
Accessor to all actions, mainly used in the internal implementation to add the actions into the gui.
A Cursor which is bound to a specific Document, and maintains its position.
InsertBehavior
Insert behavior of this cursor, should it stay if text is insert at its position or should it move.
@ MoveOnInsert
move on insert
A range that is bound to a specific Document, and maintains its position.
EmptyBehavior
Behavior of range if it becomes empty.
const Range toRange() const
Convert this clever range into a dumb one.
virtual void setFeedback(MovingRangeFeedback *feedback)=0
Sets the currently active MovingRangeFeedback for this range.
bool contains(const Range &range) const
Check whether the this range wholly encompasses range.
@ DoNotExpand
Don't expand to encapsulate new characters in either direction. This is the default.
@ ExpandRight
Expand to encapsulate new characters to the right of the range.
@ ExpandLeft
Expand to encapsulate new characters to the left of the range.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
void setEnd(Cursor end) noexcept
Set the end cursor to end.
constexpr bool isEmpty() const noexcept
Returns true if this range contains no characters, ie.
void setRange(Range range) noexcept
Set the start and end cursors to range.start() and range.end() respectively.
constexpr bool overlaps(Range range) const noexcept
Check whether the this range overlaps with range.
constexpr int columnWidth() const noexcept
Returns the number of columns separating the start() and end() positions.
constexpr bool onSingleLine() const noexcept
Check whether this range is wholly contained within one line, ie.
static constexpr Range invalid() noexcept
Returns an invalid range.
constexpr bool isValid() const noexcept
Validity check.
constexpr bool contains(Range range) const noexcept
Check whether the this range wholly encompasses range.
constexpr Range intersect(Range range) const noexcept
Intersects this range with another, returning the shared area of the two ranges.
void setBothLines(int line) noexcept
Convenience function.
constexpr int numberOfLines() const noexcept
Returns the number of lines separating the start() and end() positions.
void setStart(Cursor start) noexcept
Set the start cursor to start.
A text widget with KXMLGUIClient that represents a Document.
virtual QMenu * defaultContextMenu(QMenu *menu=nullptr) const =0
Populate menu with default text editor actions.
virtual bool setCursorPosition(Cursor position)=0
Set the view's new cursor to position.
virtual Document * document() const =0
Get the view's document, that means the view is a view of the returned document.
void focusIn(KTextEditor::View *view)
This signal is emitted whenever the view gets the focus.
void cursorPositionChanged(KTextEditor::View *view, KTextEditor::Cursor newPosition)
This signal is emitted whenever the view's cursor position changed.
virtual void setContextMenu(QMenu *menu)=0
Set a context menu for this view to menu.
Provides Auto-Indent functionality for katepart.
The KateBuffer class maintains a collections of lines.
void tagLines(KTextEditor::LineRange lineRange)
Emitted when the highlighting of a certain range has changed.
void configEnd()
End a config change transaction, update the concerned KateDocumentConfig/KateDocumentConfig/KateDocum...
void configStart()
Start some config changes.
bool setValue(const int key, const QVariant &value)
Set a config value.
File indentation detecter.
This dialog will prompt the user for what do with a file that is modified on disk.
Object to help to search for plain text.
This class can be used to efficiently search for occurrences of strings in a given string.
QString findPrefix(const QString &s, int start=0) const
Returns the shortest prefix of the given string that is contained in this prefix store starting at po...
Object to help to search for regexp.
static QString escapePlaintext(const QString &text)
Returns a modified version of text where escape sequences are resolved, e.g.
const QFont & currentFont() const
Access currently used font.
Inserts a template and offers advanced snippet features, like navigation and mirroring.
KateUndoManager implements a document's history.
Class for tracking editing actions.
Class representing a 'clever' text cursor.
Class representing a single text line.
int attribute(int pos) const
Gets the attribute at the given position use KRenderer::attributes to get the KTextAttribute for this...
const QString & text() const
Accessor to the text contained in this line.
bool endsWith(const QString &match) const
Returns true, if the line ends with match, otherwise returns false.
void setAutoWrapped(bool wrapped)
set auto-wrapped property
const QList< Attribute > & attributesList() const
Accessor to attributes.
int virtualLength(int tabWidth) const
Returns the text length with each tab expanded into tabWidth characters.
QString string(int column, int length) const
Returns the substring with length beginning at the given column.
int previousNonSpaceChar(int pos) const
Find the position of the previous char that is not a space.
int length() const
Returns the line's length.
bool isAutoWrapped() const
Returns true, if the line was automagically wrapped, otherwise returns false.
bool startsWith(const QString &match) const
Returns true, if the line starts with match, otherwise returns false.
int lastChar() const
Returns the position of the last non-whitespace character.
QChar at(int column) const
Returns the character at the given column.
int firstChar() const
Returns the position of the first non-whitespace character.
int toVirtualColumn(int column, int tabWidth) const
Returns the column with each tab expanded into tabWidth characters.
bool matchesAt(int column, const QString &match) const
Returns true, if match equals to the text at position column, otherwise returns false.
int nextNonSpaceChar(int pos) const
Find the position of the next char that is not a space.
int fromVirtualColumn(int column, int tabWidth) const
Returns the "real" column where each tab only counts one character.
Q_SCRIPTABLE Q_NOREPLY void start()
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KCALUTILS_EXPORT QString mimeType()
KCOREADDONS_EXPORT Result match(QStringView pattern, QStringView str)
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
KIOCORE_EXPORT FileCopyJob * file_copy(const QUrl &src, const QUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
ButtonCode warningTwoActionsCancel(QWidget *parent, const QString &text, const QString &title, const KGuiItem &primaryAction, const KGuiItem &secondaryAction, const KGuiItem &cancelAction=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Options(Notify|Dangerous))
QStringView merge(QStringView lhs, QStringView rhs)
bool isValid(QStringView ifopt)
KIOCORE_EXPORT QString dir(const QString &fileClass)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KCOREADDONS_EXPORT QString csqueeze(const QString &str, int maxlen=40)
The KTextEditor namespace contains all the public API that is required to use the KTextEditor compone...
@ CaseInsensitive
Ignores cases, e.g. "a" matches "A".
@ Regex
Treats the pattern as a regular expression.
@ Backwards
Searches in backward direction.
@ EscapeSequences
Plaintext mode: Processes escape sequences.
@ WholeWords
Plaintext mode: Whole words only, e.g. not "amp" in "example".
void triggered(bool checked)
QByteArray & append(QByteArrayView data)
bool isEmpty() const const
qsizetype size() const const
QByteArray toHex(char separator) const const
bool isHighSurrogate(char32_t ucs4)
bool isLowSurrogate(char32_t ucs4)
bool isNull() const const
bool isSpace(char32_t ucs4)
char32_t mirroredChar(char32_t ucs4)
char toLatin1() const const
char32_t toUpper(char32_t ucs4)
QColor fromString(QAnyStringView name)
bool isValid() const const
bool copy(const QString &fileName, const QString &newName)
bool exists() const const
QUrl getSaveFileUrl(QWidget *parent, const QString &caption, const QUrl &dir, const QString &filter, QString *selectedFilter, Options options, const QStringList &supportedSchemes)
QString canonicalFilePath() const const
bool isSymLink() const const
bool testFlag(Enum flag) const const
iterator find(const Key &key)
T value(const Key &key) const const
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
const_iterator cbegin() const const
const_iterator cend() const const
qsizetype count() const const
bool isEmpty() const const
void prepend(parameter_type value)
void push_back(parameter_type value)
void reserve(qsizetype size)
qsizetype size() const const
QString toLower(const QString &str) const const
QString toUpper(const QString &str) const const
QMimeType mimeTypeForData(QIODevice *device) const const
QMimeType mimeTypeForFile(const QFileInfo &fileInfo, MatchMode mode) const const
QMimeType mimeTypeForFileNameAndData(const QString &fileName, QIODevice *device) const const
bool disconnect(const QMetaObject::Connection &connection)
void setParent(QObject *parent)
int exitCode() const const
void setWorkingDirectory(const QString &dir)
void start(OpenMode mode)
bool waitForFinished(int msecs)
bool waitForStarted(int msecs)
QRegularExpressionMatch match(QStringView subjectView, qsizetype offset, MatchType matchType, MatchOptions matchOptions) const const
UnanchoredWildcardConversion
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
bool contains(const QSet< T > &other) const const
iterator insert(const T &value)
QString findExecutable(const QString &executableName, const QStringList &paths)
qsizetype count() const const
QString & append(QChar ch)
QString arg(Args &&... args) const const
const QChar at(qsizetype position) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString fromUtf8(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
bool isNull() const const
QString left(qsizetype n) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString repeated(qsizetype times) const const
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
void reserve(qsizetype size)
qsizetype size() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
QByteArray toLatin1() const const
QString toLower() const const
QString toUpper() const const
QString trimmed() const const
QString join(QChar separator) const const
QStringView mid(qsizetype start, qsizetype length) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
virtual QString fileName() const const override
int nextCursorPosition(int oldPos, CursorMode mode) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl adjusted(FormattingOptions options) const const
QString fileName(ComponentFormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
bool isLocalFile() const const
bool isValid() const const
QString path(ComponentFormattingOptions options) const const
QString toString(FormattingOptions options) const const
const_iterator cbegin() const const
const_iterator cend() const const
void reserve(qsizetype size)