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);
229 connect(&m_autoReloadThrottle, &
QTimer::timeout,
this, &DocumentPrivate::onModOnHdAutoReload);
245 if (m_bSingleViewMode && parentWidget) {
247 insertChildClient(view);
255 onTheFlySpellCheckingEnabled(config()->onTheFlySpellCheck());
260 m_autoSaveTimer.setSingleShot(
true);
262 if (isModified() && url().isLocalFile()) {
271KTextEditor::DocumentPrivate::~DocumentPrivate()
278 delete m_modOnHdHandler;
284 delete m_onTheFlyChecker;
285 m_onTheFlyChecker =
nullptr;
287 clearDictionaryRanges();
295 deactivateDirWatch();
306 for (
auto &
mark : std::as_const(m_marks)) {
321 if (m_editingStackPosition != m_editingStack.size() - 1) {
322 m_editingStack.resize(m_editingStackPosition);
326 std::shared_ptr<KTextEditor::MovingCursor> mc;
329 if (!m_editingStack.isEmpty() && cursor.
line() == m_editingStack.top()->line()) {
330 mc = m_editingStack.pop();
335 const int editingStackSizeLimit = 32;
336 if (m_editingStack.size() >= editingStackSizeLimit) {
338 m_editingStack.removeFirst();
340 mc = m_editingStack.takeFirst();
346 mc->setPosition(cursor);
348 mc = std::shared_ptr<KTextEditor::MovingCursor>(
newMovingCursor(cursor));
352 m_editingStack.push(mc);
353 m_editingStackPosition = m_editingStack.size() - 1;
358 if (m_editingStack.isEmpty()) {
361 auto targetPos = m_editingStack.at(m_editingStackPosition)->toCursor();
362 if (targetPos == currentCursor) {
363 if (nextOrPrev == Previous) {
364 m_editingStackPosition--;
366 m_editingStackPosition++;
368 m_editingStackPosition = qBound(0, m_editingStackPosition, m_editingStack.size() - 1);
370 return m_editingStack.at(m_editingStackPosition)->toCursor();
375 m_editingStack.clear();
376 m_editingStackPosition = -1;
383 if (!singleViewMode()) {
404 KTextEditor::ViewPrivate *newView =
new KTextEditor::ViewPrivate(
this,
parent, mainWindow);
406 if (m_fileChangedDialogsActivated) {
413 const auto keys = m_messageHash.keys();
415 if (!message->view()) {
416 newView->postMessage(message, m_messageHash[message]);
425 const int col1 = toVirtualColumn(range.
start());
426 const int col2 = toVirtualColumn(range.
end());
427 return KTextEditor::Range(line, fromVirtualColumn(line, col1), line, fromVirtualColumn(line, col2));
434 return editSessionNumber > 0;
439 return m_buffer->text();
445 qCWarning(LOG_KTE) <<
"Text requested for invalid range" << range;
464 }
else if (i == range.
end().
line()) {
486 return textLine.
at(position.
column());
501 const int lineLenth = textLine.
length();
502 if (cursor.
column() > lineLenth) {
512 while (end < lineLenth && highlight()->isInWord(textLine.
at(end), textLine.
attribute(end))) {
521 const int ln = cursor.
line();
522 const int col = cursor.
column();
529 Q_ASSERT(str.
length() >= col);
533 if (col == 0 || col == len) {
546 qCWarning(LOG_KTE) <<
"Text requested for invalid range" << range;
555 Q_ASSERT(range.
start() <= range.
end());
565 }
else if (i == range.
end().
line()) {
568 ret << textLine.
text();
586bool KTextEditor::DocumentPrivate::setText(
const QString &s)
588 if (!isReadWrite()) {
592 std::vector<KTextEditor::Mark> msave;
594 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(msave), [](
KTextEditor::Mark *mark) {
598 for (
auto v : std::as_const(m_views)) {
599 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
608 insertText(KTextEditor::Cursor(), s);
612 for (
auto v : std::as_const(m_views)) {
613 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
616 for (KTextEditor::Mark mark : msave) {
617 setMark(mark.line, mark.type);
623bool KTextEditor::DocumentPrivate::setText(
const QStringList &text)
625 if (!isReadWrite()) {
629 std::vector<KTextEditor::Mark> msave;
630 msave.reserve(m_marks.size());
631 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(msave), [](KTextEditor::Mark *mark) {
635 for (
auto v : std::as_const(m_views)) {
636 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
649 for (
auto v : std::as_const(m_views)) {
650 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
653 for (KTextEditor::Mark mark : msave) {
654 setMark(mark.line, mark.type);
660bool KTextEditor::DocumentPrivate::clear()
662 if (!isReadWrite()) {
666 for (
auto view : std::as_const(m_views)) {
667 static_cast<ViewPrivate *
>(view)->
clear();
668 static_cast<ViewPrivate *
>(view)->tagAll();
674 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
675 m_buffer->invalidateRanges();
677 Q_EMIT aboutToRemoveText(documentRange());
679 return editRemoveLines(0, lastLine());
682bool KTextEditor::DocumentPrivate::insertText(
const KTextEditor::Cursor position,
const QString &text,
bool block)
684 if (!isReadWrite()) {
698 auto insertStart = position;
699 int currentLine = position.
line();
700 int currentLineStart = 0;
701 const int totalLength = text.
length();
702 int insertColumn = position.
column();
705 if (position.
line() >= lines()) {
707 while (line <= position.
line()) {
708 editInsertLine(line, QString(),
false);
711 if (insertStart == position) {
712 insertStart = m_editLastChangeStartCursor;
720 int positionColumnExpanded = insertColumn;
721 const int tabWidth = config()->tabWidth();
723 if (currentLine < lines()) {
724 positionColumnExpanded = plainKateTextLine(currentLine).toVirtualColumn(insertColumn, tabWidth);
730 for (; pos < totalLength; pos++) {
731 const QChar &ch = text.
at(pos);
733 if (ch == QLatin1Char(
'\n')) {
735 if (currentLineStart < pos) {
736 editInsertText(currentLine, insertColumn, text.
mid(currentLineStart, pos - currentLineStart), notify);
737 endCol = insertColumn + (pos - currentLineStart);
742 const auto wrapColumn = insertColumn + pos - currentLineStart;
743 const auto currentLineLength = lineLength(currentLine);
744 if (wrapColumn > currentLineLength) {
745 editInsertText(currentLine, currentLineLength, QString(wrapColumn - currentLineLength, QLatin1Char(
' ')), notify);
749 editWrapLine(currentLine, wrapColumn,
true,
nullptr, notify);
757 auto l = currentLine < lines();
758 if (currentLine == lastLine() + 1) {
759 editInsertLine(currentLine, QString(), notify);
762 insertColumn = positionColumnExpanded;
764 insertColumn = plainKateTextLine(currentLine).fromVirtualColumn(insertColumn, tabWidth);
768 currentLineStart = pos + 1;
773 if (currentLineStart < pos) {
774 editInsertText(currentLine, insertColumn, text.
mid(currentLineStart, pos - currentLineStart), notify);
775 endCol = insertColumn + (pos - currentLineStart);
779 KTextEditor::Range insertedRange(insertStart, currentLine, endCol);
780 Q_EMIT textInsertedRange(
this, insertedRange);
786bool KTextEditor::DocumentPrivate::insertText(KTextEditor::Cursor position,
const QStringList &textLines,
bool block)
788 if (!isReadWrite()) {
793 return insertText(position, textLines.
join(QLatin1Char(
'\n')), block);
796bool KTextEditor::DocumentPrivate::removeText(KTextEditor::Range _range,
bool block)
798 KTextEditor::Range range = _range;
800 if (!isReadWrite()) {
812 Q_EMIT aboutToRemoveText(range);
818 if (range.
end().
line() > lastLine()) {
819 range.
setEnd(KTextEditor::Cursor(lastLine() + 1, 0));
829 if (to <= lastLine()) {
830 editRemoveText(to, 0, range.
end().
column());
839 editRemoveLines(from + 1, to - 1);
843 editRemoveText(from, range.
start().
column(), m_buffer->plainLine(from).length() - range.
start().
column());
844 editUnWrapLine(from);
849 int startLine = qMax(0, range.
start().
line());
850 int vc1 = toVirtualColumn(range.
start());
851 int vc2 = toVirtualColumn(range.
end());
852 for (
int line = qMin(range.
end().
line(), lastLine()); line >= startLine; --line) {
853 int col1 = fromVirtualColumn(line, vc1);
854 int col2 = fromVirtualColumn(line, vc2);
855 editRemoveText(line, qMin(col1, col2), qAbs(col2 - col1));
863bool KTextEditor::DocumentPrivate::insertLine(
int l,
const QString &str)
865 if (!isReadWrite()) {
869 if (l < 0 || l > lines()) {
873 return editInsertLine(l, str);
876bool KTextEditor::DocumentPrivate::insertLines(
int line,
const QStringList &text)
878 if (!isReadWrite()) {
882 if (line < 0 || line > lines()) {
887 for (
const QString &
string : text) {
888 success &= editInsertLine(line++,
string);
894bool KTextEditor::DocumentPrivate::removeLine(
int line)
896 if (!isReadWrite()) {
900 if (line < 0 || line > lastLine()) {
904 return editRemoveLine(line);
910 for (
int i = 0; i < m_buffer->lines(); ++i) {
911 l += m_buffer->lineLength(i);
918 return m_buffer->lines();
923 return m_buffer->lineLength(
line);
928 return m_buffer->cursorToOffset(c);
933 return m_buffer->offsetToCursor(offset);
938 if (line < 0 || line >=
lines()) {
943 return l.markedAsModified();
948 if (line < 0 || line >=
lines()) {
953 return l.markedAsSavedOnDisk();
958 if (line < 0 || line >=
lines()) {
963 return l.markedAsModified() || l.markedAsSavedOnDisk();
975 if (editSessionNumber > 1) {
979 editIsRunning =
true;
984 m_undoManager->editStart();
986 for (
auto view : std::as_const(m_views)) {
987 static_cast<ViewPrivate *
>(view)->
editStart();
990 m_buffer->editStart();
999 if (editSessionNumber == 0) {
1005 if (m_buffer->editChanged() && (editSessionNumber == 1)) {
1006 if (m_undoManager->isActive() &&
config()->wordWrap()) {
1007 wrapText(m_buffer->editTagStart(), m_buffer->editTagEnd());
1011 editSessionNumber--;
1013 if (editSessionNumber > 0) {
1019 m_buffer->editEnd();
1021 m_undoManager->editEnd();
1024 for (
auto view : std::as_const(m_views)) {
1025 static_cast<ViewPrivate *
>(view)->
editEnd(m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
1028 if (m_buffer->editChanged()) {
1036 if (m_editLastChangeStartCursor.isValid()) {
1040 if (
config()->autoSave() &&
config()->autoSaveInterval() > 0) {
1041 m_autoSaveTimer.start();
1044 editIsRunning =
false;
1048void KTextEditor::DocumentPrivate::pushEditState()
1050 editStateStack.push(editSessionNumber);
1053void KTextEditor::DocumentPrivate::popEditState()
1055 if (editStateStack.isEmpty()) {
1059 int count = editStateStack.pop() - editSessionNumber;
1070void KTextEditor::DocumentPrivate::inputMethodStart()
1072 m_undoManager->inputMethodStart();
1075void KTextEditor::DocumentPrivate::inputMethodEnd()
1077 m_undoManager->inputMethodEnd();
1082 if (startLine < 0 || endLine < 0) {
1090 int col =
config()->wordWrapAt();
1109 int eolPosition = l.
length() - 1;
1115 for (; z2 < l.
length(); z2++) {
1117 if (t.
at(z2) == tabChar) {
1118 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
1128 const int colInChars = qMin(z2, l.
length() - 1);
1129 int searchStart = colInChars;
1133 if (searchStart == eolPosition && t.
at(searchStart).
isSpace()) {
1145 for (z = searchStart; z >= 0; z--) {
1149 if ((nw < 0) && highlight()->canBreakAt(t.
at(z), l.
attribute(z))) {
1165 if ((nw >= 0) && nw < colInChars) {
1168 z = (nw >= 0) ? nw : colInChars;
1181 bool newLineAdded =
false;
1198 if (first == last) {
1202 if (first < 0 || last < first) {
1206 if (last >=
lines() || first > last) {
1226 curr->setPosition(curr->line() + 1, 0);
1232 curr->setPosition(
line, 0);
1238 first = curr->line() + 1;
1244 bool needWrap = (curr->line() != range->end().line());
1260 EDIT_DEBUG <<
"editInsertText" <<
line << col << s;
1262 if (
line < 0 || col < 0) {
1276 int length = l.length();
1285 if (col2 > length) {
1290 m_undoManager->slotTextInserted(
line, col2, s2, l);
1296 m_buffer->insertText(m_editLastChangeStartCursor, s2);
1309 EDIT_DEBUG <<
"editRemoveText" <<
line << col << len;
1311 if (line < 0 || line >=
lines() || col < 0 || len < 0) {
1332 len = qMin(len, l.
text().
size() - col);
1338 m_undoManager->slotTextRemoved(
line, col, oldText, l);
1356 EDIT_DEBUG <<
"editMarkLineAutoWrapped" <<
line << autowrapped;
1358 if (line < 0 || line >=
lines()) {
1368 m_undoManager->slotMarkLineAutoWrapped(
line, autowrapped);
1372 m_buffer->setLineMetaData(
line, l);
1382 EDIT_DEBUG <<
"editWrapLine" <<
line << col << newLine;
1384 if (line < 0 || line >=
lines() || col < 0) {
1398 m_undoManager->slotLineWrapped(
line, col, tl.length() - col, (!nextLineValid || newLine), tl);
1400 if (!nextLineValid || newLine) {
1404 for (
const auto &
mark : std::as_const(m_marks)) {
1406 if ((col == 0) || (
mark->line >
line)) {
1412 for (
const auto &
mark : list) {
1413 m_marks.take(
mark->line);
1416 for (
const auto &
mark : list) {
1421 if (!list.
empty()) {
1427 (*newLineAdded) =
true;
1431 m_buffer->unwrapLine(
line + 2);
1435 (*newLineAdded) =
false;
1454 EDIT_DEBUG <<
"editUnWrapLine" <<
line << removeLine << length;
1456 if (line < 0 || line >=
lines() ||
line + 1 >=
lines() || length < 0) {
1470 m_undoManager->slotLineUnWrapped(
line, col, length, removeLine, tl, nextLine);
1473 m_buffer->unwrapLine(
line + 1);
1476 m_buffer->unwrapLine(
line + 1);
1480 for (
const auto &
mark : std::as_const(m_marks)) {
1486 auto m = m_marks.take(
line);
1488 mark->type |= m->type;
1494 for (
const auto &
mark : list) {
1495 m_marks.take(
mark->line);
1498 for (
const auto &
mark : list) {
1520 EDIT_DEBUG <<
"editInsertLine" <<
line << s;
1536 m_undoManager->slotLineInserted(
line, s);
1550 for (
const auto &
mark : std::as_const(m_marks)) {
1556 for (
const auto &
mark : list) {
1557 m_marks.take(
mark->line);
1560 for (
const auto &
mark : list) {
1579 m_editLastChangeStartCursor = rangeInserted.
start();
1592 return editRemoveLines(
line,
line);
1595bool KTextEditor::DocumentPrivate::editRemoveLines(
int from,
int to)
1598 EDIT_DEBUG <<
"editRemoveLines" << from << to;
1600 if (to < from || from < 0 || to > lastLine()) {
1604 if (!isReadWrite()) {
1609 return editRemoveText(0, 0, lineLength(0));
1613 QStringList oldText;
1616 for (
int line = to; line >= from; --line) {
1617 const Kate::TextLine l = plainKateTextLine(line);
1619 m_undoManager->slotLineRemoved(line, l.
text(), l);
1621 m_buffer->removeText(KTextEditor::Range(KTextEditor::Cursor(line, 0), KTextEditor::Cursor(line, l.
length())));
1625 for (
int line = to; line >= from; --line) {
1627 if (line + 1 < m_buffer->lines()) {
1628 m_buffer->unwrapLine(line + 1);
1630 m_buffer->unwrapLine(line);
1634 QVarLengthArray<int, 8> rmark;
1635 QVarLengthArray<KTextEditor::Mark *, 8>
list;
1637 for (KTextEditor::Mark *mark : std::as_const(m_marks)) {
1638 int line = mark->line;
1641 }
else if (line >= from) {
1646 for (
int line : rmark) {
1647 delete m_marks.take(line);
1650 for (
auto mark : list) {
1651 m_marks.take(mark->line);
1654 for (
auto mark : list) {
1655 mark->line -= to - from + 1;
1656 m_marks.insert(mark->line, mark);
1660 Q_EMIT marksChanged(
this);
1663 KTextEditor::Range rangeRemoved(from, 0, to + 1, 0);
1665 if (to == lastLine() + to - from + 1) {
1666 rangeRemoved.setEnd(KTextEditor::Cursor(to, oldText.
last().length()));
1668 int prevLineLength = lineLength(from - 1);
1669 rangeRemoved.setStart(KTextEditor::Cursor(from - 1, prevLineLength));
1674 m_editLastChangeStartCursor = rangeRemoved.start();
1676 Q_EMIT textRemoved(
this, rangeRemoved, oldText.
join(QLatin1Char(
'\n')) + QLatin1Char(
'\n'));
1685uint KTextEditor::DocumentPrivate::undoCount()
const
1687 return m_undoManager->undoCount();
1690uint KTextEditor::DocumentPrivate::redoCount()
const
1692 return m_undoManager->redoCount();
1695void KTextEditor::DocumentPrivate::undo()
1697 for (
auto v : std::as_const(m_views)) {
1698 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
1701 m_undoManager->undo();
1703 for (
auto v : std::as_const(m_views)) {
1704 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
1708void KTextEditor::DocumentPrivate::redo()
1710 for (
auto v : std::as_const(m_views)) {
1711 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
true);
1714 m_undoManager->redo();
1716 for (
auto v : std::as_const(m_views)) {
1717 static_cast<KTextEditor::ViewPrivate *
>(v)->completionWidget()->setIgnoreBufferSignals(
false);
1723QList<KTextEditor::Range>
1724KTextEditor::DocumentPrivate::searchText(KTextEditor::Range range,
const QString &pattern,
const KTextEditor::SearchOptions options)
const
1739 KateRegExpSearch searcher(
this);
1740 return searcher.search(pattern, range, backwards, patternOptions);
1743 if (escapeSequences) {
1745 KatePlainTextSearch searcher(
this, caseSensitivity, wholeWords);
1748 QList<KTextEditor::Range> result;
1754 KatePlainTextSearch searcher(
this, caseSensitivity, wholeWords);
1755 KTextEditor::Range
match = searcher.search(pattern, range, backwards);
1757 QList<KTextEditor::Range> result;
1763QWidget *KTextEditor::DocumentPrivate::dialogParent()
1765 QWidget *w = widget();
1780QUrl KTextEditor::DocumentPrivate::getSaveFileUrl(
const QString &dialogTitle)
1807 for (KateFileType *type : modeList) {
1816 int mode = KateHlManager::self()->nameFind(name);
1820 m_buffer->setHighlight(
mode);
1826 return highlight()->name();
1831 const auto modeList = KateHlManager::self()->modeList();
1834 for (
const auto &hl : modeList) {
1842 return KateHlManager::self()->modeList().
at(index).section();
1850void KTextEditor::DocumentPrivate::bufferHlChanged()
1856 m_indenter->checkRequiredStyle();
1858 Q_EMIT highlightingModeChanged(
this);
1863 m_hlSetByUser =
true;
1868 m_bomSetByUser =
true;
1875 if (!flags.
contains(QStringLiteral(
"SkipEncoding"))) {
1883 if (!flags.
contains(QStringLiteral(
"SkipUrl"))) {
1888 if (!
url.isEmpty() &&
url.isValid()) {
1898 if (!flags.
contains(QStringLiteral(
"SkipMode")) && kconfig.
hasKey(
"Mode Set By User")) {
1902 if (!flags.
contains(QStringLiteral(
"SkipHighlighting"))) {
1904 if (kconfig.
hasKey(
"Highlighting Set By User")) {
1905 const int mode = KateHlManager::self()->nameFind(kconfig.
readEntry(
"Highlighting"));
1906 m_hlSetByUser =
true;
1909 m_buffer->setHighlight(
mode);
1916 if (!userSetIndentMode.
isEmpty()) {
1917 config()->setIndentationMode(userSetIndentMode);
1922 for (
int i = 0; i <
marks.count(); i++) {
1932 if (this->
url().isLocalFile()) {
1933 const QString path = this->
url().toLocalFile();
1939 if (!flags.
contains(QStringLiteral(
"SkipUrl"))) {
1951 if (m_fileTypeSetByUser && !flags.
contains(QStringLiteral(
"SkipMode"))) {
1952 kconfig.
writeEntry(
"Mode Set By User",
true);
1956 if (m_hlSetByUser && !flags.
contains(QStringLiteral(
"SkipHighlighting"))) {
1958 kconfig.
writeEntry(
"Highlighting", highlight()->name());
1961 kconfig.
writeEntry(
"Highlighting Set By User", m_hlSetByUser);
1965 if (m_indenterSetByUser) {
1971 for (
const auto &
mark : std::as_const(m_marks)) {
1977 if (!
marks.isEmpty()) {
1994void KTextEditor::DocumentPrivate::setMark(
int line, uint markType)
1997 addMark(line, markType);
2000void KTextEditor::DocumentPrivate::clearMark(
int line)
2002 if (line < 0 || line > lastLine()) {
2006 if (
auto mark = m_marks.take(line)) {
2007 Q_EMIT markChanged(
this, *mark, MarkRemoved);
2008 Q_EMIT marksChanged(
this);
2015void KTextEditor::DocumentPrivate::addMark(
int line, uint markType)
2017 KTextEditor::Mark *mark;
2019 if (line < 0 || line > lastLine()) {
2023 if (markType == 0) {
2027 if ((mark = m_marks.value(line))) {
2029 markType &= ~mark->type;
2031 if (markType == 0) {
2036 mark->
type |= markType;
2038 mark =
new KTextEditor::Mark;
2040 mark->
type = markType;
2041 m_marks.insert(line, mark);
2045 KTextEditor::Mark temp;
2047 temp.
type = markType;
2048 Q_EMIT markChanged(
this, temp, MarkAdded);
2050 Q_EMIT marksChanged(
this);
2055void KTextEditor::DocumentPrivate::removeMark(
int line, uint markType)
2057 if (line < 0 || line > lastLine()) {
2061 auto it = m_marks.find(line);
2062 if (it == m_marks.end()) {
2065 KTextEditor::Mark *mark = it.value();
2068 markType &= mark->
type;
2070 if (markType == 0) {
2075 mark->
type &= ~markType;
2078 KTextEditor::Mark temp;
2080 temp.
type = markType;
2081 Q_EMIT markChanged(
this, temp, MarkRemoved);
2083 if (mark->
type == 0) {
2088 Q_EMIT marksChanged(
this);
2098void KTextEditor::DocumentPrivate::requestMarkTooltip(
int line,
QPoint position)
2105 bool handled =
false;
2106 Q_EMIT markToolTipRequested(
this, *mark, position, handled);
2111 bool handled =
false;
2124 bool handled =
false;
2144 for (
const auto &m : marksCopy) {
2156 m_markDescriptions.insert(type, description);
2162 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
2163 return KateRendererConfig::global()->lineMarkerColor(type);
2171 return m_markDescriptions.value(type,
QString());
2174void KTextEditor::DocumentPrivate::setEditableMarks(uint markMask)
2176 m_editableMarks = markMask;
2181 return m_editableMarks;
2187 m_markIcons.insert(markType, icon);
2192 return m_markIcons.value(markType,
QIcon());
2196bool KTextEditor::DocumentPrivate::print()
2198 return KatePrinter::print(
this);
2201void KTextEditor::DocumentPrivate::printPreview()
2203 KatePrinter::printPreview(
this);
2210 if (!m_modOnHd &&
url().isLocalFile()) {
2218 for (
int i = 0; (i <
lines()) && (buf.
size() <= 4096); ++i) {
2234void KTextEditor::DocumentPrivate::showAndSetOpeningErrorAccess()
2237 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.",
2240 message->setWordWrap(
true);
2242 i18nc(
"translators: you can also translate 'Try Again' with 'Reload'",
"Try Again"),
2247 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
2250 message->addAction(tryAgainAction);
2251 message->addAction(closeAction);
2254 postMessage(message);
2257 m_openingError =
true;
2261void KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride()
2264 const int longestLine = m_buffer->longestLineLoaded();
2265 int newLimit = pow(2, ceil(log2(longestLine)));
2266 if (newLimit <= longestLine) {
2271 config()->setLineLengthLimit(newLimit);
2276 if (!m_openingError) {
2278 m_readWriteStateBeforeLoading =
true;
2284 return config()->lineLengthLimit();
2294 m_openingError =
false;
2307 if (pos != -1 && !(m_reloading && m_userSetEncodingForNextReload)) {
2319 if (m_reloading && m_userSetEncodingForNextReload && (currentEncoding !=
encoding())) {
2323 bool success = m_buffer->openFile(
localFilePath(), (m_reloading && m_userSetEncodingForNextReload));
2336 for (
auto view : std::as_const(m_views)) {
2339 static_cast<ViewPrivate *
>(view)->updateView(
true);
2358 if (!
isEmpty() &&
config()->autoDetectIndent() && !
config()->isSet(KateDocumentConfig::IndentationWidth)
2359 && !
config()->isSet(KateDocumentConfig::ReplaceTabsWithSpaces)) {
2361 auto result = detecter.detect(
config()->indentationWidth(),
config()->replaceTabsDyn());
2362 config()->setIndentationWidth(result.indentWidth);
2363 config()->setReplaceTabsDyn(result.indentUsingSpaces);
2370 showAndSetOpeningErrorAccess();
2374 if (m_buffer->brokenEncoding()) {
2376 setReadWrite(
false);
2377 m_readWriteStateBeforeLoading =
false;
2379 i18n(
"The file %1 was opened with %2 encoding but contained invalid characters.<br />"
2380 "It is set to read-only mode, as saving might destroy its content.<br />"
2381 "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.",
2383 m_buffer->textCodec()),
2385 message->setWordWrap(
true);
2389 m_openingError =
true;
2393 if (m_buffer->tooLongLinesWrapped()) {
2395 setReadWrite(
false);
2396 m_readWriteStateBeforeLoading =
false;
2398 new KTextEditor::Message(
i18n(
"The file %1 was opened and contained lines longer than the configured Line Length Limit (%2 characters).<br />"
2399 "The longest of those lines was %3 characters long<br/>"
2400 "Those lines were wrapped and the document is set to read-only mode, as saving will modify its content.",
2403 m_buffer->longestLineLoaded()),
2405 QAction *increaseAndReload =
new QAction(
i18n(
"Temporarily raise limit and reload file"), message);
2406 connect(increaseAndReload, &
QAction::triggered,
this, &KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride);
2407 message->addAction(increaseAndReload,
true);
2408 message->addAction(
new QAction(
i18n(
"Close"), message),
true);
2409 message->setWordWrap(
true);
2413 m_openingError =
true;
2425 delete m_modOnHdHandler;
2429 if (m_fileChangedDialogsActivated && m_modOnHd) {
2435 str +
i18n(
"Do you really want to save this unmodified file? You could overwrite changed data in the file on disk."),
2436 i18n(
"Trying to Save Unmodified File"),
2446 "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."),
2447 i18n(
"Possible Data Loss"),
2459 if (!m_buffer->canEncode()
2461 i18n(
"The selected encoding cannot encode every Unicode character in this document. Do you really want to save "
2462 "it? There could be some data lost."),
2463 i18n(
"Possible Data Loss"),
2471 if (!createBackupFile()) {
2476 QString oldPath = m_dirWatchFile;
2482 if (
url().isLocalFile()) {
2489 const bool variablesWereRead = readVariables();
2495 if (!variablesWereRead) {
2496 for (
auto *view : std::as_const(m_views)) {
2497 auto v =
static_cast<ViewPrivate *
>(view);
2498 if (v->isVisible()) {
2499 const auto range = v->visibleRange();
2501 bool repaint =
false;
2510 v->updateView(
true);
2517 deactivateDirWatch();
2522 removeTrailingSpacesAndAddNewLineAtEof();
2529 activateDirWatch(oldPath);
2531 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 "
2532 "that enough disk space is available.\nThe original file may be lost or damaged. "
2533 "Don't quit the application until the file is successfully written.",
2556 m_undoManager->undoSafePoint();
2557 m_undoManager->updateLineModifications();
2565bool KTextEditor::DocumentPrivate::createBackupFile()
2568 const bool backupLocalFiles = config()->backupOnSaveLocal();
2569 const bool backupRemoteFiles = config()->backupOnSaveRemote();
2573 if (!backupLocalFiles && !backupRemoteFiles) {
2580 bool needBackup = backupLocalFiles && backupRemoteFiles;
2582 bool slowOrRemoteFile = !u.isLocalFile();
2583 if (!slowOrRemoteFile) {
2587 slowOrRemoteFile = (mountPoint && mountPoint->probablySlow());
2589 needBackup = (!slowOrRemoteFile && backupLocalFiles) || (slowOrRemoteFile && backupRemoteFiles);
2600 if (backupPrefix.isEmpty() && backupSuffix.isEmpty()) {
2607 u.setPath(backupPrefix + u.fileName() + backupSuffix);
2610 const QString fileName = u.fileName();
2612 u.setPath(u.path() + backupPrefix + fileName + backupSuffix);
2615 qCDebug(LOG_KTE) <<
"backup src file name: " << url();
2616 qCDebug(LOG_KTE) <<
"backup dst file name: " << u;
2619 bool backupSuccess =
false;
2622 if (u.isLocalFile()) {
2625 QFile backupFile(u.toLocalFile());
2626 if (backupFile.exists()) {
2627 backupFile.remove();
2630 backupSuccess =
QFile::copy(url().toLocalFile(), u.toLocalFile());
2632 backupSuccess =
true;
2638 if (statJob->
exec()) {
2640 KFileItem item(statJob->
statResult(), url());
2643 backupSuccess = job->
exec();
2645 backupSuccess =
true;
2652 i18n(
"For file %1 no backup copy could be created before saving."
2653 " If an error occurs while saving, you might lose the data of this file."
2654 " A reason could be that the media you write to is full or the directory of the file is read-only for you.",
2656 i18n(
"Failed to create backup copy."),
2657 KGuiItem(
i18n(
"Try to Save Nevertheless")),
2659 QStringLiteral(
"Backup Failed Warning"))
2667void KTextEditor::DocumentPrivate::readDirConfig(KTextEditor::ViewPrivate *v)
2675 QSet<QString> seenDirectories;
2676 QDir
dir(QFileInfo(localFilePath()).absolutePath());
2677 while (!seenDirectories.
contains(
dir.absolutePath())) {
2679 seenDirectories.
insert(
dir.absolutePath());
2682 QFile f(
dir.absolutePath() + QLatin1String(
"/.kateconfig"));
2684 QTextStream stream(&f);
2687 QString line = stream.readLine();
2688 while ((linesRead < 32) && !line.
isNull()) {
2689 readVariableLine(line, v);
2691 line = stream.readLine();
2705#if EDITORCONFIG_FOUND
2707 if (!v && config()->value(KateDocumentConfig::UseEditorConfig).toBool()) {
2711 EditorConfig editorConfig(
this);
2712 editorConfig.parse();
2717void KTextEditor::DocumentPrivate::activateDirWatch(
const QString &useFileName)
2719 QString fileToUse = useFileName;
2721 fileToUse = localFilePath();
2728 QFileInfo fileInfo = QFileInfo(fileToUse);
2735 if (fileToUse == m_dirWatchFile) {
2740 deactivateDirWatch();
2743 if (url().isLocalFile() && !fileToUse.
isEmpty()) {
2745 m_dirWatchFile = fileToUse;
2749void KTextEditor::DocumentPrivate::deactivateDirWatch()
2751 if (!m_dirWatchFile.isEmpty()) {
2755 m_dirWatchFile.clear();
2758bool KTextEditor::DocumentPrivate::openUrl(
const QUrl &url)
2762 m_fileTypeSetByUser =
false;
2769bool KTextEditor::DocumentPrivate::closeUrl()
2774 if (!m_reloading && !url().isEmpty()) {
2775 if (m_fileChangedDialogsActivated && m_modOnHd) {
2777 delete m_modOnHdHandler;
2779 QWidget *parentWidget(dialogParent());
2781 reasonedMOHString() + QLatin1String(
"\n\n")
2782 +
i18n(
"Do you really want to continue to close this file? Data loss may occur."),
2783 i18n(
"Possible Data Loss"),
2784 KGuiItem(
i18n(
"Close Nevertheless")),
2786 QStringLiteral(
"kate_close_modonhd_%1").arg(m_modOnHdReason))
2789 m_reloading =
false;
2800 m_reloading =
false;
2806 Q_EMIT aboutToClose(
this);
2810 if (!m_messageHash.isEmpty()) {
2811 const auto keys = m_messageHash.keys();
2812 for (KTextEditor::Message *message : keys) {
2818 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
2821 deactivateDirWatch();
2824 setLocalFilePath(QString());
2829 m_modOnHdReason = OnDiskUnmodified;
2830 m_prevModOnHdReason = OnDiskUnmodified;
2831 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
2841 m_undoManager->clearUndo();
2842 m_undoManager->clearRedo();
2848 m_buffer->setHighlight(0);
2851 for (
auto view : std::as_const(m_views)) {
2852 static_cast<ViewPrivate *
>(view)->clearSelection();
2853 static_cast<ViewPrivate *
>(view)->
clear();
2858 m_swapfile->fileClosed();
2867 return m_swapfile && m_swapfile->shouldRecover();
2873 m_swapfile->recover();
2880 m_swapfile->discard();
2884void KTextEditor::DocumentPrivate::setReadWrite(
bool rw)
2886 if (isReadWrite() == rw) {
2892 for (
auto v : std::as_const(m_views)) {
2893 auto view =
static_cast<ViewPrivate *
>(v);
2894 view->slotUpdateUndo();
2895 view->slotReadWriteChanged();
2898 Q_EMIT readWriteChanged(
this);
2903 if (isModified() != m) {
2906 for (
auto view : std::as_const(m_views)) {
2907 static_cast<ViewPrivate *
>(view)->slotUpdateUndo();
2910 Q_EMIT modifiedChanged(
this);
2913 m_undoManager->setModified(m);
2919void KTextEditor::DocumentPrivate::makeAttribs(
bool needInvalidate)
2921 for (
auto view : std::as_const(m_views)) {
2922 static_cast<ViewPrivate *
>(view)->renderer()->updateAttributes();
2925 if (needInvalidate) {
2926 m_buffer->invalidateHighlighting();
2929 for (
auto v : std::as_const(m_views)) {
2930 auto view =
static_cast<ViewPrivate *
>(v);
2932 view->updateView(
true);
2937void KTextEditor::DocumentPrivate::internalHlChanged()
2942void KTextEditor::DocumentPrivate::addView(KTextEditor::View *view)
2944 Q_ASSERT(!m_views.contains(view));
2945 m_views.append(view);
2946 auto *v =
static_cast<KTextEditor::ViewPrivate *
>(view);
2949 if (!m_fileType.isEmpty()) {
2958 setActiveView(view);
2963 Q_ASSERT(m_views.contains(view));
2964 m_views.removeAll(view);
2966 if (activeView() == view) {
2967 setActiveView(
nullptr);
2973 if (m_activeView == view) {
2977 m_activeView =
static_cast<KTextEditor::ViewPrivate *
>(view);
2980bool KTextEditor::DocumentPrivate::ownedView(KTextEditor::ViewPrivate *view)
2983 return (m_views.contains(view));
2986int KTextEditor::DocumentPrivate::toVirtualColumn(
int line,
int column)
const
2988 Kate::TextLine textLine = m_buffer->plainLine(line);
2992int KTextEditor::DocumentPrivate::toVirtualColumn(
const KTextEditor::Cursor cursor)
const
2994 return toVirtualColumn(cursor.
line(), cursor.
column());
2997int KTextEditor::DocumentPrivate::fromVirtualColumn(
int line,
int column)
const
2999 Kate::TextLine textLine = m_buffer->plainLine(line);
3003int KTextEditor::DocumentPrivate::fromVirtualColumn(
const KTextEditor::Cursor cursor)
const
3005 return fromVirtualColumn(cursor.
line(), cursor.
column());
3008bool KTextEditor::DocumentPrivate::skipAutoBrace(QChar closingBracket, KTextEditor::Cursor pos)
3014 bool skipAutobrace = closingBracket == QLatin1Char(
'\'');
3015 if (highlight() && skipAutobrace) {
3017 skipAutobrace = highlight()->spellCheckingRequiredForLocation(
this, pos -
Cursor{0, 1});
3020 if (!skipAutobrace && (closingBracket == QLatin1Char(
'\''))) {
3022 Kate::TextLine textLine = m_buffer->plainLine(pos.
line());
3024 static const QRegularExpression re(QStringLiteral(
"(?<!\\\\)(?:\\\\\\\\)*\\\'"));
3026 skipAutobrace = (count % 2 == 0) ?
true : false;
3028 if (!skipAutobrace && (closingBracket == QLatin1Char(
'\"'))) {
3030 Kate::TextLine textLine = m_buffer->plainLine(pos.
line());
3031 static const QRegularExpression re(QStringLiteral(
"(?<!\\\\)(?:\\\\\\\\)*\\\""));
3033 skipAutobrace = (count % 2 == 0) ?
true : false;
3035 return skipAutobrace;
3046 QChar closingBracket;
3047 if (view->config()->autoBrackets()) {
3049 const QChar typedChar = chars.
at(0);
3050 const QChar openBracket = matchingStartBracket(typedChar);
3051 if (!openBracket.
isNull()) {
3053 if ((
characterAt(curPos) == typedChar) && findMatchingBracket(curPos, 123 ).isValid()) {
3055 view->cursorRight();
3061 if (chars.
size() == 1) {
3063 closingBracket = matchingEndBracket(typedChar);
3066 if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) {
3068 m_currentAutobraceRange.reset(
nullptr);
3069 view->cursorRight();
3076 if (view->selection() && closingBracket.
isNull() && view->config()->encloseSelectionInChars()) {
3077 const QChar typedChar = chars.
at(0);
3078 if (view->config()->charsToEncloseSelection().
contains(typedChar)) {
3087 if (view->selection() && !closingBracket.
isNull()) {
3088 std::unique_ptr<KTextEditor::MovingRange> selectionRange(
newMovingRange(view->selectionRange()));
3089 const int startLine = qMax(0, selectionRange->start().line());
3090 const int endLine = qMin(selectionRange->end().line(),
lastLine());
3091 const bool blockMode = view->blockSelection() && (startLine != endLine);
3093 if (selectionRange->start().column() > selectionRange->end().column()) {
3099 const int startColumn = qMin(selectionRange->start().column(), selectionRange->end().column());
3100 const int endColumn = qMax(selectionRange->start().column(), selectionRange->end().column());
3104 insertText(r.
end(),
QString(closingBracket));
3105 view->slotTextInserted(view, r.
end(),
QString(closingBracket));
3106 insertText(r.
start(), chars);
3107 view->slotTextInserted(view, r.
start(), chars);
3111 for (
const auto &cursor : view->secondaryCursors()) {
3112 if (!cursor.range) {
3115 const auto &currSelectionRange = cursor.range;
3116 auto expandBehaviour = currSelectionRange->insertBehaviors();
3118 insertText(currSelectionRange->end(),
QString(closingBracket));
3119 insertText(currSelectionRange->start(), chars);
3120 currSelectionRange->setInsertBehaviors(expandBehaviour);
3121 cursor.pos->setPosition(currSelectionRange->end());
3122 auto mutableCursor =
const_cast<KTextEditor::ViewPrivate::SecondaryCursor *
>(&cursor);
3123 mutableCursor->anchor = currSelectionRange->start().toCursor();
3127 insertText(selectionRange->end(),
QString(closingBracket));
3128 view->slotTextInserted(view, selectionRange->end(),
QString(closingBracket));
3129 insertText(selectionRange->start(), chars);
3130 view->slotTextInserted(view, selectionRange->start(), chars);
3134 view->setSelection(selectionRange->toRange());
3135 view->setCursorPosition(selectionRange->end());
3142 if (!view->config()->persistentSelection() && view->selection()) {
3143 view->removeSelectedText();
3148 const bool multiLineBlockMode = view->blockSelection() && view->selection();
3149 if (view->currentInputMode()->overwrite()) {
3152 const int startLine = multiLineBlockMode ? qMax(0, selectionRange.
start().
line()) : view->cursorPosition().
line();
3153 const int endLine = multiLineBlockMode ? qMin(selectionRange.
end().
line(),
lastLine()) : startLine;
3154 const int virtualColumn = toVirtualColumn(multiLineBlockMode ? selectionRange.
end() : view->cursorPosition());
3158 const int column = fromVirtualColumn(
line, virtualColumn);
3164 view->currentInputMode()->overwrittenChar(removed);
3171 chars = eventuallyReplaceTabs(view->cursorPosition(), chars);
3173 if (multiLineBlockMode) {
3175 const int startLine = qMax(0, selectionRange.
start().
line());
3177 const int column = toVirtualColumn(selectionRange.
end());
3181 int newSelectionColumn = toVirtualColumn(view->cursorPosition());
3184 view->setSelection(selectionRange);
3189 view->completionWidget()->setIgnoreBufferSignals(
true);
3190 const auto &sc = view->secondaryCursors();
3192 const bool hasClosingBracket = !closingBracket.
isNull();
3193 const QString closingChar = closingBracket;
3195 std::vector<std::pair<Kate::TextCursor *, KTextEditor::Cursor>> freezedCursors;
3196 for (
auto it = sc.begin(); it != sc.end(); ++it) {
3197 auto pos = it->cursor();
3198 if (it != sc.begin() && pos == std::prev(it)->cursor()) {
3199 freezedCursors.push_back({std::prev(it)->pos.get(), std::prev(it)->cursor()});
3202 lastInsertionCursor = pos;
3203 insertText(pos, chars);
3206 if (it->cursor() == view->cursorPosition()) {
3207 freezedCursors.push_back({it->pos.get(), it->cursor()});
3210 const auto nextChar = view->document()->
text({pos, pos +
Cursor{0, 1}}).trimmed();
3211 if (hasClosingBracket && !skipAutoBrace(closingBracket, pos) && (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber())) {
3212 insertText(it->cursor(), closingChar);
3213 it->pos->setPosition(pos);
3217 view->completionWidget()->setIgnoreBufferSignals(
false);
3219 insertText(view->cursorPosition(), chars);
3221 for (
auto &freezed : freezedCursors) {
3222 freezed.first->setPosition(freezed.second);
3230 if (!closingBracket.
isNull() && !skipAutoBrace(closingBracket, view->cursorPosition())) {
3232 const auto cursorPos = view->cursorPosition();
3233 const auto nextChar = view->document()->
text({cursorPos, cursorPos +
Cursor{0, 1}}).trimmed();
3234 if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) {
3235 insertText(view->cursorPosition(),
QString(closingBracket));
3236 const auto insertedAt(view->cursorPosition());
3237 view->setCursorPosition(cursorPos);
3242 chars.
append(closingBracket);
3244 m_currentAutobraceClosingChar = closingBracket;
3251 const auto &secondaryCursors = view->secondaryCursors();
3252 for (
const auto &c : secondaryCursors) {
3253 m_indenter->userTypedChar(view, c.cursor(), chars.
isEmpty() ?
QChar() : chars.
at(chars.
length() - 1));
3261 view->slotTextInserted(view, oldCur, chars);
3266 if (m_currentAutobraceRange && !m_currentAutobraceRange->toRange().contains(newPos)) {
3267 m_currentAutobraceRange.reset();
3271void KTextEditor::DocumentPrivate::newLine(KTextEditor::ViewPrivate *v, KTextEditor::DocumentPrivate::NewLineIndent indent, NewLinePos newLinePos)
3275 if (!v->config()->persistentSelection() && v->selection()) {
3276 v->removeSelectedText();
3277 v->clearSelection();
3280 auto insertNewLine = [
this](KTextEditor::Cursor c) {
3281 if (c.line() > lastLine()) {
3282 c.setLine(lastLine());
3291 int len = lineLength(ln);
3293 if (c.column() > len) {
3298 editWrapLine(c.line(), c.column());
3301 m_buffer->updateHighlighting();
3306 auto adjustCusorPos = [newLinePos,
this](KTextEditor::Cursor pos) {
3308 bool moveCursorToTop =
false;
3309 if (newLinePos == Above) {
3310 if (pos.
line() <= 0) {
3313 moveCursorToTop =
true;
3318 }
else if (newLinePos == Below) {
3319 int lastCol = lineLength(pos.
line());
3322 return std::pair{pos, moveCursorToTop};
3326 const auto &secondaryCursors = v->secondaryCursors();
3327 if (!secondaryCursors.empty()) {
3330 for (
const auto &c : secondaryCursors) {
3331 const auto [newPos, moveCursorToTop] = adjustCusorPos(c.cursor());
3332 c.pos->setPosition(newPos);
3333 insertNewLine(c.cursor());
3334 if (moveCursorToTop) {
3335 c.pos->setPosition({0, 0});
3338 if (indent == KTextEditor::DocumentPrivate::Indent) {
3342 v->setCursorPosition(c.cursor());
3343 m_indenter->userTypedChar(v, c.cursor(), QLatin1Char(
'\n'));
3345 c.pos->setPosition(v->cursorPosition());
3349 v->setCursorPosition(savedPrimary.toCursor());
3352 const auto [newPos, moveCursorToTop] = adjustCusorPos(v->cursorPosition());
3353 v->setCursorPosition(newPos);
3354 insertNewLine(v->cursorPosition());
3355 if (moveCursorToTop) {
3356 v->setCursorPosition({0, 0});
3359 if (indent == KTextEditor::DocumentPrivate::Indent) {
3360 m_indenter->userTypedChar(v, v->cursorPosition(), QLatin1Char(
'\n'));
3366void KTextEditor::DocumentPrivate::transpose(
const KTextEditor::Cursor cursor)
3368 Kate::TextLine textLine = m_buffer->plainLine(cursor.
line());
3369 if (textLine.
length() < 2) {
3373 uint col = cursor.
column();
3379 if ((textLine.
length() - col) < 2) {
3383 uint line = cursor.
line();
3394 editRemoveText(line, col, 2);
3395 editInsertText(line, col, s);
3399void KTextEditor::DocumentPrivate::swapTextRanges(KTextEditor::Range firstWord, KTextEditor::Range secondWord)
3402 Q_ASSERT(!firstWord.
overlaps(secondWord));
3405 const KTextEditor::Range tempRange = firstWord;
3410 const QString tempString = text(secondWord);
3413 replaceText(secondWord, text(firstWord));
3414 replaceText(firstWord, tempString);
3418KTextEditor::Cursor KTextEditor::DocumentPrivate::backspaceAtCursor(KTextEditor::ViewPrivate *view, KTextEditor::Cursor c)
3420 int col = qMax(c.
column(), 0);
3421 int line = qMax(c.
line(), 0);
3422 if ((col == 0) && (line == 0)) {
3425 if (line >= lines()) {
3429 const Kate::TextLine textLine = m_buffer->plainLine(line);
3432 bool useNextBlock =
false;
3433 if (config()->backspaceIndents()) {
3440 if (pos < 0 || pos >= (
int)colX) {
3442 if ((
int)col > textLine.
length()) {
3444 return KTextEditor::Cursor(line, col - 1);
3446 indent(KTextEditor::Range(line, 0, line, 0), -1);
3448 useNextBlock =
true;
3451 if (!config()->backspaceIndents() || useNextBlock) {
3452 KTextEditor::Cursor beginCursor(line, 0);
3453 KTextEditor::Cursor endCursor(line, col);
3454 if (!view->config()->backspaceRemoveComposed()) {
3455 beginCursor.setColumn(col - 1);
3457 if (!isValidTextPosition(beginCursor)) {
3459 beginCursor.setColumn(col - 2);
3462 if (
auto l = view->textLayout(c)) {
3463 beginCursor.setColumn(l->previousCursorPosition(c.
column()));
3466 removeText(KTextEditor::Range(beginCursor, endCursor));
3474 const Kate::TextLine textLine = m_buffer->plainLine(line - 1);
3478 if (config()->wordWrap() && textLine.
endsWith(QStringLiteral(
" "))) {
3480 ret = KTextEditor::Cursor(line - 1, textLine.
length() - 1);
3481 removeText(KTextEditor::Range(line - 1, textLine.
length() - 1, line, 0));
3483 ret = KTextEditor::Cursor(line - 1, textLine.
length());
3484 removeText(KTextEditor::Range(line - 1, textLine.
length(), line, 0));
3491void KTextEditor::DocumentPrivate::backspace(KTextEditor::ViewPrivate *view)
3493 if (!view->config()->persistentSelection() && view->hasSelections()) {
3494 KTextEditor::Range range = view->selectionRange();
3497 if (view->blockSelection() && view->selection() && range.
start().
column() > 0 && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3500 view->setSelection(range);
3502 view->removeSelectedText();
3503 view->ensureUniqueCursors();
3511 const auto &multiCursors = view->secondaryCursors();
3512 view->completionWidget()->setIgnoreBufferSignals(
true);
3513 for (
const auto &c : multiCursors) {
3514 const auto newPos = backspaceAtCursor(view, c.cursor());
3519 view->completionWidget()->setIgnoreBufferSignals(
false);
3522 auto newPos = backspaceAtCursor(view, view->cursorPosition());
3524 view->setCursorPosition(newPos);
3527 view->ensureUniqueCursors();
3532 if (m_currentAutobraceRange) {
3533 const auto r = m_currentAutobraceRange->toRange();
3534 if (r.columnWidth() == 1 && view->cursorPosition() == r.
start()) {
3536 del(view, view->cursorPosition());
3537 m_currentAutobraceRange.reset();
3542void KTextEditor::DocumentPrivate::del(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor c)
3544 if (!view->config()->persistentSelection() && view->selection()) {
3545 KTextEditor::Range range = view->selectionRange();
3547 if (view->blockSelection() && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3550 view->setSelection(range);
3552 view->removeSelectedText();
3557 if (c.
column() < m_buffer->lineLength(c.
line())) {
3559 removeText(KTextEditor::Range(c, endCursor));
3560 }
else if (c.
line() < lastLine()) {
3561 removeText(KTextEditor::Range(c.
line(), c.
column(), c.
line() + 1, 0));
3565bool KTextEditor::DocumentPrivate::multiPaste(KTextEditor::ViewPrivate *view,
const QStringList &texts)
3567 if (texts.
isEmpty() || view->isMulticursorNotAllowed() || view->secondaryCursors().size() + 1 != (
size_t)texts.
size()) {
3571 m_undoManager->undoSafePoint();
3574 if (view->selection()) {
3575 view->removeSelectedText();
3578 auto plainSecondaryCursors = view->plainSecondaryCursors();
3579 KTextEditor::ViewPrivate::PlainSecondaryCursor primary;
3580 primary.pos = view->cursorPosition();
3581 primary.range = view->selectionRange();
3582 plainSecondaryCursors.append(primary);
3583 std::sort(plainSecondaryCursors.begin(), plainSecondaryCursors.end());
3585 static const QRegularExpression re(QStringLiteral(
"\r\n?"));
3587 for (
int i = texts.
size() - 1; i >= 0; --i) {
3588 QString text = texts[i];
3589 text.
replace(re, QStringLiteral(
"\n"));
3590 KTextEditor::Cursor pos = plainSecondaryCursors[i].pos;
3592 insertText(pos, text,
false);
3600void KTextEditor::DocumentPrivate::paste(KTextEditor::ViewPrivate *view,
const QString &text)
3610 s.
replace(QRegularExpression(QStringLiteral(
"\r\n?")), QStringLiteral(
"\n"));
3612 int lines = s.
count(QLatin1Char(
'\n'));
3613 const bool isSingleLine = lines == 0;
3615 m_undoManager->undoSafePoint();
3619 KTextEditor::Cursor pos = view->cursorPosition();
3621 bool skipIndentOnPaste =
false;
3623 const int length = lineLength(pos.
line());
3625 skipIndentOnPaste = length > 0;
3628 if (!view->config()->persistentSelection() && view->selection()) {
3629 pos = view->selectionRange().
start();
3630 if (view->blockSelection()) {
3631 pos = rangeOnLine(view->selectionRange(), pos.
line()).
start();
3633 s += QLatin1Char(
'\n');
3638 view->removeSelectedText();
3641 if (config()->ovr()) {
3642 const auto pasteLines = QStringView(s).split(QLatin1Char(
'\n'));
3644 if (!view->blockSelection()) {
3645 int endColumn = (pasteLines.count() == 1 ? pos.
column() : 0) + pasteLines.last().length();
3646 removeText(KTextEditor::Range(pos, pos.
line() + pasteLines.count() - 1, endColumn));
3648 int maxi = qMin(pos.
line() + pasteLines.count(), this->lines());
3650 for (
int i = pos.
line(); i < maxi; ++i) {
3651 int pasteLength = pasteLines.at(i - pos.
line()).length();
3652 removeText(KTextEditor::Range(i, pos.
column(), i, qMin(pasteLength + pos.
column(), lineLength(i))));
3657 insertText(pos, s, view->blockSelection());
3664 if (view->blockSelection()) {
3665 view->setCursorPositionInternal(pos);
3668 if (config()->indentPastedText()) {
3669 KTextEditor::Range range = KTextEditor::Range(KTextEditor::Cursor(pos.
line(), 0), KTextEditor::Cursor(pos.
line() + lines, 0));
3670 if (!skipIndentOnPaste) {
3671 m_indenter->indent(view, range);
3675 if (!view->blockSelection()) {
3676 Q_EMIT charactersSemiInteractivelyInserted(pos, s);
3678 m_undoManager->undoSafePoint();
3681void KTextEditor::DocumentPrivate::indent(KTextEditor::Range range,
int change)
3683 if (!isReadWrite()) {
3688 m_indenter->changeIndent(range, change);
3692void KTextEditor::DocumentPrivate::align(KTextEditor::ViewPrivate *view, KTextEditor::Range range)
3694 m_indenter->indent(view, range);
3697void KTextEditor::DocumentPrivate::alignOn(KTextEditor::Range range,
const QString &pattern,
bool blockwise)
3699 QStringList lines = textLines(range, blockwise);
3701 if (lines.
size() < 2) {
3705 QRegularExpression re(pattern.
isEmpty() ? QStringLiteral(
"[^\\s]") : pattern);
3707 int selectionStartColumn = range.
start().
column();
3708 QList<int> patternStartColumns;
3709 for (
const auto &line : lines) {
3710 QRegularExpressionMatch
match = re.match(line);
3711 if (!
match.hasMatch()) {
3712 patternStartColumns.
append(-1);
3713 }
else if (
match.lastCapturedIndex() == 0) {
3714 patternStartColumns.
append(
match.capturedStart(0) + (blockwise ? selectionStartColumn : 0));
3716 patternStartColumns.
append(
match.capturedStart(1) + (blockwise ? selectionStartColumn : 0));
3719 if (!blockwise && patternStartColumns[0] != -1) {
3720 patternStartColumns[0] += selectionStartColumn;
3723 int maxColumn = *std::max_element(patternStartColumns.
cbegin(), patternStartColumns.
cend());
3726 for (
int i = 0; i < lines.size(); ++i) {
3727 if (patternStartColumns[i] != -1) {
3728 insertText(KTextEditor::Cursor(range.
start().
line() + i, patternStartColumns[i]), QString(maxColumn - patternStartColumns[i],
QChar::Space));
3734void KTextEditor::DocumentPrivate::insertTab(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor)
3736 if (!isReadWrite()) {
3740 int lineLen = line(view->cursorPosition().
line()).length();
3741 KTextEditor::Cursor c = view->cursorPosition();
3745 if (!view->config()->persistentSelection() && view->selection()) {
3746 view->removeSelectedText();
3747 }
else if (view->currentInputMode()->overwrite() && c.
column() < lineLen) {
3748 KTextEditor::Range r = KTextEditor::Range(view->cursorPosition(), 1);
3751 QChar removed = line(view->cursorPosition().
line()).at(r.
start().
column());
3752 view->currentInputMode()->overwrittenChar(removed);
3756 c = view->cursorPosition();
3757 editInsertText(c.
line(), c.
column(), QStringLiteral(
"\t"));
3766bool KTextEditor::DocumentPrivate::removeStringFromBeginning(
int line,
const QString &str)
3768 Kate::TextLine textline = m_buffer->plainLine(line);
3770 KTextEditor::Cursor cursor(line, 0);
3780 removeText(KTextEditor::Range(cursor, str.
length()));
3790bool KTextEditor::DocumentPrivate::removeStringFromEnd(
int line,
const QString &str)
3792 Kate::TextLine textline = m_buffer->plainLine(line);
3794 KTextEditor::Cursor cursor(line, 0);
3795 bool there = textline.
endsWith(str);
3806 removeText(KTextEditor::Range(cursor, str.
length()));
3815QString KTextEditor::DocumentPrivate::eventuallyReplaceTabs(
const KTextEditor::Cursor cursorPos,
const QString &str)
const
3817 const bool replacetabs = config()->replaceTabsDyn();
3821 const int indentWidth = config()->indentationWidth();
3822 static const QLatin1Char tabChar(
'\t');
3824 int column = cursorPos.
column();
3830 for (
const QChar ch : str) {
3831 if (ch == tabChar) {
3834 int spacesToInsert = indentWidth - (column % indentWidth);
3835 result += QString(spacesToInsert, QLatin1Char(
' '));
3836 column += spacesToInsert;
3849void KTextEditor::DocumentPrivate::addStartLineCommentToSingleLine(
int line,
int attrib)
3851 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) + QLatin1Char(
' ');
3854 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3855 const Kate::TextLine l = kateTextLine(line);
3858 insertText(KTextEditor::Cursor(line, pos), commentLineMark);
3865bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSingleLine(
int line,
int attrib)
3867 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
3868 const QString longCommentMark = shortCommentMark + QLatin1Char(
' ');
3873 bool removed = (removeStringFromBeginning(line, longCommentMark) || removeStringFromBeginning(line, shortCommentMark));
3884void KTextEditor::DocumentPrivate::addStartStopCommentToSingleLine(
int line,
int attrib)
3886 const QString startCommentMark = highlight()->getCommentStart(attrib) + QLatin1Char(
' ');
3887 const QString stopCommentMark = QLatin1Char(
' ') + highlight()->getCommentEnd(attrib);
3892 insertText(KTextEditor::Cursor(line, 0), startCommentMark);
3895 const int col = m_buffer->lineLength(line);
3898 insertText(KTextEditor::Cursor(line, col), stopCommentMark);
3907bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSingleLine(
int line,
int attrib)
3909 const QString shortStartCommentMark = highlight()->getCommentStart(attrib);
3910 const QString longStartCommentMark = shortStartCommentMark + QLatin1Char(
' ');
3911 const QString shortStopCommentMark = highlight()->getCommentEnd(attrib);
3912 const QString longStopCommentMark = QLatin1Char(
' ') + shortStopCommentMark;
3917 const bool removedStart = (removeStringFromBeginning(line, longStartCommentMark) || removeStringFromBeginning(line, shortStartCommentMark));
3920 const bool removedStop = removedStart && (removeStringFromEnd(line, longStopCommentMark) || removeStringFromEnd(line, shortStopCommentMark));
3924 return (removedStart || removedStop);
3931void KTextEditor::DocumentPrivate::addStartStopCommentToSelection(KTextEditor::Range selection,
bool blockSelection,
int attrib)
3933 const QString startComment = highlight()->getCommentStart(attrib);
3934 const QString endComment = highlight()->getCommentEnd(attrib);
3936 KTextEditor::Range range = selection;
3944 if (!blockSelection) {
3945 insertText(range.
end(), endComment);
3946 insertText(range.
start(), startComment);
3948 for (
int line = range.
start().
line(); line <= range.
end().
line(); line++) {
3949 KTextEditor::Range subRange = rangeOnLine(range, line);
3950 insertText(subRange.
end(), endComment);
3951 insertText(subRange.
start(), startComment);
3962void KTextEditor::DocumentPrivate::addStartLineCommentToSelection(KTextEditor::Range selection,
int attrib)
3965 int el = selection.
end().
line();
3968 if ((selection.
end().
column() == 0) && (el > 0)) {
3972 if (sl < 0 || el < 0 || sl >= lines() || el >= lines()) {
3978 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) + QLatin1Char(
' ');
3981 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3989 col = std::numeric_limits<int>::max();
3991 for (
int l = el; l >= sl; l--) {
3992 const auto line = plainKateTextLine(l);
3993 if (line.length() == 0) {
3996 col = qMin(col, qMax(0, line.firstChar()));
4003 if (col == std::numeric_limits<int>::max()) {
4010 for (
int l = el; l >= sl; l--) {
4011 insertText(KTextEditor::Cursor(l, col), commentLineMark);
4017bool KTextEditor::DocumentPrivate::nextNonSpaceCharPos(
int &line,
int &col)
4019 for (; line >= 0 && line < m_buffer->lines(); line++) {
4020 Kate::TextLine textLine = m_buffer->plainLine(line);
4033bool KTextEditor::DocumentPrivate::previousNonSpaceCharPos(
int &line,
int &col)
4035 while (line >= 0 && line < m_buffer->lines()) {
4036 Kate::TextLine textLine = m_buffer->plainLine(line);
4057bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSelection(KTextEditor::Range selection,
int attrib)
4059 const QString startComment = highlight()->getCommentStart(attrib);
4060 const QString endComment = highlight()->getCommentEnd(attrib);
4062 int sl = qMax<int>(0, selection.
start().
line());
4063 int el = qMin<int>(selection.
end().
line(), lastLine());
4070 }
else if (el > 0) {
4072 ec = m_buffer->lineLength(el) - 1;
4075 const int startCommentLen = startComment.
length();
4076 const int endCommentLen = endComment.
length();
4080 bool remove = nextNonSpaceCharPos(sl, sc) && m_buffer->plainLine(sl).matchesAt(sc, startComment) && previousNonSpaceCharPos(el, ec)
4081 && ((ec - endCommentLen + 1) >= 0) && m_buffer->plainLine(el).matchesAt(ec - endCommentLen + 1, endComment);
4086 removeText(KTextEditor::Range(el, ec - endCommentLen + 1, el, ec + 1));
4087 removeText(KTextEditor::Range(sl, sc, sl, sc + startCommentLen));
4096bool KTextEditor::DocumentPrivate::removeStartStopCommentFromRegion(
const KTextEditor::Cursor
start,
const KTextEditor::Cursor end,
int attrib)
4098 const QString startComment = highlight()->getCommentStart(attrib);
4099 const QString endComment = highlight()->getCommentEnd(attrib);
4100 const int startCommentLen = startComment.
length();
4101 const int endCommentLen = endComment.
length();
4103 const bool remove = m_buffer->plainLine(
start.line()).matchesAt(
start.column(), startComment)
4104 && m_buffer->plainLine(
end.line()).matchesAt(
end.column() - endCommentLen, endComment);
4107 removeText(KTextEditor::Range(
end.line(),
end.column() - endCommentLen,
end.line(),
end.column()));
4108 removeText(KTextEditor::Range(
start, startCommentLen));
4118bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSelection(KTextEditor::Range selection,
int attrib,
bool toggleComment)
4120 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
4121 const QString longCommentMark = shortCommentMark + QLatin1Char(
' ');
4123 const int startLine = selection.
start().
line();
4124 int endLine = selection.
end().
line();
4126 if ((selection.
end().
column() == 0) && (endLine > 0)) {
4130 bool removed =
false;
4136 if (toggleComment) {
4137 bool allLinesAreCommented =
true;
4138 for (
int line = endLine; line >= startLine; line--) {
4139 const auto ln = m_buffer->plainLine(line);
4140 const QString &text = ln.text();
4145 QStringView textView(text.
data(), text.
size());
4147 textView = textView.trimmed();
4148 if (!textView.startsWith(shortCommentMark) && !textView.startsWith(longCommentMark)) {
4149 allLinesAreCommented =
false;
4153 if (!allLinesAreCommented) {
4161 for (
int z = endLine; z >= startLine; z--) {
4163 removed = (removeStringFromBeginning(z, longCommentMark) || removeStringFromBeginning(z, shortCommentMark) || removed);
4172void KTextEditor::DocumentPrivate::commentSelection(KTextEditor::Range selection, KTextEditor::Cursor c,
bool blockSelect, CommentType changeType)
4174 const bool hasSelection = !selection.
isEmpty();
4175 int selectionCol = 0;
4180 const int line = c.
line();
4182 int startAttrib = 0;
4183 Kate::TextLine ln = kateTextLine(line);
4185 if (selectionCol < ln.
length()) {
4186 startAttrib = ln.
attribute(selectionCol);
4191 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart(startAttrib).isEmpty());
4192 bool hasStartStopCommentMark = (!(highlight()->getCommentStart(startAttrib).isEmpty()) && !(highlight()->getCommentEnd(startAttrib).isEmpty()));
4194 if (changeType == Comment) {
4195 if (!hasSelection) {
4196 if (hasStartLineCommentMark) {
4197 addStartLineCommentToSingleLine(line, startAttrib);
4198 }
else if (hasStartStopCommentMark) {
4199 addStartStopCommentToSingleLine(line, startAttrib);
4209 const KTextEditor::Range sel = selection;
4210 if (hasStartStopCommentMark
4211 && (!hasStartLineCommentMark
4214 addStartStopCommentToSelection(selection, blockSelect, startAttrib);
4215 }
else if (hasStartLineCommentMark) {
4216 addStartLineCommentToSelection(selection, startAttrib);
4220 bool removed =
false;
4221 const bool toggleComment = changeType == ToggleComment;
4222 if (!hasSelection) {
4223 removed = (hasStartLineCommentMark && removeStartLineCommentFromSingleLine(line, startAttrib))
4224 || (hasStartStopCommentMark && removeStartStopCommentFromSingleLine(line, startAttrib));
4227 removed = (hasStartStopCommentMark && removeStartStopCommentFromSelection(selection, startAttrib))
4228 || (hasStartLineCommentMark && removeStartLineCommentFromSelection(selection, startAttrib, toggleComment));
4232 if (!removed && toggleComment) {
4233 commentSelection(selection, c, blockSelect, Comment);
4242void KTextEditor::DocumentPrivate::comment(KTextEditor::ViewPrivate *v, uint line, uint column, CommentType change)
4245 const bool skipWordWrap = wordWrap();
4252 if (v->selection()) {
4253 const auto &cursors = v->secondaryCursors();
4254 for (
const auto &c : cursors) {
4258 commentSelection(c.range->toRange(), c.cursor(),
false, change);
4260 KTextEditor::Cursor c(line, column);
4261 commentSelection(v->selectionRange(), c, v->blockSelection(), change);
4263 const auto &cursors = v->secondaryCursors();
4264 for (
const auto &c : cursors) {
4265 commentSelection({}, c.cursor(),
false, change);
4267 commentSelection({}, KTextEditor::Cursor(line, column),
false, change);
4277void KTextEditor::DocumentPrivate::transformCursorOrRange(KTextEditor::ViewPrivate *v,
4278 KTextEditor::Cursor c,
4279 KTextEditor::Range selection,
4280 KTextEditor::DocumentPrivate::TextTransform t)
4282 if (v->selection()) {
4285 KTextEditor::Range range(selection.
start(), 0);
4294 if (range.
start().
line() == selection.
end().
line() || v->blockSelection()) {
4299 int swapCol =
start;
4306 QString s = text(range);
4309 if (t == Uppercase) {
4312 }
else if (t == Lowercase) {
4316 Kate::TextLine l = m_buffer->plainLine(range.
start().
line());
4325 && !highlight()->isInWord(l.
at(range.
start().
column() - 1)))
4326 || (p && !highlight()->isInWord(s.
at(p - 1)))) {
4335 insertText(range.
start(), s);
4346 KTextEditor::Cursor cursor = c;
4348 QString old = text(KTextEditor::Range(cursor, 1));
4358 Kate::TextLine l = m_buffer->plainLine(cursor.
line());
4362 old = text(KTextEditor::Range(cursor, 1));
4369 removeText(KTextEditor::Range(cursor, 1));
4370 insertText(cursor, s);
4380 if (v->selection()) {
4381 const auto &cursors = v->secondaryCursors();
4382 for (
const auto &c : cursors) {
4386 auto pos = c.pos->toCursor();
4387 transformCursorOrRange(v, c.anchor, c.range->toRange(), t);
4391 const auto selRange = v->selectionRange();
4392 transformCursorOrRange(v, c, v->selectionRange(), t);
4393 v->setSelection(selRange);
4394 v->setCursorPosition(c);
4396 const auto &secondaryCursors = v->secondaryCursors();
4397 for (
const auto &c : secondaryCursors) {
4398 transformCursorOrRange(v, c.cursor(), {}, t);
4400 transformCursorOrRange(v, c, {}, t);
4411 while (first < last) {
4446 for (
auto view : std::as_const(m_views)) {
4447 static_cast<ViewPrivate *
>(view)->tagLines(lineRange,
true);
4451void KTextEditor::DocumentPrivate::tagLine(
int line)
4453 tagLines({line, line});
4456void KTextEditor::DocumentPrivate::repaintViews(
bool paintOnlyDirty)
4458 for (
auto view : std::as_const(m_views)) {
4459 static_cast<ViewPrivate *
>(view)->repaintText(paintOnlyDirty);
4470KTextEditor::Range KTextEditor::DocumentPrivate::findMatchingBracket(
const KTextEditor::Cursor
start,
int maxLines)
4472 if (maxLines < 0 ||
start.line() < 0 ||
start.line() >= lines()) {
4476 Kate::TextLine textLine = m_buffer->plainLine(
start.line());
4482 if (config()->ovr()) {
4483 if (isBracket(right)) {
4488 }
else if (isBracket(right)) {
4490 }
else if (isBracket(left)) {
4497 const QChar opposite = matchingBracket(bracket);
4502 const int searchDir = isStartBracket(bracket) ? 1 : -1;
4505 const int minLine = qMax(range.
start().
line() - maxLines, 0);
4506 const int maxLine = qMin(range.
start().
line() + maxLines, documentEnd().line());
4509 KTextEditor::DocumentCursor cursor(
this);
4511 int validAttr = kateTextLine(cursor.
line()).attribute(cursor.
column());
4513 while (cursor.
line() >= minLine && cursor.
line() <= maxLine) {
4514 if (!cursor.move(searchDir)) {
4518 Kate::TextLine textLine = kateTextLine(cursor.
line());
4521 QChar c = textLine.
at(cursor.
column());
4522 if (c == opposite) {
4524 if (searchDir > 0) {
4525 range.
setEnd(cursor.toCursor());
4532 }
else if (c == bracket) {
4542inline static QString removeNewLines(
const QString &str)
4545 return tmp.replace(QLatin1String(
"\r\n"), QLatin1String(
" ")).replace(QLatin1Char(
'\r'), QLatin1Char(
' ')).replace(QLatin1Char(
'\n'), QLatin1Char(
' '));
4548void KTextEditor::DocumentPrivate::updateDocName()
4551 if (!url().isEmpty() && (m_docName == removeNewLines(url().fileName()) || m_docName.
startsWith(removeNewLines(url().fileName()) + QLatin1String(
" (")))) {
4557 std::vector<KTextEditor::DocumentPrivate *> docsWithSameName;
4560 for (KTextEditor::Document *kteDoc : docs) {
4561 auto doc =
static_cast<KTextEditor::DocumentPrivate *
>(kteDoc);
4562 if ((doc !=
this) && (doc->url().fileName() == url().fileName())) {
4563 if (doc->m_docNameNumber > count) {
4564 count = doc->m_docNameNumber;
4566 docsWithSameName.push_back(doc);
4570 m_docNameNumber = count + 1;
4572 QString oldName = m_docName;
4573 m_docName = removeNewLines(url().fileName());
4575 m_isUntitled = m_docName.isEmpty();
4577 if (!m_isUntitled && !docsWithSameName.empty()) {
4578 docsWithSameName.push_back(
this);
4579 uniquifyDocNames(docsWithSameName);
4584 m_docName =
i18n(
"Untitled");
4587 if (m_docNameNumber > 0) {
4588 m_docName = QString(m_docName + QLatin1String(
" (%1)")).arg(m_docNameNumber + 1);
4592 if (oldName != m_docName) {
4593 Q_EMIT documentNameChanged(
this);
4608static QString shortestPrefix(
const std::vector<QString> &urls, KTextEditor::DocumentPrivate *doc)
4611 int lastSlash = url.lastIndexOf(QLatin1Char(
'/'));
4612 if (lastSlash == -1) {
4616 int fileNameStart = lastSlash;
4619 lastSlash = url.lastIndexOf(QLatin1Char(
'/'), lastSlash);
4620 if (lastSlash == -1) {
4623 return url.mid(lastSlash, fileNameStart);
4626 QStringView urlView = url;
4627 QStringView urlv = url;
4628 urlv = urlv.
mid(lastSlash);
4630 for (
size_t i = 0; i < urls.size(); ++i) {
4631 if (urls[i] == url) {
4635 if (urls[i].endsWith(urlv)) {
4636 lastSlash = url.lastIndexOf(QLatin1Char(
'/'), lastSlash - 1);
4637 if (lastSlash <= 0) {
4639 return url.mid(0, fileNameStart);
4642 urlv = urlView.
mid(lastSlash);
4647 return url.mid(lastSlash + 1, fileNameStart - (lastSlash + 1));
4650void KTextEditor::DocumentPrivate::uniquifyDocNames(
const std::vector<KTextEditor::DocumentPrivate *> &docs)
4652 std::vector<QString> paths;
4653 paths.reserve(docs.size());
4654 std::transform(docs.begin(), docs.end(), std::back_inserter(paths), [](
const KTextEditor::DocumentPrivate *d) {
4655 return d->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
4658 for (
const auto doc : docs) {
4659 const QString prefix = shortestPrefix(paths, doc);
4661 const QString oldName = doc->m_docName;
4664 doc->m_docName = fileName + QStringLiteral(
" - ") + prefix;
4666 doc->m_docName = fileName;
4669 if (doc->m_docName != oldName) {
4682 onModOnHdAutoReload();
4686 if (!m_fileChangedDialogsActivated || m_modOnHdHandler) {
4691 if (m_modOnHdReason == m_prevModOnHdReason) {
4694 m_prevModOnHdReason = m_modOnHdReason;
4696 m_modOnHdHandler =
new KateModOnHdPrompt(
this, m_modOnHdReason, reasonedMOHString());
4697 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::saveAsTriggered,
this, &DocumentPrivate::onModOnHdSaveAs);
4698 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::closeTriggered,
this, &DocumentPrivate::onModOnHdClose);
4699 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::reloadTriggered,
this, &DocumentPrivate::onModOnHdReload);
4700 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::autoReloadTriggered,
this, &DocumentPrivate::onModOnHdAutoReload);
4701 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::ignoreTriggered,
this, &DocumentPrivate::onModOnHdIgnore);
4704void KTextEditor::DocumentPrivate::onModOnHdSaveAs()
4707 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
4713 delete m_modOnHdHandler;
4714 m_prevModOnHdReason = OnDiskUnmodified;
4715 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4722void KTextEditor::DocumentPrivate::onModOnHdClose()
4728 m_fileChangedDialogsActivated =
false;
4733 m_fileChangedDialogsActivated =
true;
4738void KTextEditor::DocumentPrivate::onModOnHdReload()
4741 m_prevModOnHdReason = OnDiskUnmodified;
4742 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4748 m_undoManager->clearUndo();
4749 m_undoManager->clearRedo();
4752 delete m_modOnHdHandler;
4755void KTextEditor::DocumentPrivate::autoReloadToggled(
bool b)
4757 m_autoReloadMode->setChecked(b);
4761 disconnect(&m_modOnHdTimer, &
QTimer::timeout,
this, &DocumentPrivate::onModOnHdAutoReload);
4765bool KTextEditor::DocumentPrivate::isAutoReload()
4767 return m_autoReloadMode->isChecked();
4770void KTextEditor::DocumentPrivate::delayAutoReload()
4772 if (isAutoReload()) {
4773 m_autoReloadThrottle.start();
4777void KTextEditor::DocumentPrivate::onModOnHdAutoReload()
4779 if (m_modOnHdHandler) {
4780 delete m_modOnHdHandler;
4781 autoReloadToggled(
true);
4784 if (!isAutoReload()) {
4788 if (m_modOnHd && !m_reloading && !m_autoReloadThrottle.isActive()) {
4790 m_prevModOnHdReason = OnDiskUnmodified;
4791 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4795 m_undoManager->clearUndo();
4796 m_undoManager->clearRedo();
4799 m_autoReloadThrottle.start();
4803void KTextEditor::DocumentPrivate::onModOnHdIgnore()
4806 delete m_modOnHdHandler;
4811 m_modOnHdReason = reason;
4816class KateDocumentTmpMark
4825 m_fileChangedDialogsActivated = on;
4842 m_undoManager->clearUndo();
4843 m_undoManager->clearRedo();
4848 delete m_modOnHdHandler;
4854 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(tmp), [
this](
KTextEditor::Mark *
mark) {
4855 return KateDocumentTmpMark{.line = line(mark->line), .mark = *mark};
4859 const QString oldMode = mode();
4860 const bool modeByUser = m_fileTypeSetByUser;
4861 const QString oldHlMode = highlightingMode();
4862 const bool hlByUser = m_hlSetByUser;
4864 m_storedVariables.clear();
4868 std::transform(m_views.cbegin(), m_views.cend(), std::back_inserter(cursorPositions), [](
KTextEditor::View *v) {
4869 return std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor>(static_cast<ViewPrivate *>(v), v->cursorPosition());
4874 for (
auto *view : m_views) {
4875 static_cast<ViewPrivate *
>(view)->clearSecondaryCursors();
4878 static_cast<ViewPrivate *
>(view)->clearFoldingState();
4883 KTextEditor::DocumentPrivate::openUrl(url());
4886 m_userSetEncodingForNextReload =
false;
4889 for (
auto v : std::as_const(m_views)) {
4891 auto it = std::find_if(cursorPositions.
cbegin(), cursorPositions.
cend(), [v](
const std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor> &p) {
4892 return p.first == v;
4894 v->setCursorPosition(it->second);
4900 const int lines = this->lines();
4901 for (
const auto &tmpMark : tmp) {
4902 if (tmpMark.mark.line < lines) {
4903 if (tmpMark.line == line(tmpMark.mark.line)) {
4904 setMark(tmpMark.mark.line, tmpMark.mark.type);
4911 updateFileType(oldMode,
true);
4914 setHighlightingMode(oldHlMode);
4917 Q_EMIT reloaded(
this);
4922bool KTextEditor::DocumentPrivate::documentSave()
4924 if (!url().
isValid() || !isReadWrite()) {
4925 return documentSaveAs();
4931bool KTextEditor::DocumentPrivate::documentSaveAs()
4933 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4941bool KTextEditor::DocumentPrivate::documentSaveAsWithEncoding(
const QString &encoding)
4943 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4948 setEncoding(encoding);
4952void KTextEditor::DocumentPrivate::documentSaveCopyAs()
4954 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save Copy of File"));
4959 QTemporaryFile *file =
new QTemporaryFile();
4960 if (!file->
open()) {
4964 if (!m_buffer->saveFile(file->
fileName())) {
4966 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 "
4967 "that enough disk space is available.",
4975 const auto url = this->url();
4977 if (
auto sj = qobject_cast<KIO::StatJob *>(j)) {
4978 const int permissions = KFileItem(sj->statResult(), url).permissions();
4988void KTextEditor::DocumentPrivate::setWordWrap(
bool on)
4990 config()->setWordWrap(on);
4993bool KTextEditor::DocumentPrivate::wordWrap()
const
4995 return config()->wordWrap();
4998void KTextEditor::DocumentPrivate::setWordWrapAt(uint col)
5000 config()->setWordWrapAt(col);
5003unsigned int KTextEditor::DocumentPrivate::wordWrapAt()
const
5005 return config()->wordWrapAt();
5008void KTextEditor::DocumentPrivate::setPageUpDownMovesCursor(
bool on)
5010 config()->setPageUpDownMovesCursor(on);
5013bool KTextEditor::DocumentPrivate::pageUpDownMovesCursor()
const
5015 return config()->pageUpDownMovesCursor();
5021 return m_config->setEncoding(e);
5026 return m_config->encoding();
5029void KTextEditor::DocumentPrivate::updateConfig()
5031 m_undoManager->updateConfig();
5034 m_indenter->setMode(m_config->indentationMode());
5035 m_indenter->updateConfig();
5038 m_buffer->setTabWidth(config()->tabWidth());
5041 for (
auto view : std::as_const(m_views)) {
5042 static_cast<ViewPrivate *
>(view)->updateDocumentConfig();
5046 if (m_onTheFlyChecker) {
5047 m_onTheFlyChecker->updateConfig();
5050 if (config()->autoSave()) {
5051 int interval = config()->autoSaveInterval();
5052 if (interval == 0) {
5053 m_autoSaveTimer.stop();
5055 m_autoSaveTimer.setInterval(interval * 1000);
5057 m_autoSaveTimer.start();
5062 Q_EMIT configChanged(
this);
5072bool KTextEditor::DocumentPrivate::readVariables(KTextEditor::ViewPrivate *view)
5074 const bool hasVariableline = [
this] {
5075 const QLatin1String s(
"kate");
5077 for (
int i = qMax(10, lines() - 10); i < lines(); ++i) {
5078 if (line(i).contains(s)) {
5083 for (
int i = 0; i < qMin(9, lines()); ++i) {
5084 if (line(i).contains(s)) {
5090 if (!hasVariableline) {
5095 m_config->configStart();
5096 for (
auto view : std::as_const(m_views)) {
5097 auto v =
static_cast<ViewPrivate *
>(view);
5108 for (
int i = 0; i < qMin(9, lines()); ++i) {
5109 readVariableLine(line(i), view);
5112 for (
int i = qMax(10, lines() - 10); i < lines(); i++) {
5113 readVariableLine(line(i), view);
5118 m_config->configEnd();
5119 for (
auto view : std::as_const(m_views)) {
5120 auto v =
static_cast<ViewPrivate *
>(view);
5132void KTextEditor::DocumentPrivate::readVariableLine(
const QString &t, KTextEditor::ViewPrivate *view)
5134 static const QRegularExpression kvLine(QStringLiteral(
"kate:(.*)"));
5135 static const QRegularExpression kvLineWildcard(QStringLiteral(
"kate-wildcard\\((.*)\\):(.*)"));
5136 static const QRegularExpression kvLineMime(QStringLiteral(
"kate-mimetype\\((.*)\\):(.*)"));
5137 static const QRegularExpression kvVar(QStringLiteral(
"([\\w\\-]+)\\s+([^;]+)"));
5141 if (!t.
contains(QLatin1String(
"kate"))) {
5149 auto match = kvLine.match(t);
5150 if (
match.hasMatch()) {
5151 s =
match.captured(1);
5154 }
else if ((match = kvLineWildcard.match(t)).hasMatch()) {
5156 const QString nameOfFile = url().
fileName();
5157 const QString pathOfFile = url().
path();
5160 for (
const QString &pattern : wildcards) {
5163 const bool matchPath = pattern.
contains(QLatin1Char(
'/'));
5167 found = wildcard.match(matchPath ? pathOfFile : nameOfFile).hasMatch();
5178 s =
match.captured(2);
5181 }
else if ((match = kvLineMime.match(t)).hasMatch()) {
5189 s =
match.captured(2);
5197 static const auto vvl = {
5198 QLatin1String(
"dynamic-word-wrap"),
5199 QLatin1String(
"dynamic-word-wrap-indicators"),
5200 QLatin1String(
"line-numbers"),
5201 QLatin1String(
"icon-border"),
5202 QLatin1String(
"folding-markers"),
5203 QLatin1String(
"folding-preview"),
5204 QLatin1String(
"bookmark-sorting"),
5205 QLatin1String(
"auto-center-lines"),
5206 QLatin1String(
"icon-bar-color"),
5207 QLatin1String(
"scrollbar-minimap"),
5208 QLatin1String(
"scrollbar-preview"),
5209 QLatin1String(
"enter-to-insert-completion")
5212 QLatin1String(
"background-color"),
5213 QLatin1String(
"selection-color"),
5214 QLatin1String(
"current-line-color"),
5215 QLatin1String(
"bracket-highlight-color"),
5216 QLatin1String(
"word-wrap-marker-color"),
5217 QLatin1String(
"font"),
5218 QLatin1String(
"font-size"),
5219 QLatin1String(
"scheme"),
5221 int spaceIndent = -1;
5222 bool replaceTabsSet =
false;
5227 while ((match = kvVar.match(s, startPos)).hasMatch()) {
5228 startPos =
match.capturedEnd(0);
5229 var =
match.captured(1);
5230 val =
match.captured(2).trimmed();
5236 if (contains(vvl, var)) {
5237 KTextEditor::View *v =
static_cast<KTextEditor::View *
>(view);
5238 setViewVariable(var, val, {&v, 1});
5242 if (var == QLatin1String(
"word-wrap") && checkBoolValue(val, &state)) {
5247 else if (var == QLatin1String(
"backspace-indents") && checkBoolValue(val, &state)) {
5248 m_config->setBackspaceIndents(state);
5249 }
else if (var == QLatin1String(
"indent-pasted-text") && checkBoolValue(val, &state)) {
5250 m_config->setIndentPastedText(state);
5251 }
else if (var == QLatin1String(
"replace-tabs") && checkBoolValue(val, &state)) {
5252 m_config->setReplaceTabsDyn(state);
5253 replaceTabsSet =
true;
5254 }
else if (var == QLatin1String(
"remove-trailing-space") && checkBoolValue(val, &state)) {
5255 qCWarning(LOG_KTE) <<
i18n(
5256 "Using deprecated modeline 'remove-trailing-space'. "
5257 "Please replace with 'remove-trailing-spaces modified;', see "
5258 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5259 m_config->setRemoveSpaces(state ? 1 : 0);
5260 }
else if (var == QLatin1String(
"replace-trailing-space-save") && checkBoolValue(val, &state)) {
5261 qCWarning(LOG_KTE) <<
i18n(
5262 "Using deprecated modeline 'replace-trailing-space-save'. "
5263 "Please replace with 'remove-trailing-spaces all;', see "
5264 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5265 m_config->setRemoveSpaces(state ? 2 : 0);
5266 }
else if (var == QLatin1String(
"overwrite-mode") && checkBoolValue(val, &state)) {
5267 m_config->setOvr(state);
5268 }
else if (var == QLatin1String(
"keep-extra-spaces") && checkBoolValue(val, &state)) {
5269 m_config->setKeepExtraSpaces(state);
5270 }
else if (var == QLatin1String(
"tab-indents") && checkBoolValue(val, &state)) {
5271 m_config->setTabIndents(state);
5272 }
else if (var == QLatin1String(
"show-tabs") && checkBoolValue(val, &state)) {
5273 m_config->setShowTabs(state);
5274 }
else if (var == QLatin1String(
"show-trailing-spaces") && checkBoolValue(val, &state)) {
5275 m_config->setShowSpaces(state ? KateDocumentConfig::Trailing : KateDocumentConfig::None);
5276 }
else if (var == QLatin1String(
"space-indent") && checkBoolValue(val, &state)) {
5278 spaceIndent = state;
5279 }
else if (var == QLatin1String(
"smart-home") && checkBoolValue(val, &state)) {
5280 m_config->setSmartHome(state);
5281 }
else if (var == QLatin1String(
"newline-at-eof") && checkBoolValue(val, &state)) {
5282 m_config->setNewLineAtEof(state);
5286 else if (var == QLatin1String(
"tab-width") && checkIntValue(val, &n)) {
5287 m_config->setTabWidth(n);
5288 }
else if (var == QLatin1String(
"indent-width") && checkIntValue(val, &n)) {
5289 m_config->setIndentationWidth(n);
5290 }
else if (var == QLatin1String(
"indent-mode")) {
5291 m_config->setIndentationMode(val);
5292 }
else if (var == QLatin1String(
"word-wrap-column") && checkIntValue(val, &n) && n > 0) {
5293 m_config->setWordWrapAt(n);
5297 else if (var == QLatin1String(
"eol") || var == QLatin1String(
"end-of-line")) {
5298 const auto l = {QLatin1String(
"unix"), QLatin1String(
"dos"), QLatin1String(
"mac")};
5299 if ((n = indexOf(l, val.
toLower())) != -1) {
5302 m_config->setEol(n);
5303 m_config->setAllowEolDetection(
false);
5305 }
else if (var == QLatin1String(
"bom") || var == QLatin1String(
"byte-order-mark") || var == QLatin1String(
"byte-order-marker")) {
5306 if (checkBoolValue(val, &state)) {
5307 m_config->setBom(state);
5309 }
else if (var == QLatin1String(
"remove-trailing-spaces")) {
5311 if (val == QLatin1String(
"1") || val == QLatin1String(
"modified") || val == QLatin1String(
"mod") || val == QLatin1String(
"+")) {
5312 m_config->setRemoveSpaces(1);
5313 }
else if (val == QLatin1String(
"2") || val == QLatin1String(
"all") || val == QLatin1String(
"*")) {
5314 m_config->setRemoveSpaces(2);
5316 m_config->setRemoveSpaces(0);
5318 }
else if (var == QLatin1String(
"syntax") || var == QLatin1String(
"hl")) {
5319 setHighlightingMode(val);
5320 }
else if (var == QLatin1String(
"mode")) {
5322 }
else if (var == QLatin1String(
"encoding")) {
5324 }
else if (var == QLatin1String(
"default-dictionary")) {
5325 setDefaultDictionary(val);
5326 }
else if (var == QLatin1String(
"automatic-spell-checking") && checkBoolValue(val, &state)) {
5327 onTheFlySpellCheckingEnabled(state);
5331 else if (contains(vvl, var)) {
5332 setViewVariable(var, val, m_views);
5334 m_storedVariables[var] = val;
5346 if (!replaceTabsSet && spaceIndent >= 0) {
5347 m_config->setReplaceTabsDyn(spaceIndent > 0);
5351void KTextEditor::DocumentPrivate::setViewVariable(
const QString &var,
const QString &val, std::span<KTextEditor::View *> views)
5356 for (
auto view : views) {
5357 auto v =
static_cast<ViewPrivate *
>(view);
5360 if (checkBoolValue(val, &state)) {
5363 if (v->config()->
setValue(var, help)) {
5364 }
else if (v->rendererConfig()->
setValue(var, help)) {
5366 }
else if (var == QLatin1String(
"dynamic-word-wrap") && checkBoolValue(val, &state)) {
5367 v->config()->setDynWordWrap(state);
5368 }
else if (var == QLatin1String(
"block-selection") && checkBoolValue(val, &state)) {
5369 v->setBlockSelection(state);
5372 }
else if (var == QLatin1String(
"icon-bar-color") && checkColorValue(val, c)) {
5373 v->rendererConfig()->setIconBarColor(c);
5376 else if (var == QLatin1String(
"background-color") && checkColorValue(val, c)) {
5377 v->rendererConfig()->setBackgroundColor(c);
5378 }
else if (var == QLatin1String(
"selection-color") && checkColorValue(val, c)) {
5379 v->rendererConfig()->setSelectionColor(c);
5380 }
else if (var == QLatin1String(
"current-line-color") && checkColorValue(val, c)) {
5381 v->rendererConfig()->setHighlightedLineColor(c);
5382 }
else if (var == QLatin1String(
"bracket-highlight-color") && checkColorValue(val, c)) {
5383 v->rendererConfig()->setHighlightedBracketColor(c);
5384 }
else if (var == QLatin1String(
"word-wrap-marker-color") && checkColorValue(val, c)) {
5385 v->rendererConfig()->setWordWrapMarkerColor(c);
5386 }
else if (var == QLatin1String(
"font") || (checkIntValue(val, &n) && n > 0 && var == QLatin1String(
"font-size"))) {
5389 if (var == QLatin1String(
"font")) {
5391 _f.setFixedPitch(QFont(val).fixedPitch());
5396 v->rendererConfig()->setFont(_f);
5397 }
else if (var == QLatin1String(
"scheme")) {
5398 v->rendererConfig()->setSchema(val);
5403bool KTextEditor::DocumentPrivate::checkBoolValue(QString val,
bool *result)
5406 static const auto trueValues = {QLatin1String(
"1"), QLatin1String(
"on"), QLatin1String(
"true")};
5407 if (contains(trueValues, val)) {
5412 static const auto falseValues = {QLatin1String(
"0"), QLatin1String(
"off"), QLatin1String(
"false")};
5413 if (contains(falseValues, val)) {
5420bool KTextEditor::DocumentPrivate::checkIntValue(
const QString &val,
int *result)
5423 *result = val.
toInt(&ret);
5427bool KTextEditor::DocumentPrivate::checkColorValue(
const QString &val, QColor &c)
5436 auto it = m_storedVariables.find(name);
5437 if (it == m_storedVariables.end()) {
5445 QString s = QStringLiteral(
"kate: ");
5449 readVariableLine(s);
5454void KTextEditor::DocumentPrivate::slotModOnHdDirty(
const QString &path)
5456 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskModified)) {
5458 m_modOnHdReason = OnDiskModified;
5460 if (!m_modOnHdTimer.isActive()) {
5461 m_modOnHdTimer.start();
5466void KTextEditor::DocumentPrivate::slotModOnHdCreated(
const QString &path)
5468 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskCreated)) {
5470 m_modOnHdReason = OnDiskCreated;
5472 if (!m_modOnHdTimer.isActive()) {
5473 m_modOnHdTimer.start();
5478void KTextEditor::DocumentPrivate::slotModOnHdDeleted(
const QString &path)
5480 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskDeleted)) {
5482 m_modOnHdReason = OnDiskDeleted;
5484 if (!m_modOnHdTimer.isActive()) {
5485 m_modOnHdTimer.start();
5490void KTextEditor::DocumentPrivate::slotDelayedHandleModOnHd()
5493 const QByteArray oldDigest = checksum();
5494 if (!oldDigest.
isEmpty() && !url().isEmpty() && url().isLocalFile()) {
5496 if (m_modOnHdReason != OnDiskDeleted && m_modOnHdReason != OnDiskCreated && createDigest() && oldDigest == checksum()) {
5498 m_modOnHdReason = OnDiskUnmodified;
5499 m_prevModOnHdReason = OnDiskUnmodified;
5506 if (m_modOnHd && !isModified() &&
QFile::exists(url().toLocalFile())
5507 && config()->value(KateDocumentConfig::AutoReloadIfStateIsInVersionControl).toBool()) {
5512 const QStringList args{QStringLiteral(
"cat-file"), QStringLiteral(
"-e"),
QString::fromUtf8(oldDigest.
toHex())};
5514 git.
start(fullGitPath, args);
5521 m_modOnHdReason = OnDiskUnmodified;
5522 m_prevModOnHdReason = OnDiskUnmodified;
5532 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
5537 return m_buffer->digest();
5540bool KTextEditor::DocumentPrivate::createDigest()
5544 if (url().isLocalFile()) {
5545 QFile f(url().toLocalFile());
5549 const QString header = QStringLiteral(
"blob %1").
arg(f.size());
5552 digest = crypto.result();
5557 m_buffer->setDigest(digest);
5561QString KTextEditor::DocumentPrivate::reasonedMOHString()
const
5566 switch (m_modOnHdReason) {
5567 case OnDiskModified:
5568 return i18n(
"The file '%1' was modified on disk.", str);
5571 return i18n(
"The file '%1' was created on disk.", str);
5574 return i18n(
"The file '%1' was deleted or moved on disk.", str);
5583void KTextEditor::DocumentPrivate::removeTrailingSpacesAndAddNewLineAtEof()
5586 const int remove = config()->removeSpaces();
5587 const bool newLineAtEof = config()->newLineAtEof();
5588 if (remove == 0 && !newLineAtEof) {
5593 const bool wordWrapEnabled = config()->wordWrap();
5594 if (wordWrapEnabled) {
5601 const int lines = this->lines();
5603 for (
int line = 0; line < lines; ++line) {
5604 Kate::TextLine textline = plainKateTextLine(line);
5609 if (remove == 2 || textline.markedAsModified() || textline.markedAsSavedOnDisk()) {
5610 const int p = textline.
lastChar() + 1;
5611 const int l = textline.
length() - p;
5613 editRemoveText(line, p, l);
5622 Q_ASSERT(lines > 0);
5623 const auto length = lineLength(lines - 1);
5627 const auto oldEndOfDocumentCursor = documentEnd();
5628 std::vector<KTextEditor::ViewPrivate *> viewsToRestoreCursors;
5629 for (
auto view : std::as_const(m_views)) {
5630 auto v =
static_cast<ViewPrivate *
>(view);
5631 if (v->cursorPosition() == oldEndOfDocumentCursor) {
5632 viewsToRestoreCursors.push_back(v);
5637 editWrapLine(lines - 1, length);
5640 for (
auto v : viewsToRestoreCursors) {
5641 v->setCursorPosition(oldEndOfDocumentCursor);
5649 if (wordWrapEnabled) {
5657 const int lines = this->lines();
5660 const int p = textline.
lastChar() + 1;
5661 const int l = textline.
length() - p;
5671 if (user || !m_fileTypeSetByUser) {
5677 if (fileType.name.isEmpty()) {
5682 m_fileTypeSetByUser = user;
5684 m_fileType = newType;
5686 m_config->configStart();
5691 if ((user || !m_hlSetByUser) && !fileType.hl.isEmpty()) {
5692 int hl(KateHlManager::self()->nameFind(fileType.hl));
5695 m_buffer->setHighlight(hl);
5702 if (!m_indenterSetByUser && !fileType.indenter.isEmpty()) {
5703 config()->setIndentationMode(fileType.indenter);
5707 for (
auto view : std::as_const(m_views)) {
5708 auto v =
static_cast<ViewPrivate *
>(view);
5713 bool bom_settings =
false;
5714 if (m_bomSetByUser) {
5715 bom_settings = m_config->bom();
5717 readVariableLine(fileType.varLine);
5718 if (m_bomSetByUser) {
5719 m_config->setBom(bom_settings);
5721 m_config->configEnd();
5722 for (
auto view : std::as_const(m_views)) {
5723 auto v =
static_cast<ViewPrivate *
>(view);
5734void KTextEditor::DocumentPrivate::slotQueryClose_save(
bool *handled,
bool *abortClosing)
5737 *abortClosing =
true;
5738 if (url().isEmpty()) {
5739 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
5741 *abortClosing =
true;
5745 *abortClosing =
false;
5748 *abortClosing =
false;
5758 return m_config->configKeys();
5764 return m_config->
value(key);
5770 m_config->setValue(key, value);
5784 bool changed = removeText(range, block);
5785 changed |= insertText(range.
start(), s, block);
5790KateHighlighting *KTextEditor::DocumentPrivate::highlight()
const
5792 return m_buffer->highlight();
5797 m_buffer->ensureHighlighted(i);
5798 return m_buffer->plainLine(i);
5803 return m_buffer->plainLine(i);
5806bool KTextEditor::DocumentPrivate::isEditRunning()
const
5808 return editIsRunning;
5811void KTextEditor::DocumentPrivate::setUndoMergeAllEdits(
bool merge)
5813 if (merge && m_undoMergeAllEdits) {
5818 m_undoManager->undoSafePoint();
5819 m_undoManager->setAllowComplexMerge(merge);
5820 m_undoMergeAllEdits =
merge;
5833 return new Kate::TextRange(m_buffer, range, insertBehaviors, emptyBehavior);
5838 return m_buffer->history().revision();
5843 return m_buffer->history().lastSavedRevision();
5848 m_buffer->history().lockRevision(
revision);
5853 m_buffer->history().unlockRevision(
revision);
5859 qint64 fromRevision,
5862 m_buffer->history().transformCursor(
line, column, insertBehavior, fromRevision, toRevision);
5867 qint64 fromRevision,
5871 int column = cursor.
column();
5872 m_buffer->history().transformCursor(
line, column, insertBehavior, fromRevision, toRevision);
5879 qint64 fromRevision,
5882 m_buffer->history().transformRange(range, insertBehaviors, emptyBehavior, fromRevision, toRevision);
5891 m_annotationModel = model;
5892 Q_EMIT annotationModelChanged(oldmodel, m_annotationModel);
5897 return m_annotationModel;
5902bool KTextEditor::DocumentPrivate::queryClose()
5904 if (!isModified() || (isEmpty() && url().isEmpty())) {
5908 QString docName = documentName();
5911 i18n(
"The document \"%1\" has been modified.\n"
5912 "Do you want to save your changes or discard them?",
5914 i18n(
"Close Document"),
5918 bool abortClose =
false;
5919 bool handled =
false;
5923 sigQueryClose(&handled, &abortClose);
5925 if (url().isEmpty()) {
5926 const QUrl url = getSaveFileUrl(
i18n(
"Save File"));
5935 }
else if (abortClose) {
5938 return waitSaveComplete();
5946void KTextEditor::DocumentPrivate::slotStarted(KIO::Job *job)
5949 if (m_documentState == DocumentIdle) {
5950 m_documentState = DocumentLoading;
5958 if (m_documentState == DocumentLoading) {
5960 m_readWriteStateBeforeLoading = isReadWrite();
5965 setReadWrite(
false);
5975void KTextEditor::DocumentPrivate::slotCompleted()
5979 if (m_documentState == DocumentLoading) {
5980 setReadWrite(m_readWriteStateBeforeLoading);
5981 delete m_loadingMessage;
5982 m_reloading =
false;
5986 if (m_documentState == DocumentSaving || m_documentState == DocumentSavingAs) {
5987 Q_EMIT documentSavedOrUploaded(
this, m_documentState == DocumentSavingAs);
5991 m_documentState = DocumentIdle;
5994void KTextEditor::DocumentPrivate::slotCanceled()
5998 if (m_documentState == DocumentLoading) {
5999 setReadWrite(m_readWriteStateBeforeLoading);
6000 delete m_loadingMessage;
6001 m_reloading =
false;
6003 if (!m_openingError) {
6004 showAndSetOpeningErrorAccess();
6011 m_documentState = DocumentIdle;
6014void KTextEditor::DocumentPrivate::slotTriggerLoadingMessage()
6018 if (m_documentState != DocumentLoading) {
6023 delete m_loadingMessage;
6025 new KTextEditor::Message(
i18n(
"The file <a href=\"%1\">%2</a> is still loading.", url().toDisplayString(
QUrl::PreferLocalFile), url().fileName()));
6030 QAction *
cancel =
new QAction(
i18n(
"&Abort Loading"),
nullptr);
6032 m_loadingMessage->addAction(cancel);
6036 postMessage(m_loadingMessage);
6039void KTextEditor::DocumentPrivate::slotAbortLoading()
6042 if (!m_loadingJob) {
6048 m_loadingJob->kill(KJob::EmitResult);
6049 m_loadingJob =
nullptr;
6052void KTextEditor::DocumentPrivate::slotUrlChanged(
const QUrl &url)
6056 Q_EMIT documentUrlChanged(
this);
6059bool KTextEditor::DocumentPrivate::save()
6063 if ((m_documentState != DocumentIdle) && (m_documentState != DocumentPreSavingAs)) {
6068 if (m_documentState == DocumentIdle) {
6069 m_documentState = DocumentSaving;
6071 m_documentState = DocumentSavingAs;
6075 Q_EMIT aboutToSave(
this);
6081bool KTextEditor::DocumentPrivate::saveAs(
const QUrl &url)
6092 if (m_documentState != DocumentIdle) {
6097 m_documentState = DocumentPreSavingAs;
6103QUrl KTextEditor::DocumentPrivate::startUrlForFileDialog()
6105 QUrl startUrl = url();
6115 const auto views = mainWindow->views();
6116 for (
auto view : views) {
6128QString KTextEditor::DocumentPrivate::defaultDictionary()
const
6130 return m_defaultDictionary;
6133QList<QPair<KTextEditor::MovingRange *, QString>> KTextEditor::DocumentPrivate::dictionaryRanges()
const
6135 return m_dictionaryRanges;
6138void KTextEditor::DocumentPrivate::clearDictionaryRanges()
6140 for (
auto i = m_dictionaryRanges.cbegin(); i != m_dictionaryRanges.cend(); ++i) {
6143 m_dictionaryRanges.clear();
6144 if (m_onTheFlyChecker) {
6145 m_onTheFlyChecker->refreshSpellCheck();
6147 Q_EMIT dictionaryRangesPresent(
false);
6150void KTextEditor::DocumentPrivate::setDictionary(
const QString &newDictionary, KTextEditor::Range range,
bool blockmode)
6154 setDictionary(newDictionary, rangeOnLine(range, i));
6157 setDictionary(newDictionary, range);
6160 Q_EMIT dictionaryRangesPresent(!m_dictionaryRanges.isEmpty());
6163void KTextEditor::DocumentPrivate::setDictionary(
const QString &newDictionary, KTextEditor::Range range)
6165 KTextEditor::Range newDictionaryRange = range;
6166 if (!newDictionaryRange.
isValid() || newDictionaryRange.
isEmpty()) {
6169 QList<QPair<KTextEditor::MovingRange *, QString>> newRanges;
6171 for (
auto i = m_dictionaryRanges.begin(); i != m_dictionaryRanges.end();) {
6172 qCDebug(LOG_KTE) <<
"new iteration" << newDictionaryRange;
6173 if (newDictionaryRange.
isEmpty()) {
6176 QPair<KTextEditor::MovingRange *, QString> pair = *i;
6177 QString dictionarySet = pair.second;
6178 KTextEditor::MovingRange *dictionaryRange = pair.first;
6179 qCDebug(LOG_KTE) << *dictionaryRange << dictionarySet;
6180 if (dictionaryRange->
contains(newDictionaryRange) && newDictionary == dictionarySet) {
6181 qCDebug(LOG_KTE) <<
"dictionaryRange contains newDictionaryRange";
6184 if (newDictionaryRange.
contains(*dictionaryRange)) {
6185 delete dictionaryRange;
6186 i = m_dictionaryRanges.erase(i);
6187 qCDebug(LOG_KTE) <<
"newDictionaryRange contains dictionaryRange";
6191 KTextEditor::Range intersection = dictionaryRange->
toRange().
intersect(newDictionaryRange);
6193 if (dictionarySet == newDictionary) {
6195 QList<KTextEditor::Range> remainingRanges = KateSpellCheckManager::rangeDifference(newDictionaryRange, intersection);
6196 Q_ASSERT(remainingRanges.
size() == 1);
6197 newDictionaryRange = remainingRanges.
first();
6199 qCDebug(LOG_KTE) <<
"dictionarySet == newDictionary";
6202 QList<KTextEditor::Range> remainingRanges = KateSpellCheckManager::rangeDifference(*dictionaryRange, intersection);
6203 for (
auto j = remainingRanges.
begin(); j != remainingRanges.
end(); ++j) {
6206 newRanges.
push_back({remainingRange, dictionarySet});
6208 i = m_dictionaryRanges.erase(i);
6209 delete dictionaryRange;
6214 m_dictionaryRanges += newRanges;
6216 KTextEditor::MovingRange *newDictionaryMovingRange =
6219 m_dictionaryRanges.push_back({newDictionaryMovingRange, newDictionary});
6221 if (m_onTheFlyChecker && !newDictionaryRange.
isEmpty()) {
6222 m_onTheFlyChecker->refreshSpellCheck(newDictionaryRange);
6226void KTextEditor::DocumentPrivate::setDefaultDictionary(
const QString &dict)
6228 if (m_defaultDictionary == dict) {
6232 m_defaultDictionary = dict;
6234 if (m_onTheFlyChecker) {
6235 m_onTheFlyChecker->updateConfig();
6236 refreshOnTheFlyCheck();
6238 Q_EMIT defaultDictionaryChanged(
this);
6241void KTextEditor::DocumentPrivate::onTheFlySpellCheckingEnabled(
bool enable)
6243 if (isOnTheFlySpellCheckingEnabled() == enable) {
6248 Q_ASSERT(m_onTheFlyChecker ==
nullptr);
6249 m_onTheFlyChecker =
new KateOnTheFlyChecker(
this);
6251 delete m_onTheFlyChecker;
6252 m_onTheFlyChecker =
nullptr;
6255 for (
auto view : std::as_const(m_views)) {
6256 static_cast<ViewPrivate *
>(view)->reflectOnTheFlySpellCheckStatus(enable);
6260bool KTextEditor::DocumentPrivate::isOnTheFlySpellCheckingEnabled()
const
6262 return m_onTheFlyChecker !=
nullptr;
6265QString KTextEditor::DocumentPrivate::dictionaryForMisspelledRange(KTextEditor::Range range)
const
6267 if (!m_onTheFlyChecker) {
6270 return m_onTheFlyChecker->dictionaryForMisspelledRange(range);
6274void KTextEditor::DocumentPrivate::clearMisspellingForWord(
const QString &word)
6276 if (m_onTheFlyChecker) {
6277 m_onTheFlyChecker->clearMisspellingForWord(word);
6281void KTextEditor::DocumentPrivate::refreshOnTheFlyCheck(KTextEditor::Range range)
6283 if (m_onTheFlyChecker) {
6284 m_onTheFlyChecker->refreshSpellCheck(range);
6290 deleteDictionaryRange(movingRange);
6295 deleteDictionaryRange(movingRange);
6300 qCDebug(LOG_KTE) <<
"deleting" << movingRange;
6302 auto finder = [=](
const QPair<KTextEditor::MovingRange *, QString> &item) ->
bool {
6303 return item.first == movingRange;
6306 auto it = std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder);
6308 if (it != m_dictionaryRanges.end()) {
6309 m_dictionaryRanges.erase(it);
6313 Q_ASSERT(std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder) == m_dictionaryRanges.end());
6316bool KTextEditor::DocumentPrivate::containsCharacterEncoding(KTextEditor::Range range)
6318 KateHighlighting *highlighting = highlight();
6320 const int rangeStartLine = range.
start().
line();
6321 const int rangeStartColumn = range.
start().
column();
6322 const int rangeEndLine = range.
end().
line();
6323 const int rangeEndColumn = range.
end().
column();
6325 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6326 const Kate::TextLine textLine = kateTextLine(line);
6327 const int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6328 const int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6329 for (
int col = startColumn; col < endColumn; ++col) {
6331 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6341int KTextEditor::DocumentPrivate::computePositionWrtOffsets(
const OffsetList &offsetList,
int pos)
6343 int previousOffset = 0;
6344 for (
auto i = offsetList.cbegin(); i != offsetList.cend(); ++i) {
6345 if (i->first > pos) {
6348 previousOffset = i->second;
6350 return pos + previousOffset;
6354 KTextEditor::DocumentPrivate::OffsetList &decToEncOffsetList,
6355 KTextEditor::DocumentPrivate::OffsetList &encToDecOffsetList)
6359 int decToEncCurrentOffset = 0;
6360 int encToDecCurrentOffset = 0;
6364 KateHighlighting *highlighting = highlight();
6367 const int rangeStartLine = range.
start().
line();
6368 const int rangeStartColumn = range.
start().
column();
6369 const int rangeEndLine = range.
end().
line();
6370 const int rangeEndColumn = range.
end().
column();
6374 int startColumn = (
line == rangeStartLine) ? rangeStartColumn : 0;
6375 int endColumn = (
line == rangeEndLine) ? rangeEndColumn : textLine.
length();
6376 for (
int col = startColumn; col < endColumn;) {
6378 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6381 if (!matchingPrefix.
isEmpty()) {
6383 const QChar &c = characterEncodingsHash.
value(matchingPrefix);
6384 const bool isNullChar = c.
isNull();
6388 i += matchingPrefix.
length();
6389 col += matchingPrefix.
length();
6391 decToEncCurrentOffset = decToEncCurrentOffset - (isNullChar ? 0 : 1) + matchingPrefix.
length();
6392 encToDecCurrentOffset = encToDecCurrentOffset - matchingPrefix.
length() + (isNullChar ? 0 : 1);
6393 newI += (isNullChar ? 0 : 1);
6394 decToEncOffsetList.
push_back(QPair<int, int>(newI, decToEncCurrentOffset));
6395 encToDecOffsetList.
push_back(QPair<int, int>(i, encToDecCurrentOffset));
6405 if (previous < range.
end()) {
6411void KTextEditor::DocumentPrivate::replaceCharactersByEncoding(
KTextEditor::Range range)
6413 KateHighlighting *highlighting = highlight();
6416 const int rangeStartLine = range.
start().
line();
6417 const int rangeStartColumn = range.
start().
column();
6418 const int rangeEndLine = range.
end().
line();
6419 const int rangeEndColumn = range.
end().
column();
6421 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6422 textLine = kateTextLine(line);
6423 int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6424 int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6425 for (
int col = startColumn; col < endColumn;) {
6427 const QHash<QChar, QString> &reverseCharacterEncodingsHash = highlighting->getReverseCharacterEncodings(attr);
6428 auto it = reverseCharacterEncodingsHash.
find(textLine.
at(col));
6429 if (it != reverseCharacterEncodingsHash.
end()) {
6431 col += (*it).length();
6445 return highlight()->getEmbeddedHighlightingModes();
6450 return highlight()->higlightingModeForLocation(
this, position);
6465 if (line < 0 || line >=
lines() || column < 0) {
6466 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6474 if (column < tl.
length()) {
6476 }
else if (column == tl.
length()) {
6480 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6483 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6486 return highlight()->defaultStyleForAttribute(attribute);
6489bool KTextEditor::DocumentPrivate::isComment(
int line,
int column)
6491 return defStyleNum(line, column) == KSyntaxHighlighting::Theme::TextStyle::Comment;
6496 const int offset = down ? 1 : -1;
6497 const int lineCount =
lines();
6498 while (startLine >= 0 && startLine < lineCount) {
6500 if (tl.markedAsModified() || tl.markedAsSavedOnDisk()) {
6503 startLine += offset;
6512 delete m_activeTemplateHandler.data();
6513 m_activeTemplateHandler = handler;
6526 qCWarning(LOG_KTE) <<
"trying to post a message to a view of another document:" << message->
text();
6536 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
6542 const auto messageActions = message->
actions();
6543 managedMessageActions.
reserve(messageActions.size());
6545 action->setParent(
nullptr);
6546 managedMessageActions.
append(std::shared_ptr<QAction>(
action));
6548 m_messageHash.insert(message, managedMessageActions);
6552 view->postMessage(message, managedMessageActions);
6554 for (
auto view : std::as_const(m_views)) {
6555 static_cast<ViewPrivate *
>(view)->
postMessage(message, managedMessageActions);
6560 connect(message, &
Message::closed,
this, &DocumentPrivate::messageDestroyed);
6568 Q_ASSERT(m_messageHash.contains(message));
6569 m_messageHash.remove(message);
6573#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)
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()
virtual void setWidget(QWidget *widget)
void setAutoDeletePart(bool autoDeletePart)
void setAutoDeleteWidget(bool autoDeleteWidget)
virtual bool openUrl(const QUrl &url)
void urlChanged(const QUrl &url)
OpenUrlArguments arguments() const
void canceled(const QString &errMsg)
void started(KIO::Job *job)
QString localFilePath() const
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.
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.
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.
QString text(KTextEditor::Range range, bool blockwise=false) const override
Get the document content within the given range.
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.
int lastLine() const
gets the last line number (lines() - 1)
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.
void textRemoved(KTextEditor::Document *document, KTextEditor::Range range, const QString &oldText)
The document emits this signal whenever range was removed, i.e.
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)
KateDocumentConfig * config()
Configuration.
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.
void textInsertedRange(KTextEditor::Document *document, KTextEditor::Range range)
The document emits this signal whenever text was inserted.
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.
void documentNameChanged(KTextEditor::Document *document)
This signal is emitted whenever the document name changes.
void textChanged(KTextEditor::Document *document)
The document emits this signal whenever its text changes.
void marksChanged(KTextEditor::Document *document)
The document emits this signal whenever a mark mask changed.
void markClicked(KTextEditor::Document *document, KTextEditor::Mark mark, bool &handled)
The document emits this signal whenever the mark is left-clicked.
MarkTypes
Predefined mark types.
void viewCreated(KTextEditor::Document *document, KTextEditor::View *view)
This signal is emitted whenever the document creates a new view.
virtual bool isEmpty() const
Returns if the document is empty.
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 modeChanged(KTextEditor::Document *document)
Warn anyone listening that the current document's mode has changed.
void aboutToClose(KTextEditor::Document *document)
Warn anyone listening that the current document is about to close.
@ MarkRemoved
action: a mark was removed.
void modifiedOnDisk(KTextEditor::Document *document, bool isModified, KTextEditor::Document::ModifiedOnDiskReason reason)
This signal is emitted whenever the document changed its modified-on-disk state.
void markChanged(KTextEditor::Document *document, KTextEditor::Mark mark, KTextEditor::Document::MarkChangeAction action)
The document emits this signal whenever the mark changes.
void aboutToReload(KTextEditor::Document *document)
Warn anyone listening that the current document is about to reload.
void markContextMenuRequested(KTextEditor::Document *document, KTextEditor::Mark mark, QPoint pos, bool &handled)
The document emits this signal whenever the mark is right-clicked to show a context menu.
ModifiedOnDiskReason
Reasons why a document is modified on disk.
@ OnDiskUnmodified
Not modified.
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.
QFlags< InsertBehavior > InsertBehaviors
Stores a combination of InsertBehavior values.
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.
virtual QAction * action(const QDomElement &element) const
void insertChildClient(KXMLGUIClient *child)
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.
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...
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 QString start(QString train="")
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)
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)
const QList< QKeySequence > & end()
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".
QFlags< SearchOption > SearchOptions
Stores a combination of SearchOption values.
void triggered(bool checked)
QByteArray & append(QByteArrayView data)
bool isEmpty() const const
qsizetype size() const const
QByteArray toHex(char separator) const const
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
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)
QObject * parent() const const
T qobject_cast(QObject *object)
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)
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)
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
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)