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) {
2227 return QStringLiteral(
"text/plain");
2241void KTextEditor::DocumentPrivate::showAndSetOpeningErrorAccess()
2244 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.",
2247 message->setWordWrap(
true);
2249 i18nc(
"translators: you can also translate 'Try Again' with 'Reload'",
"Try Again"),
2254 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
2257 message->addAction(tryAgainAction);
2258 message->addAction(closeAction);
2261 postMessage(message);
2264 m_openingError =
true;
2268void KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride()
2271 const int longestLine = m_buffer->longestLineLoaded();
2272 int newLimit = pow(2, ceil(log2(longestLine)));
2273 if (newLimit <= longestLine) {
2278 config()->setLineLengthLimit(newLimit);
2283 if (!m_openingError) {
2285 m_readWriteStateBeforeLoading =
true;
2291 return config()->lineLengthLimit();
2301 m_openingError =
false;
2314 if (pos != -1 && !(m_reloading && m_userSetEncodingForNextReload)) {
2326 if (m_reloading && m_userSetEncodingForNextReload && (currentEncoding !=
encoding())) {
2330 bool success = m_buffer->openFile(
localFilePath(), (m_reloading && m_userSetEncodingForNextReload));
2343 for (
auto view : std::as_const(m_views)) {
2346 static_cast<ViewPrivate *
>(view)->updateView(
true);
2365 if (!
isEmpty() &&
config()->autoDetectIndent() && !
config()->isSet(KateDocumentConfig::IndentationWidth)
2366 && !
config()->isSet(KateDocumentConfig::ReplaceTabsWithSpaces)) {
2368 auto result = detecter.detect(
config()->indentationWidth(),
config()->replaceTabsDyn());
2369 config()->setIndentationWidth(result.indentWidth);
2370 config()->setReplaceTabsDyn(result.indentUsingSpaces);
2377 showAndSetOpeningErrorAccess();
2381 if (m_buffer->brokenEncoding()) {
2383 setReadWrite(
false);
2384 m_readWriteStateBeforeLoading =
false;
2386 i18n(
"The file %1 was opened with %2 encoding but contained invalid characters.<br />"
2387 "It is set to read-only mode, as saving might destroy its content.<br />"
2388 "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.",
2390 m_buffer->textCodec()),
2392 message->setWordWrap(
true);
2396 m_openingError =
true;
2400 if (m_buffer->tooLongLinesWrapped()) {
2402 setReadWrite(
false);
2403 m_readWriteStateBeforeLoading =
false;
2405 new KTextEditor::Message(
i18n(
"The file %1 was opened and contained lines longer than the configured Line Length Limit (%2 characters).<br />"
2406 "The longest of those lines was %3 characters long<br/>"
2407 "Those lines were wrapped and the document is set to read-only mode, as saving will modify its content.",
2410 m_buffer->longestLineLoaded()),
2412 QAction *increaseAndReload =
new QAction(
i18n(
"Temporarily raise limit and reload file"), message);
2413 connect(increaseAndReload, &
QAction::triggered,
this, &KTextEditor::DocumentPrivate::openWithLineLengthLimitOverride);
2414 message->addAction(increaseAndReload,
true);
2415 message->addAction(
new QAction(
i18n(
"Close"), message),
true);
2416 message->setWordWrap(
true);
2420 m_openingError =
true;
2432 delete m_modOnHdHandler;
2436 if (m_fileChangedDialogsActivated && m_modOnHd) {
2442 str +
i18n(
"Do you really want to save this unmodified file? You could overwrite changed data in the file on disk."),
2443 i18n(
"Trying to Save Unmodified File"),
2453 "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."),
2454 i18n(
"Possible Data Loss"),
2466 if (!m_buffer->canEncode()
2468 i18n(
"The selected encoding cannot encode every Unicode character in this document. Do you really want to save "
2469 "it? There could be some data lost."),
2470 i18n(
"Possible Data Loss"),
2478 if (!createBackupFile()) {
2483 QString oldPath = m_dirWatchFile;
2489 if (
url().isLocalFile()) {
2496 const bool variablesWereRead = readVariables();
2502 if (!variablesWereRead) {
2503 for (
auto *view : std::as_const(m_views)) {
2504 auto v =
static_cast<ViewPrivate *
>(view);
2505 if (v->isVisible()) {
2506 const auto range = v->visibleRange();
2508 bool repaint =
false;
2517 v->updateView(
true);
2524 deactivateDirWatch();
2529 removeTrailingSpacesAndAddNewLineAtEof();
2536 activateDirWatch(oldPath);
2538 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 "
2539 "that enough disk space is available.\nThe original file may be lost or damaged. "
2540 "Don't quit the application until the file is successfully written.",
2563 m_undoManager->undoSafePoint();
2564 m_undoManager->updateLineModifications();
2572bool KTextEditor::DocumentPrivate::createBackupFile()
2575 const bool backupLocalFiles = config()->backupOnSaveLocal();
2576 const bool backupRemoteFiles = config()->backupOnSaveRemote();
2580 if (!backupLocalFiles && !backupRemoteFiles) {
2587 bool needBackup = backupLocalFiles && backupRemoteFiles;
2589 bool slowOrRemoteFile = !u.isLocalFile();
2590 if (!slowOrRemoteFile) {
2594 slowOrRemoteFile = (mountPoint && mountPoint->probablySlow());
2596 needBackup = (!slowOrRemoteFile && backupLocalFiles) || (slowOrRemoteFile && backupRemoteFiles);
2607 if (backupPrefix.isEmpty() && backupSuffix.isEmpty()) {
2614 u.setPath(backupPrefix + u.fileName() + backupSuffix);
2617 const QString fileName = u.fileName();
2619 u.setPath(u.path() + backupPrefix + fileName + backupSuffix);
2622 qCDebug(LOG_KTE) <<
"backup src file name: " << url();
2623 qCDebug(LOG_KTE) <<
"backup dst file name: " << u;
2626 bool backupSuccess =
false;
2629 if (u.isLocalFile()) {
2632 QFile backupFile(u.toLocalFile());
2633 if (backupFile.exists()) {
2634 backupFile.remove();
2637 backupSuccess =
QFile::copy(url().toLocalFile(), u.toLocalFile());
2639 backupSuccess =
true;
2645 if (statJob->
exec()) {
2647 KFileItem item(statJob->
statResult(), url());
2650 backupSuccess = job->
exec();
2652 backupSuccess =
true;
2659 i18n(
"For file %1 no backup copy could be created before saving."
2660 " If an error occurs while saving, you might lose the data of this file."
2661 " A reason could be that the media you write to is full or the directory of the file is read-only for you.",
2663 i18n(
"Failed to create backup copy."),
2664 KGuiItem(
i18n(
"Try to Save Nevertheless")),
2666 QStringLiteral(
"Backup Failed Warning"))
2674void KTextEditor::DocumentPrivate::readDirConfig(KTextEditor::ViewPrivate *v)
2682 QSet<QString> seenDirectories;
2683 QDir
dir(QFileInfo(localFilePath()).absolutePath());
2684 while (!seenDirectories.
contains(
dir.absolutePath())) {
2686 seenDirectories.
insert(
dir.absolutePath());
2689 QFile f(
dir.absolutePath() + QLatin1String(
"/.kateconfig"));
2691 QTextStream stream(&f);
2694 QString line = stream.readLine();
2695 while ((linesRead < 32) && !line.
isNull()) {
2696 readVariableLine(line, v);
2698 line = stream.readLine();
2712#if EDITORCONFIG_FOUND
2714 if (!v && config()->value(KateDocumentConfig::UseEditorConfig).toBool()) {
2718 EditorConfig editorConfig(
this);
2719 editorConfig.parse();
2724void KTextEditor::DocumentPrivate::activateDirWatch(
const QString &useFileName)
2726 QString fileToUse = useFileName;
2728 fileToUse = localFilePath();
2735 QFileInfo fileInfo = QFileInfo(fileToUse);
2742 if (fileToUse == m_dirWatchFile) {
2747 deactivateDirWatch();
2750 if (url().isLocalFile() && !fileToUse.
isEmpty()) {
2752 m_dirWatchFile = fileToUse;
2756void KTextEditor::DocumentPrivate::deactivateDirWatch()
2758 if (!m_dirWatchFile.isEmpty()) {
2762 m_dirWatchFile.clear();
2765bool KTextEditor::DocumentPrivate::openUrl(
const QUrl &url)
2769 m_fileTypeSetByUser =
false;
2776bool KTextEditor::DocumentPrivate::closeUrl()
2781 if (!m_reloading && !url().isEmpty()) {
2782 if (m_fileChangedDialogsActivated && m_modOnHd) {
2784 delete m_modOnHdHandler;
2786 QWidget *parentWidget(dialogParent());
2788 reasonedMOHString() + QLatin1String(
"\n\n")
2789 +
i18n(
"Do you really want to continue to close this file? Data loss may occur."),
2790 i18n(
"Possible Data Loss"),
2791 KGuiItem(
i18n(
"Close Nevertheless")),
2793 QStringLiteral(
"kate_close_modonhd_%1").arg(m_modOnHdReason))
2796 m_reloading =
false;
2807 m_reloading =
false;
2813 Q_EMIT aboutToClose(
this);
2817 if (!m_messageHash.isEmpty()) {
2818 const auto keys = m_messageHash.keys();
2819 for (KTextEditor::Message *message : keys) {
2825 Q_EMIT aboutToInvalidateMovingInterfaceContent(
this);
2828 deactivateDirWatch();
2831 setLocalFilePath(QString());
2836 m_modOnHdReason = OnDiskUnmodified;
2837 m_prevModOnHdReason = OnDiskUnmodified;
2838 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
2848 m_undoManager->clearUndo();
2849 m_undoManager->clearRedo();
2855 m_buffer->setHighlight(0);
2858 for (
auto view : std::as_const(m_views)) {
2859 static_cast<ViewPrivate *
>(view)->clearSelection();
2860 static_cast<ViewPrivate *
>(view)->
clear();
2865 m_swapfile->fileClosed();
2874 return m_swapfile && m_swapfile->shouldRecover();
2880 m_swapfile->recover();
2887 m_swapfile->discard();
2891void KTextEditor::DocumentPrivate::setReadWrite(
bool rw)
2893 if (isReadWrite() == rw) {
2899 for (
auto v : std::as_const(m_views)) {
2900 auto view =
static_cast<ViewPrivate *
>(v);
2901 view->slotUpdateUndo();
2902 view->slotReadWriteChanged();
2905 Q_EMIT readWriteChanged(
this);
2910 if (isModified() != m) {
2913 for (
auto view : std::as_const(m_views)) {
2914 static_cast<ViewPrivate *
>(view)->slotUpdateUndo();
2917 Q_EMIT modifiedChanged(
this);
2920 m_undoManager->setModified(m);
2926void KTextEditor::DocumentPrivate::makeAttribs(
bool needInvalidate)
2928 for (
auto view : std::as_const(m_views)) {
2929 static_cast<ViewPrivate *
>(view)->renderer()->updateAttributes();
2932 if (needInvalidate) {
2933 m_buffer->invalidateHighlighting();
2936 for (
auto v : std::as_const(m_views)) {
2937 auto view =
static_cast<ViewPrivate *
>(v);
2939 view->updateView(
true);
2944void KTextEditor::DocumentPrivate::internalHlChanged()
2949void KTextEditor::DocumentPrivate::addView(KTextEditor::View *view)
2951 Q_ASSERT(!m_views.contains(view));
2952 m_views.append(view);
2953 auto *v =
static_cast<KTextEditor::ViewPrivate *
>(view);
2956 if (!m_fileType.isEmpty()) {
2965 setActiveView(view);
2970 Q_ASSERT(m_views.contains(view));
2971 m_views.removeAll(view);
2973 if (activeView() == view) {
2974 setActiveView(
nullptr);
2980 if (m_activeView == view) {
2984 m_activeView =
static_cast<KTextEditor::ViewPrivate *
>(view);
2987bool KTextEditor::DocumentPrivate::ownedView(KTextEditor::ViewPrivate *view)
2990 return (m_views.contains(view));
2993int KTextEditor::DocumentPrivate::toVirtualColumn(
int line,
int column)
const
2995 Kate::TextLine textLine = m_buffer->plainLine(line);
2999int KTextEditor::DocumentPrivate::toVirtualColumn(
const KTextEditor::Cursor cursor)
const
3001 return toVirtualColumn(cursor.
line(), cursor.
column());
3004int KTextEditor::DocumentPrivate::fromVirtualColumn(
int line,
int column)
const
3006 Kate::TextLine textLine = m_buffer->plainLine(line);
3010int KTextEditor::DocumentPrivate::fromVirtualColumn(
const KTextEditor::Cursor cursor)
const
3012 return fromVirtualColumn(cursor.
line(), cursor.
column());
3015bool KTextEditor::DocumentPrivate::skipAutoBrace(QChar closingBracket, KTextEditor::Cursor pos)
3021 bool skipAutobrace = closingBracket == QLatin1Char(
'\'');
3022 if (highlight() && skipAutobrace) {
3024 skipAutobrace = highlight()->spellCheckingRequiredForLocation(
this, pos -
Cursor{0, 1});
3027 if (!skipAutobrace && (closingBracket == QLatin1Char(
'\''))) {
3029 Kate::TextLine textLine = m_buffer->plainLine(pos.
line());
3031 static const QRegularExpression re(QStringLiteral(
"(?<!\\\\)(?:\\\\\\\\)*\\\'"));
3033 skipAutobrace = (count % 2 == 0) ?
true : false;
3035 if (!skipAutobrace && (closingBracket == QLatin1Char(
'\"'))) {
3037 Kate::TextLine textLine = m_buffer->plainLine(pos.
line());
3038 static const QRegularExpression re(QStringLiteral(
"(?<!\\\\)(?:\\\\\\\\)*\\\""));
3040 skipAutobrace = (count % 2 == 0) ?
true : false;
3042 return skipAutobrace;
3053 QChar closingBracket;
3054 if (view->config()->autoBrackets()) {
3056 const QChar typedChar = chars.
at(0);
3057 const QChar openBracket = matchingStartBracket(typedChar);
3058 if (!openBracket.
isNull()) {
3060 if ((
characterAt(curPos) == typedChar) && findMatchingBracket(curPos, 123 ).isValid()) {
3062 view->cursorRight();
3068 if (chars.
size() == 1) {
3070 closingBracket = matchingEndBracket(typedChar);
3073 if (m_currentAutobraceClosingChar == typedChar && m_currentAutobraceRange) {
3075 m_currentAutobraceRange.reset(
nullptr);
3076 view->cursorRight();
3083 if (view->selection() && closingBracket.
isNull() && view->config()->encloseSelectionInChars()) {
3084 const QChar typedChar = chars.
at(0);
3085 if (view->config()->charsToEncloseSelection().
contains(typedChar)) {
3094 if (view->selection() && !closingBracket.
isNull()) {
3095 std::unique_ptr<KTextEditor::MovingRange> selectionRange(
newMovingRange(view->selectionRange()));
3096 const int startLine = qMax(0, selectionRange->start().line());
3097 const int endLine = qMin(selectionRange->end().line(),
lastLine());
3098 const bool blockMode = view->blockSelection() && (startLine != endLine);
3100 if (selectionRange->start().column() > selectionRange->end().column()) {
3106 const int startColumn = qMin(selectionRange->start().column(), selectionRange->end().column());
3107 const int endColumn = qMax(selectionRange->start().column(), selectionRange->end().column());
3111 insertText(r.
end(),
QString(closingBracket));
3112 view->slotTextInserted(view, r.
end(),
QString(closingBracket));
3113 insertText(r.
start(), chars);
3114 view->slotTextInserted(view, r.
start(), chars);
3118 for (
const auto &cursor : view->secondaryCursors()) {
3119 if (!cursor.range) {
3122 const auto &currSelectionRange = cursor.range;
3123 auto expandBehaviour = currSelectionRange->insertBehaviors();
3125 insertText(currSelectionRange->end(),
QString(closingBracket));
3126 insertText(currSelectionRange->start(), chars);
3127 currSelectionRange->setInsertBehaviors(expandBehaviour);
3128 cursor.pos->setPosition(currSelectionRange->end());
3129 auto mutableCursor =
const_cast<KTextEditor::ViewPrivate::SecondaryCursor *
>(&cursor);
3130 mutableCursor->anchor = currSelectionRange->start().toCursor();
3134 insertText(selectionRange->end(),
QString(closingBracket));
3135 view->slotTextInserted(view, selectionRange->end(),
QString(closingBracket));
3136 insertText(selectionRange->start(), chars);
3137 view->slotTextInserted(view, selectionRange->start(), chars);
3141 view->setSelection(selectionRange->toRange());
3142 view->setCursorPosition(selectionRange->end());
3149 if (!view->config()->persistentSelection() && view->selection()) {
3150 view->removeSelectedText();
3155 const bool multiLineBlockMode = view->blockSelection() && view->selection();
3156 if (view->currentInputMode()->overwrite()) {
3159 const int startLine = multiLineBlockMode ? qMax(0, selectionRange.
start().
line()) : view->cursorPosition().
line();
3160 const int endLine = multiLineBlockMode ? qMin(selectionRange.
end().
line(),
lastLine()) : startLine;
3161 const int virtualColumn = toVirtualColumn(multiLineBlockMode ? selectionRange.
end() : view->cursorPosition());
3165 const int column = fromVirtualColumn(
line, virtualColumn);
3171 view->currentInputMode()->overwrittenChar(removed);
3178 chars = eventuallyReplaceTabs(view->cursorPosition(), chars);
3180 if (multiLineBlockMode) {
3182 const int startLine = qMax(0, selectionRange.
start().
line());
3184 const int column = toVirtualColumn(selectionRange.
end());
3188 int newSelectionColumn = toVirtualColumn(view->cursorPosition());
3191 view->setSelection(selectionRange);
3196 view->completionWidget()->setIgnoreBufferSignals(
true);
3197 const auto &sc = view->secondaryCursors();
3199 const bool hasClosingBracket = !closingBracket.
isNull();
3200 const QString closingChar = closingBracket;
3202 std::vector<std::pair<Kate::TextCursor *, KTextEditor::Cursor>> freezedCursors;
3203 for (
auto it = sc.begin(); it != sc.end(); ++it) {
3204 auto pos = it->cursor();
3205 if (it != sc.begin() && pos == std::prev(it)->cursor()) {
3206 freezedCursors.push_back({std::prev(it)->pos.get(), std::prev(it)->cursor()});
3209 lastInsertionCursor = pos;
3210 insertText(pos, chars);
3213 if (it->cursor() == view->cursorPosition()) {
3214 freezedCursors.push_back({it->pos.get(), it->cursor()});
3217 const auto nextChar = view->document()->
text({pos, pos +
Cursor{0, 1}}).trimmed();
3218 if (hasClosingBracket && !skipAutoBrace(closingBracket, pos) && (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber())) {
3219 insertText(it->cursor(), closingChar);
3220 it->pos->setPosition(pos);
3224 view->completionWidget()->setIgnoreBufferSignals(
false);
3226 insertText(view->cursorPosition(), chars);
3228 for (
auto &freezed : freezedCursors) {
3229 freezed.first->setPosition(freezed.second);
3237 if (!closingBracket.
isNull() && !skipAutoBrace(closingBracket, view->cursorPosition())) {
3239 const auto cursorPos = view->cursorPosition();
3240 const auto nextChar = view->document()->
text({cursorPos, cursorPos +
Cursor{0, 1}}).trimmed();
3241 if (nextChar.isEmpty() || !nextChar.at(0).isLetterOrNumber()) {
3242 insertText(view->cursorPosition(),
QString(closingBracket));
3243 const auto insertedAt(view->cursorPosition());
3244 view->setCursorPosition(cursorPos);
3249 chars.
append(closingBracket);
3251 m_currentAutobraceClosingChar = closingBracket;
3258 const auto &secondaryCursors = view->secondaryCursors();
3259 for (
const auto &c : secondaryCursors) {
3260 m_indenter->userTypedChar(view, c.cursor(), chars.
isEmpty() ?
QChar() : chars.
at(chars.
length() - 1));
3268 view->slotTextInserted(view, oldCur, chars);
3273 if (m_currentAutobraceRange && !m_currentAutobraceRange->toRange().contains(newPos)) {
3274 m_currentAutobraceRange.reset();
3278void KTextEditor::DocumentPrivate::newLine(KTextEditor::ViewPrivate *v, KTextEditor::DocumentPrivate::NewLineIndent indent, NewLinePos newLinePos)
3282 if (!v->config()->persistentSelection() && v->selection()) {
3283 v->removeSelectedText();
3284 v->clearSelection();
3287 auto insertNewLine = [
this](KTextEditor::Cursor c) {
3288 if (c.line() > lastLine()) {
3289 c.setLine(lastLine());
3298 int len = lineLength(ln);
3300 if (c.column() > len) {
3305 editWrapLine(c.line(), c.column());
3308 m_buffer->updateHighlighting();
3313 auto adjustCusorPos = [newLinePos,
this](KTextEditor::Cursor pos) {
3315 bool moveCursorToTop =
false;
3316 if (newLinePos == Above) {
3317 if (pos.
line() <= 0) {
3320 moveCursorToTop =
true;
3325 }
else if (newLinePos == Below) {
3326 int lastCol = lineLength(pos.
line());
3329 return std::pair{pos, moveCursorToTop};
3333 const auto &secondaryCursors = v->secondaryCursors();
3334 if (!secondaryCursors.empty()) {
3337 for (
const auto &c : secondaryCursors) {
3338 const auto [newPos, moveCursorToTop] = adjustCusorPos(c.cursor());
3339 c.pos->setPosition(newPos);
3340 insertNewLine(c.cursor());
3341 if (moveCursorToTop) {
3342 c.pos->setPosition({0, 0});
3345 if (indent == KTextEditor::DocumentPrivate::Indent) {
3349 v->setCursorPosition(c.cursor());
3350 m_indenter->userTypedChar(v, c.cursor(), QLatin1Char(
'\n'));
3352 c.pos->setPosition(v->cursorPosition());
3356 v->setCursorPosition(savedPrimary.toCursor());
3359 const auto [newPos, moveCursorToTop] = adjustCusorPos(v->cursorPosition());
3360 v->setCursorPosition(newPos);
3361 insertNewLine(v->cursorPosition());
3362 if (moveCursorToTop) {
3363 v->setCursorPosition({0, 0});
3366 if (indent == KTextEditor::DocumentPrivate::Indent) {
3367 m_indenter->userTypedChar(v, v->cursorPosition(), QLatin1Char(
'\n'));
3373void KTextEditor::DocumentPrivate::transpose(
const KTextEditor::Cursor cursor)
3375 Kate::TextLine textLine = m_buffer->plainLine(cursor.
line());
3376 if (textLine.
length() < 2) {
3380 uint col = cursor.
column();
3386 if ((textLine.
length() - col) < 2) {
3390 uint line = cursor.
line();
3401 editRemoveText(line, col, 2);
3402 editInsertText(line, col, s);
3406void KTextEditor::DocumentPrivate::swapTextRanges(KTextEditor::Range firstWord, KTextEditor::Range secondWord)
3409 Q_ASSERT(!firstWord.
overlaps(secondWord));
3412 const KTextEditor::Range tempRange = firstWord;
3417 const QString tempString = text(secondWord);
3420 replaceText(secondWord, text(firstWord));
3421 replaceText(firstWord, tempString);
3425KTextEditor::Cursor KTextEditor::DocumentPrivate::backspaceAtCursor(KTextEditor::ViewPrivate *view, KTextEditor::Cursor c)
3427 int col = qMax(c.
column(), 0);
3428 int line = qMax(c.
line(), 0);
3429 if ((col == 0) && (line == 0)) {
3432 if (line >= lines()) {
3436 const Kate::TextLine textLine = m_buffer->plainLine(line);
3439 bool useNextBlock =
false;
3440 if (config()->backspaceIndents()) {
3447 if (pos < 0 || pos >= (
int)colX) {
3449 if ((
int)col > textLine.
length()) {
3451 return KTextEditor::Cursor(line, col - 1);
3453 indent(KTextEditor::Range(line, 0, line, 0), -1);
3455 useNextBlock =
true;
3458 if (!config()->backspaceIndents() || useNextBlock) {
3459 KTextEditor::Cursor beginCursor(line, 0);
3460 KTextEditor::Cursor endCursor(line, col);
3461 if (!view->config()->backspaceRemoveComposed()) {
3462 beginCursor.setColumn(col - 1);
3464 if (!isValidTextPosition(beginCursor)) {
3466 beginCursor.setColumn(col - 2);
3469 if (
auto l = view->textLayout(c)) {
3470 beginCursor.setColumn(l->previousCursorPosition(c.
column()));
3473 removeText(KTextEditor::Range(beginCursor, endCursor));
3481 const Kate::TextLine textLine = m_buffer->plainLine(line - 1);
3485 if (config()->wordWrap() && textLine.
endsWith(QStringLiteral(
" "))) {
3487 ret = KTextEditor::Cursor(line - 1, textLine.
length() - 1);
3488 removeText(KTextEditor::Range(line - 1, textLine.
length() - 1, line, 0));
3490 ret = KTextEditor::Cursor(line - 1, textLine.
length());
3491 removeText(KTextEditor::Range(line - 1, textLine.
length(), line, 0));
3498void KTextEditor::DocumentPrivate::backspace(KTextEditor::ViewPrivate *view)
3500 if (!view->config()->persistentSelection() && view->hasSelections()) {
3501 KTextEditor::Range range = view->selectionRange();
3504 if (view->blockSelection() && view->selection() && range.
start().
column() > 0 && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3507 view->setSelection(range);
3509 view->removeSelectedText();
3510 view->ensureUniqueCursors();
3518 const auto &multiCursors = view->secondaryCursors();
3519 view->completionWidget()->setIgnoreBufferSignals(
true);
3520 for (
const auto &c : multiCursors) {
3521 const auto newPos = backspaceAtCursor(view, c.cursor());
3526 view->completionWidget()->setIgnoreBufferSignals(
false);
3529 auto newPos = backspaceAtCursor(view, view->cursorPosition());
3531 view->setCursorPosition(newPos);
3534 view->ensureUniqueCursors();
3539 if (m_currentAutobraceRange) {
3540 const auto r = m_currentAutobraceRange->toRange();
3541 if (r.columnWidth() == 1 && view->cursorPosition() == r.
start()) {
3543 del(view, view->cursorPosition());
3544 m_currentAutobraceRange.reset();
3549void KTextEditor::DocumentPrivate::del(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor c)
3551 if (!view->config()->persistentSelection() && view->selection()) {
3552 KTextEditor::Range range = view->selectionRange();
3554 if (view->blockSelection() && toVirtualColumn(range.
start()) == toVirtualColumn(range.
end())) {
3557 view->setSelection(range);
3559 view->removeSelectedText();
3564 if (c.
column() < m_buffer->lineLength(c.
line())) {
3566 removeText(KTextEditor::Range(c, endCursor));
3567 }
else if (c.
line() < lastLine()) {
3568 removeText(KTextEditor::Range(c.
line(), c.
column(), c.
line() + 1, 0));
3572bool KTextEditor::DocumentPrivate::multiPaste(KTextEditor::ViewPrivate *view,
const QStringList &texts)
3574 if (texts.
isEmpty() || view->isMulticursorNotAllowed() || view->secondaryCursors().size() + 1 != (
size_t)texts.
size()) {
3578 m_undoManager->undoSafePoint();
3581 if (view->selection()) {
3582 view->removeSelectedText();
3585 auto plainSecondaryCursors = view->plainSecondaryCursors();
3586 KTextEditor::ViewPrivate::PlainSecondaryCursor primary;
3587 primary.pos = view->cursorPosition();
3588 primary.range = view->selectionRange();
3589 plainSecondaryCursors.append(primary);
3590 std::sort(plainSecondaryCursors.begin(), plainSecondaryCursors.end());
3592 static const QRegularExpression re(QStringLiteral(
"\r\n?"));
3594 for (
int i = texts.
size() - 1; i >= 0; --i) {
3595 QString text = texts[i];
3596 text.
replace(re, QStringLiteral(
"\n"));
3597 KTextEditor::Cursor pos = plainSecondaryCursors[i].pos;
3599 insertText(pos, text,
false);
3607void KTextEditor::DocumentPrivate::paste(KTextEditor::ViewPrivate *view,
const QString &text)
3617 s.
replace(QRegularExpression(QStringLiteral(
"\r\n?")), QStringLiteral(
"\n"));
3619 int lines = s.
count(QLatin1Char(
'\n'));
3620 const bool isSingleLine = lines == 0;
3622 m_undoManager->undoSafePoint();
3626 KTextEditor::Cursor pos = view->cursorPosition();
3628 bool skipIndentOnPaste =
false;
3630 const int length = lineLength(pos.
line());
3632 skipIndentOnPaste = length > 0;
3635 if (!view->config()->persistentSelection() && view->selection()) {
3636 pos = view->selectionRange().
start();
3637 if (view->blockSelection()) {
3638 pos = rangeOnLine(view->selectionRange(), pos.
line()).
start();
3640 s += QLatin1Char(
'\n');
3645 view->removeSelectedText();
3648 if (config()->ovr()) {
3649 const auto pasteLines = QStringView(s).split(QLatin1Char(
'\n'));
3651 if (!view->blockSelection()) {
3652 int endColumn = (pasteLines.count() == 1 ? pos.
column() : 0) + pasteLines.last().length();
3653 removeText(KTextEditor::Range(pos, pos.
line() + pasteLines.count() - 1, endColumn));
3655 int maxi = qMin(pos.
line() + pasteLines.count(), this->lines());
3657 for (
int i = pos.
line(); i < maxi; ++i) {
3658 int pasteLength = pasteLines.at(i - pos.
line()).length();
3659 removeText(KTextEditor::Range(i, pos.
column(), i, qMin(pasteLength + pos.
column(), lineLength(i))));
3664 insertText(pos, s, view->blockSelection());
3671 if (view->blockSelection()) {
3672 view->setCursorPositionInternal(pos);
3675 if (config()->indentPastedText()) {
3676 KTextEditor::Range range = KTextEditor::Range(KTextEditor::Cursor(pos.
line(), 0), KTextEditor::Cursor(pos.
line() + lines, 0));
3677 if (!skipIndentOnPaste) {
3678 m_indenter->indent(view, range);
3682 if (!view->blockSelection()) {
3683 Q_EMIT charactersSemiInteractivelyInserted(pos, s);
3685 m_undoManager->undoSafePoint();
3688void KTextEditor::DocumentPrivate::indent(KTextEditor::Range range,
int change)
3690 if (!isReadWrite()) {
3695 m_indenter->changeIndent(range, change);
3699void KTextEditor::DocumentPrivate::align(KTextEditor::ViewPrivate *view, KTextEditor::Range range)
3701 m_indenter->indent(view, range);
3704void KTextEditor::DocumentPrivate::alignOn(KTextEditor::Range range,
const QString &pattern,
bool blockwise)
3706 QStringList lines = textLines(range, blockwise);
3708 if (lines.
size() < 2) {
3712 QRegularExpression re(pattern.
isEmpty() ? QStringLiteral(
"[^\\s]") : pattern);
3714 int selectionStartColumn = range.
start().
column();
3715 QList<int> patternStartColumns;
3716 for (
const auto &line : lines) {
3717 QRegularExpressionMatch
match = re.match(line);
3718 if (!
match.hasMatch()) {
3719 patternStartColumns.
append(-1);
3720 }
else if (
match.lastCapturedIndex() == 0) {
3721 patternStartColumns.
append(
match.capturedStart(0) + (blockwise ? selectionStartColumn : 0));
3723 patternStartColumns.
append(
match.capturedStart(1) + (blockwise ? selectionStartColumn : 0));
3726 if (!blockwise && patternStartColumns[0] != -1) {
3727 patternStartColumns[0] += selectionStartColumn;
3730 int maxColumn = *std::max_element(patternStartColumns.
cbegin(), patternStartColumns.
cend());
3733 for (
int i = 0; i < lines.size(); ++i) {
3734 if (patternStartColumns[i] != -1) {
3735 insertText(KTextEditor::Cursor(range.
start().
line() + i, patternStartColumns[i]), QString(maxColumn - patternStartColumns[i],
QChar::Space));
3741void KTextEditor::DocumentPrivate::insertTab(KTextEditor::ViewPrivate *view,
const KTextEditor::Cursor)
3743 if (!isReadWrite()) {
3747 int lineLen = line(view->cursorPosition().
line()).length();
3748 KTextEditor::Cursor c = view->cursorPosition();
3752 if (!view->config()->persistentSelection() && view->selection()) {
3753 view->removeSelectedText();
3754 }
else if (view->currentInputMode()->overwrite() && c.
column() < lineLen) {
3755 KTextEditor::Range r = KTextEditor::Range(view->cursorPosition(), 1);
3758 QChar removed = line(view->cursorPosition().
line()).at(r.
start().
column());
3759 view->currentInputMode()->overwrittenChar(removed);
3763 c = view->cursorPosition();
3764 editInsertText(c.
line(), c.
column(), QStringLiteral(
"\t"));
3773bool KTextEditor::DocumentPrivate::removeStringFromBeginning(
int line,
const QString &str)
3775 Kate::TextLine textline = m_buffer->plainLine(line);
3777 KTextEditor::Cursor cursor(line, 0);
3787 removeText(KTextEditor::Range(cursor, str.
length()));
3797bool KTextEditor::DocumentPrivate::removeStringFromEnd(
int line,
const QString &str)
3799 Kate::TextLine textline = m_buffer->plainLine(line);
3801 KTextEditor::Cursor cursor(line, 0);
3802 bool there = textline.
endsWith(str);
3813 removeText(KTextEditor::Range(cursor, str.
length()));
3822QString KTextEditor::DocumentPrivate::eventuallyReplaceTabs(
const KTextEditor::Cursor cursorPos,
const QString &str)
const
3824 const bool replacetabs = config()->replaceTabsDyn();
3828 const int indentWidth = config()->indentationWidth();
3829 static const QLatin1Char tabChar(
'\t');
3831 int column = cursorPos.
column();
3837 for (
const QChar ch : str) {
3838 if (ch == tabChar) {
3841 int spacesToInsert = indentWidth - (column % indentWidth);
3842 result += QString(spacesToInsert, QLatin1Char(
' '));
3843 column += spacesToInsert;
3856void KTextEditor::DocumentPrivate::addStartLineCommentToSingleLine(
int line,
int attrib)
3858 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) + QLatin1Char(
' ');
3861 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3862 const Kate::TextLine l = kateTextLine(line);
3865 insertText(KTextEditor::Cursor(line, pos), commentLineMark);
3872bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSingleLine(
int line,
int attrib)
3874 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
3875 const QString longCommentMark = shortCommentMark + QLatin1Char(
' ');
3880 bool removed = (removeStringFromBeginning(line, longCommentMark) || removeStringFromBeginning(line, shortCommentMark));
3891void KTextEditor::DocumentPrivate::addStartStopCommentToSingleLine(
int line,
int attrib)
3893 const QString startCommentMark = highlight()->getCommentStart(attrib) + QLatin1Char(
' ');
3894 const QString stopCommentMark = QLatin1Char(
' ') + highlight()->getCommentEnd(attrib);
3899 insertText(KTextEditor::Cursor(line, 0), startCommentMark);
3902 const int col = m_buffer->lineLength(line);
3905 insertText(KTextEditor::Cursor(line, col), stopCommentMark);
3914bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSingleLine(
int line,
int attrib)
3916 const QString shortStartCommentMark = highlight()->getCommentStart(attrib);
3917 const QString longStartCommentMark = shortStartCommentMark + QLatin1Char(
' ');
3918 const QString shortStopCommentMark = highlight()->getCommentEnd(attrib);
3919 const QString longStopCommentMark = QLatin1Char(
' ') + shortStopCommentMark;
3924 const bool removedStart = (removeStringFromBeginning(line, longStartCommentMark) || removeStringFromBeginning(line, shortStartCommentMark));
3927 const bool removedStop = removedStart && (removeStringFromEnd(line, longStopCommentMark) || removeStringFromEnd(line, shortStopCommentMark));
3931 return (removedStart || removedStop);
3938void KTextEditor::DocumentPrivate::addStartStopCommentToSelection(KTextEditor::Range selection,
bool blockSelection,
int attrib)
3940 const QString startComment = highlight()->getCommentStart(attrib);
3941 const QString endComment = highlight()->getCommentEnd(attrib);
3943 KTextEditor::Range range = selection;
3951 if (!blockSelection) {
3952 insertText(range.
end(), endComment);
3953 insertText(range.
start(), startComment);
3955 for (
int line = range.
start().
line(); line <= range.
end().
line(); line++) {
3956 KTextEditor::Range subRange = rangeOnLine(range, line);
3957 insertText(subRange.
end(), endComment);
3958 insertText(subRange.
start(), startComment);
3969void KTextEditor::DocumentPrivate::addStartLineCommentToSelection(KTextEditor::Range selection,
int attrib)
3972 int el = selection.
end().
line();
3975 if ((selection.
end().
column() == 0) && (el > 0)) {
3979 if (sl < 0 || el < 0 || sl >= lines() || el >= lines()) {
3985 const QString commentLineMark = highlight()->getCommentSingleLineStart(attrib) + QLatin1Char(
' ');
3988 if (highlight()->getCommentSingleLinePosition(attrib) == KSyntaxHighlighting::CommentPosition::AfterWhitespace) {
3996 col = std::numeric_limits<int>::max();
3998 for (
int l = el; l >= sl; l--) {
3999 const auto line = plainKateTextLine(l);
4000 if (line.length() == 0) {
4003 col = qMin(col, qMax(0, line.firstChar()));
4010 if (col == std::numeric_limits<int>::max()) {
4017 for (
int l = el; l >= sl; l--) {
4018 insertText(KTextEditor::Cursor(l, col), commentLineMark);
4024bool KTextEditor::DocumentPrivate::nextNonSpaceCharPos(
int &line,
int &col)
4026 for (; line >= 0 && line < m_buffer->lines(); line++) {
4027 Kate::TextLine textLine = m_buffer->plainLine(line);
4040bool KTextEditor::DocumentPrivate::previousNonSpaceCharPos(
int &line,
int &col)
4042 while (line >= 0 && line < m_buffer->lines()) {
4043 Kate::TextLine textLine = m_buffer->plainLine(line);
4064bool KTextEditor::DocumentPrivate::removeStartStopCommentFromSelection(KTextEditor::Range selection,
int attrib)
4066 const QString startComment = highlight()->getCommentStart(attrib);
4067 const QString endComment = highlight()->getCommentEnd(attrib);
4069 int sl = qMax<int>(0, selection.
start().
line());
4070 int el = qMin<int>(selection.
end().
line(), lastLine());
4077 }
else if (el > 0) {
4079 ec = m_buffer->lineLength(el) - 1;
4082 const int startCommentLen = startComment.
length();
4083 const int endCommentLen = endComment.
length();
4087 bool remove = nextNonSpaceCharPos(sl, sc) && m_buffer->plainLine(sl).matchesAt(sc, startComment) && previousNonSpaceCharPos(el, ec)
4088 && ((ec - endCommentLen + 1) >= 0) && m_buffer->plainLine(el).matchesAt(ec - endCommentLen + 1, endComment);
4093 removeText(KTextEditor::Range(el, ec - endCommentLen + 1, el, ec + 1));
4094 removeText(KTextEditor::Range(sl, sc, sl, sc + startCommentLen));
4103bool KTextEditor::DocumentPrivate::removeStartStopCommentFromRegion(
const KTextEditor::Cursor
start,
const KTextEditor::Cursor end,
int attrib)
4105 const QString startComment = highlight()->getCommentStart(attrib);
4106 const QString endComment = highlight()->getCommentEnd(attrib);
4107 const int startCommentLen = startComment.
length();
4108 const int endCommentLen = endComment.
length();
4110 const bool remove = m_buffer->plainLine(
start.line()).matchesAt(
start.column(), startComment)
4111 && m_buffer->plainLine(
end.line()).matchesAt(
end.column() - endCommentLen, endComment);
4114 removeText(KTextEditor::Range(
end.line(),
end.column() - endCommentLen,
end.line(),
end.column()));
4115 removeText(KTextEditor::Range(
start, startCommentLen));
4125bool KTextEditor::DocumentPrivate::removeStartLineCommentFromSelection(KTextEditor::Range selection,
int attrib,
bool toggleComment)
4127 const QString shortCommentMark = highlight()->getCommentSingleLineStart(attrib);
4128 const QString longCommentMark = shortCommentMark + QLatin1Char(
' ');
4130 const int startLine = selection.
start().
line();
4131 int endLine = selection.
end().
line();
4133 if ((selection.
end().
column() == 0) && (endLine > 0)) {
4137 bool removed =
false;
4143 if (toggleComment) {
4144 bool allLinesAreCommented =
true;
4145 for (
int line = endLine; line >= startLine; line--) {
4146 const auto ln = m_buffer->plainLine(line);
4147 const QString &text = ln.text();
4152 QStringView textView(text.
data(), text.
size());
4154 textView = textView.trimmed();
4155 if (!textView.startsWith(shortCommentMark) && !textView.startsWith(longCommentMark)) {
4156 allLinesAreCommented =
false;
4160 if (!allLinesAreCommented) {
4168 for (
int z = endLine; z >= startLine; z--) {
4170 removed = (removeStringFromBeginning(z, longCommentMark) || removeStringFromBeginning(z, shortCommentMark) || removed);
4179void KTextEditor::DocumentPrivate::commentSelection(KTextEditor::Range selection, KTextEditor::Cursor c,
bool blockSelect, CommentType changeType)
4181 const bool hasSelection = !selection.
isEmpty();
4182 int selectionCol = 0;
4187 const int line = c.
line();
4189 int startAttrib = 0;
4190 Kate::TextLine ln = kateTextLine(line);
4192 if (selectionCol < ln.
length()) {
4193 startAttrib = ln.
attribute(selectionCol);
4198 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart(startAttrib).isEmpty());
4199 bool hasStartStopCommentMark = (!(highlight()->getCommentStart(startAttrib).isEmpty()) && !(highlight()->getCommentEnd(startAttrib).isEmpty()));
4201 if (changeType == Comment) {
4202 if (!hasSelection) {
4203 if (hasStartLineCommentMark) {
4204 addStartLineCommentToSingleLine(line, startAttrib);
4205 }
else if (hasStartStopCommentMark) {
4206 addStartStopCommentToSingleLine(line, startAttrib);
4216 const KTextEditor::Range sel = selection;
4217 if (hasStartStopCommentMark
4218 && (!hasStartLineCommentMark
4221 addStartStopCommentToSelection(selection, blockSelect, startAttrib);
4222 }
else if (hasStartLineCommentMark) {
4223 addStartLineCommentToSelection(selection, startAttrib);
4227 bool removed =
false;
4228 const bool toggleComment = changeType == ToggleComment;
4229 if (!hasSelection) {
4230 removed = (hasStartLineCommentMark && removeStartLineCommentFromSingleLine(line, startAttrib))
4231 || (hasStartStopCommentMark && removeStartStopCommentFromSingleLine(line, startAttrib));
4234 removed = (hasStartStopCommentMark && removeStartStopCommentFromSelection(selection, startAttrib))
4235 || (hasStartLineCommentMark && removeStartLineCommentFromSelection(selection, startAttrib, toggleComment));
4239 if (!removed && toggleComment) {
4240 commentSelection(selection, c, blockSelect, Comment);
4249void KTextEditor::DocumentPrivate::comment(KTextEditor::ViewPrivate *v, uint line, uint column, CommentType change)
4252 const bool skipWordWrap = wordWrap();
4259 if (v->selection()) {
4260 const auto &cursors = v->secondaryCursors();
4261 for (
const auto &c : cursors) {
4265 commentSelection(c.range->toRange(), c.cursor(),
false, change);
4267 KTextEditor::Cursor c(line, column);
4268 commentSelection(v->selectionRange(), c, v->blockSelection(), change);
4270 const auto &cursors = v->secondaryCursors();
4271 for (
const auto &c : cursors) {
4272 commentSelection({}, c.cursor(),
false, change);
4274 commentSelection({}, KTextEditor::Cursor(line, column),
false, change);
4284void KTextEditor::DocumentPrivate::transformCursorOrRange(KTextEditor::ViewPrivate *v,
4285 KTextEditor::Cursor c,
4286 KTextEditor::Range selection,
4287 KTextEditor::DocumentPrivate::TextTransform t)
4289 if (v->selection()) {
4292 KTextEditor::Range range(selection.
start(), 0);
4301 if (range.
start().
line() == selection.
end().
line() || v->blockSelection()) {
4306 int swapCol =
start;
4313 QString s = text(range);
4316 if (t == Uppercase) {
4319 }
else if (t == Lowercase) {
4323 Kate::TextLine l = m_buffer->plainLine(range.
start().
line());
4332 && !highlight()->isInWord(l.
at(range.
start().
column() - 1)))
4333 || (p && !highlight()->isInWord(s.
at(p - 1)))) {
4342 insertText(range.
start(), s);
4353 KTextEditor::Cursor cursor = c;
4355 QString old = text(KTextEditor::Range(cursor, 1));
4365 Kate::TextLine l = m_buffer->plainLine(cursor.
line());
4369 old = text(KTextEditor::Range(cursor, 1));
4376 removeText(KTextEditor::Range(cursor, 1));
4377 insertText(cursor, s);
4387 if (v->selection()) {
4388 const auto &cursors = v->secondaryCursors();
4389 for (
const auto &c : cursors) {
4393 auto pos = c.pos->toCursor();
4394 transformCursorOrRange(v, c.anchor, c.range->toRange(), t);
4398 const auto selRange = v->selectionRange();
4399 transformCursorOrRange(v, c, v->selectionRange(), t);
4400 v->setSelection(selRange);
4401 v->setCursorPosition(c);
4403 const auto &secondaryCursors = v->secondaryCursors();
4404 for (
const auto &c : secondaryCursors) {
4405 transformCursorOrRange(v, c.cursor(), {}, t);
4407 transformCursorOrRange(v, c, {}, t);
4418 while (first < last) {
4453 for (
auto view : std::as_const(m_views)) {
4454 static_cast<ViewPrivate *
>(view)->tagLines(lineRange,
true);
4458void KTextEditor::DocumentPrivate::tagLine(
int line)
4460 tagLines({line, line});
4463void KTextEditor::DocumentPrivate::repaintViews(
bool paintOnlyDirty)
4465 for (
auto view : std::as_const(m_views)) {
4466 static_cast<ViewPrivate *
>(view)->repaintText(paintOnlyDirty);
4477KTextEditor::Range KTextEditor::DocumentPrivate::findMatchingBracket(
const KTextEditor::Cursor
start,
int maxLines)
4479 if (maxLines < 0 ||
start.line() < 0 ||
start.line() >= lines()) {
4483 Kate::TextLine textLine = m_buffer->plainLine(
start.line());
4489 if (config()->ovr()) {
4490 if (isBracket(right)) {
4495 }
else if (isBracket(right)) {
4497 }
else if (isBracket(left)) {
4504 const QChar opposite = matchingBracket(bracket);
4509 const int searchDir = isStartBracket(bracket) ? 1 : -1;
4512 const int minLine = qMax(range.
start().
line() - maxLines, 0);
4513 const int maxLine = qMin(range.
start().
line() + maxLines, documentEnd().line());
4516 KTextEditor::DocumentCursor cursor(
this);
4518 int validAttr = kateTextLine(cursor.
line()).attribute(cursor.
column());
4520 while (cursor.
line() >= minLine && cursor.
line() <= maxLine) {
4521 if (!cursor.move(searchDir)) {
4525 Kate::TextLine textLine = kateTextLine(cursor.
line());
4528 QChar c = textLine.
at(cursor.
column());
4529 if (c == opposite) {
4531 if (searchDir > 0) {
4532 range.
setEnd(cursor.toCursor());
4539 }
else if (c == bracket) {
4549inline static QString removeNewLines(
const QString &str)
4552 return tmp.replace(QLatin1String(
"\r\n"), QLatin1String(
" ")).replace(QLatin1Char(
'\r'), QLatin1Char(
' ')).replace(QLatin1Char(
'\n'), QLatin1Char(
' '));
4555void KTextEditor::DocumentPrivate::updateDocName()
4558 if (!url().isEmpty() && (m_docName == removeNewLines(url().fileName()) || m_docName.
startsWith(removeNewLines(url().fileName()) + QLatin1String(
" (")))) {
4564 std::vector<KTextEditor::DocumentPrivate *> docsWithSameName;
4567 for (KTextEditor::Document *kteDoc : docs) {
4568 auto doc =
static_cast<KTextEditor::DocumentPrivate *
>(kteDoc);
4569 if ((doc !=
this) && (doc->url().fileName() == url().fileName())) {
4570 if (doc->m_docNameNumber > count) {
4571 count = doc->m_docNameNumber;
4573 docsWithSameName.push_back(doc);
4577 m_docNameNumber = count + 1;
4579 QString oldName = m_docName;
4580 m_docName = removeNewLines(url().fileName());
4582 m_isUntitled = m_docName.isEmpty();
4584 if (!m_isUntitled && !docsWithSameName.empty()) {
4585 docsWithSameName.push_back(
this);
4586 uniquifyDocNames(docsWithSameName);
4591 m_docName =
i18n(
"Untitled");
4594 if (m_docNameNumber > 0) {
4595 m_docName = QString(m_docName + QLatin1String(
" (%1)")).arg(m_docNameNumber + 1);
4599 if (oldName != m_docName) {
4600 Q_EMIT documentNameChanged(
this);
4615static QString shortestPrefix(
const std::vector<QString> &urls, KTextEditor::DocumentPrivate *doc)
4618 int lastSlash = url.lastIndexOf(QLatin1Char(
'/'));
4619 if (lastSlash == -1) {
4623 int fileNameStart = lastSlash;
4626 lastSlash = url.lastIndexOf(QLatin1Char(
'/'), lastSlash);
4627 if (lastSlash == -1) {
4630 return url.mid(lastSlash, fileNameStart);
4633 QStringView urlView = url;
4634 QStringView urlv = url;
4635 urlv = urlv.
mid(lastSlash);
4637 for (
size_t i = 0; i < urls.size(); ++i) {
4638 if (urls[i] == url) {
4642 if (urls[i].endsWith(urlv)) {
4643 lastSlash = url.lastIndexOf(QLatin1Char(
'/'), lastSlash - 1);
4644 if (lastSlash <= 0) {
4646 return url.mid(0, fileNameStart);
4649 urlv = urlView.
mid(lastSlash);
4654 return url.mid(lastSlash + 1, fileNameStart - (lastSlash + 1));
4657void KTextEditor::DocumentPrivate::uniquifyDocNames(
const std::vector<KTextEditor::DocumentPrivate *> &docs)
4659 std::vector<QString> paths;
4660 paths.reserve(docs.size());
4661 std::transform(docs.begin(), docs.end(), std::back_inserter(paths), [](
const KTextEditor::DocumentPrivate *d) {
4662 return d->url().toString(QUrl::NormalizePathSegments | QUrl::PreferLocalFile);
4665 for (
const auto doc : docs) {
4666 const QString prefix = shortestPrefix(paths, doc);
4668 const QString oldName = doc->m_docName;
4671 doc->m_docName = fileName + QStringLiteral(
" - ") + prefix;
4673 doc->m_docName = fileName;
4676 if (doc->m_docName != oldName) {
4689 onModOnHdAutoReload();
4693 if (!m_fileChangedDialogsActivated || m_modOnHdHandler) {
4698 if (m_modOnHdReason == m_prevModOnHdReason) {
4701 m_prevModOnHdReason = m_modOnHdReason;
4703 m_modOnHdHandler =
new KateModOnHdPrompt(
this, m_modOnHdReason, reasonedMOHString());
4704 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::saveAsTriggered,
this, &DocumentPrivate::onModOnHdSaveAs);
4705 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::closeTriggered,
this, &DocumentPrivate::onModOnHdClose);
4706 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::reloadTriggered,
this, &DocumentPrivate::onModOnHdReload);
4707 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::autoReloadTriggered,
this, &DocumentPrivate::onModOnHdAutoReload);
4708 connect(m_modOnHdHandler.data(), &KateModOnHdPrompt::ignoreTriggered,
this, &DocumentPrivate::onModOnHdIgnore);
4711void KTextEditor::DocumentPrivate::onModOnHdSaveAs()
4714 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
4720 delete m_modOnHdHandler;
4721 m_prevModOnHdReason = OnDiskUnmodified;
4722 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4729void KTextEditor::DocumentPrivate::onModOnHdClose()
4735 m_fileChangedDialogsActivated =
false;
4740 m_fileChangedDialogsActivated =
true;
4745void KTextEditor::DocumentPrivate::onModOnHdReload()
4748 m_prevModOnHdReason = OnDiskUnmodified;
4749 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4755 m_undoManager->clearUndo();
4756 m_undoManager->clearRedo();
4759 delete m_modOnHdHandler;
4762void KTextEditor::DocumentPrivate::autoReloadToggled(
bool b)
4764 m_autoReloadMode->setChecked(b);
4768 disconnect(&m_modOnHdTimer, &
QTimer::timeout,
this, &DocumentPrivate::onModOnHdAutoReload);
4772bool KTextEditor::DocumentPrivate::isAutoReload()
4774 return m_autoReloadMode->isChecked();
4777void KTextEditor::DocumentPrivate::delayAutoReload()
4779 if (isAutoReload()) {
4780 m_autoReloadThrottle.start();
4784void KTextEditor::DocumentPrivate::onModOnHdAutoReload()
4786 if (m_modOnHdHandler) {
4787 delete m_modOnHdHandler;
4788 autoReloadToggled(
true);
4791 if (!isAutoReload()) {
4795 if (m_modOnHd && !m_reloading && !m_autoReloadThrottle.isActive()) {
4797 m_prevModOnHdReason = OnDiskUnmodified;
4798 Q_EMIT modifiedOnDisk(
this,
false, OnDiskUnmodified);
4802 m_undoManager->clearUndo();
4803 m_undoManager->clearRedo();
4806 m_autoReloadThrottle.start();
4810void KTextEditor::DocumentPrivate::onModOnHdIgnore()
4813 delete m_modOnHdHandler;
4818 m_modOnHdReason = reason;
4823class KateDocumentTmpMark
4832 m_fileChangedDialogsActivated = on;
4849 m_undoManager->clearUndo();
4850 m_undoManager->clearRedo();
4855 delete m_modOnHdHandler;
4861 std::transform(m_marks.cbegin(), m_marks.cend(), std::back_inserter(tmp), [
this](
KTextEditor::Mark *
mark) {
4862 return KateDocumentTmpMark{.line = line(mark->line), .mark = *mark};
4866 const QString oldMode = mode();
4867 const bool modeByUser = m_fileTypeSetByUser;
4868 const QString oldHlMode = highlightingMode();
4869 const bool hlByUser = m_hlSetByUser;
4871 m_storedVariables.clear();
4875 std::transform(m_views.cbegin(), m_views.cend(), std::back_inserter(cursorPositions), [](
KTextEditor::View *v) {
4876 return std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor>(static_cast<ViewPrivate *>(v), v->cursorPosition());
4881 for (
auto *view : m_views) {
4882 static_cast<ViewPrivate *
>(view)->clearSecondaryCursors();
4885 static_cast<ViewPrivate *
>(view)->clearFoldingState();
4890 KTextEditor::DocumentPrivate::openUrl(url());
4893 m_userSetEncodingForNextReload =
false;
4896 for (
auto v : std::as_const(m_views)) {
4898 auto it = std::find_if(cursorPositions.
cbegin(), cursorPositions.
cend(), [v](
const std::pair<KTextEditor::ViewPrivate *, KTextEditor::Cursor> &p) {
4899 return p.first == v;
4901 v->setCursorPosition(it->second);
4907 const int lines = this->lines();
4908 for (
const auto &tmpMark : tmp) {
4909 if (tmpMark.mark.line < lines) {
4910 if (tmpMark.line == line(tmpMark.mark.line)) {
4911 setMark(tmpMark.mark.line, tmpMark.mark.type);
4918 updateFileType(oldMode,
true);
4921 setHighlightingMode(oldHlMode);
4924 Q_EMIT reloaded(
this);
4929bool KTextEditor::DocumentPrivate::documentSave()
4931 if (!url().
isValid() || !isReadWrite()) {
4932 return documentSaveAs();
4938bool KTextEditor::DocumentPrivate::documentSaveAs()
4940 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4948bool KTextEditor::DocumentPrivate::documentSaveAsWithEncoding(
const QString &encoding)
4950 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save File"));
4955 setEncoding(encoding);
4959void KTextEditor::DocumentPrivate::documentSaveCopyAs()
4961 const QUrl saveUrl = getSaveFileUrl(
i18n(
"Save Copy of File"));
4966 QTemporaryFile *file =
new QTemporaryFile();
4967 if (!file->
open()) {
4971 if (!m_buffer->saveFile(file->
fileName())) {
4973 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 "
4974 "that enough disk space is available.",
4982 const auto url = this->url();
4984 if (
auto sj = qobject_cast<KIO::StatJob *>(j)) {
4985 const int permissions = KFileItem(sj->statResult(), url).permissions();
4995void KTextEditor::DocumentPrivate::setWordWrap(
bool on)
4997 config()->setWordWrap(on);
5000bool KTextEditor::DocumentPrivate::wordWrap()
const
5002 return config()->wordWrap();
5005void KTextEditor::DocumentPrivate::setWordWrapAt(uint col)
5007 config()->setWordWrapAt(col);
5010unsigned int KTextEditor::DocumentPrivate::wordWrapAt()
const
5012 return config()->wordWrapAt();
5015void KTextEditor::DocumentPrivate::setPageUpDownMovesCursor(
bool on)
5017 config()->setPageUpDownMovesCursor(on);
5020bool KTextEditor::DocumentPrivate::pageUpDownMovesCursor()
const
5022 return config()->pageUpDownMovesCursor();
5028 return m_config->setEncoding(e);
5033 return m_config->encoding();
5036void KTextEditor::DocumentPrivate::updateConfig()
5038 m_undoManager->updateConfig();
5041 m_indenter->setMode(m_config->indentationMode());
5042 m_indenter->updateConfig();
5045 m_buffer->setTabWidth(config()->tabWidth());
5048 for (
auto view : std::as_const(m_views)) {
5049 static_cast<ViewPrivate *
>(view)->updateDocumentConfig();
5053 if (m_onTheFlyChecker) {
5054 m_onTheFlyChecker->updateConfig();
5057 if (config()->autoSave()) {
5058 int interval = config()->autoSaveInterval();
5059 if (interval == 0) {
5060 m_autoSaveTimer.stop();
5062 m_autoSaveTimer.setInterval(interval * 1000);
5064 m_autoSaveTimer.start();
5069 Q_EMIT configChanged(
this);
5079bool KTextEditor::DocumentPrivate::readVariables(KTextEditor::ViewPrivate *view)
5081 const bool hasVariableline = [
this] {
5082 const QLatin1String s(
"kate");
5084 for (
int i = qMax(10, lines() - 10); i < lines(); ++i) {
5085 if (line(i).contains(s)) {
5090 for (
int i = 0; i < qMin(9, lines()); ++i) {
5091 if (line(i).contains(s)) {
5097 if (!hasVariableline) {
5102 m_config->configStart();
5103 for (
auto view : std::as_const(m_views)) {
5104 auto v =
static_cast<ViewPrivate *
>(view);
5115 for (
int i = 0; i < qMin(9, lines()); ++i) {
5116 readVariableLine(line(i), view);
5119 for (
int i = qMax(10, lines() - 10); i < lines(); i++) {
5120 readVariableLine(line(i), view);
5125 m_config->configEnd();
5126 for (
auto view : std::as_const(m_views)) {
5127 auto v =
static_cast<ViewPrivate *
>(view);
5139void KTextEditor::DocumentPrivate::readVariableLine(
const QString &t, KTextEditor::ViewPrivate *view)
5141 static const QRegularExpression kvLine(QStringLiteral(
"kate:(.*)"));
5142 static const QRegularExpression kvLineWildcard(QStringLiteral(
"kate-wildcard\\((.*)\\):(.*)"));
5143 static const QRegularExpression kvLineMime(QStringLiteral(
"kate-mimetype\\((.*)\\):(.*)"));
5144 static const QRegularExpression kvVar(QStringLiteral(
"([\\w\\-]+)\\s+([^;]+)"));
5148 if (!t.
contains(QLatin1String(
"kate"))) {
5156 auto match = kvLine.match(t);
5157 if (
match.hasMatch()) {
5158 s =
match.captured(1);
5161 }
else if ((match = kvLineWildcard.match(t)).hasMatch()) {
5163 const QString nameOfFile = url().
fileName();
5164 const QString pathOfFile = url().
path();
5167 for (
const QString &pattern : wildcards) {
5170 const bool matchPath = pattern.
contains(QLatin1Char(
'/'));
5174 found = wildcard.match(matchPath ? pathOfFile : nameOfFile).hasMatch();
5185 s =
match.captured(2);
5188 }
else if ((match = kvLineMime.match(t)).hasMatch()) {
5196 s =
match.captured(2);
5204 static const auto vvl = {
5205 QLatin1String(
"dynamic-word-wrap"),
5206 QLatin1String(
"dynamic-word-wrap-indicators"),
5207 QLatin1String(
"line-numbers"),
5208 QLatin1String(
"icon-border"),
5209 QLatin1String(
"folding-markers"),
5210 QLatin1String(
"folding-preview"),
5211 QLatin1String(
"bookmark-sorting"),
5212 QLatin1String(
"auto-center-lines"),
5213 QLatin1String(
"icon-bar-color"),
5214 QLatin1String(
"scrollbar-minimap"),
5215 QLatin1String(
"scrollbar-preview"),
5216 QLatin1String(
"enter-to-insert-completion")
5219 QLatin1String(
"background-color"),
5220 QLatin1String(
"selection-color"),
5221 QLatin1String(
"current-line-color"),
5222 QLatin1String(
"bracket-highlight-color"),
5223 QLatin1String(
"word-wrap-marker-color"),
5224 QLatin1String(
"font"),
5225 QLatin1String(
"font-size"),
5226 QLatin1String(
"scheme"),
5228 int spaceIndent = -1;
5229 bool replaceTabsSet =
false;
5234 while ((match = kvVar.match(s, startPos)).hasMatch()) {
5235 startPos =
match.capturedEnd(0);
5236 var =
match.captured(1);
5237 val =
match.captured(2).trimmed();
5243 if (contains(vvl, var)) {
5244 KTextEditor::View *v =
static_cast<KTextEditor::View *
>(view);
5245 setViewVariable(var, val, {&v, 1});
5249 if (var == QLatin1String(
"word-wrap") && checkBoolValue(val, &state)) {
5254 else if (var == QLatin1String(
"backspace-indents") && checkBoolValue(val, &state)) {
5255 m_config->setBackspaceIndents(state);
5256 }
else if (var == QLatin1String(
"indent-pasted-text") && checkBoolValue(val, &state)) {
5257 m_config->setIndentPastedText(state);
5258 }
else if (var == QLatin1String(
"replace-tabs") && checkBoolValue(val, &state)) {
5259 m_config->setReplaceTabsDyn(state);
5260 replaceTabsSet =
true;
5261 }
else if (var == QLatin1String(
"remove-trailing-space") && checkBoolValue(val, &state)) {
5262 qCWarning(LOG_KTE) <<
i18n(
5263 "Using deprecated modeline 'remove-trailing-space'. "
5264 "Please replace with 'remove-trailing-spaces modified;', see "
5265 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5266 m_config->setRemoveSpaces(state ? 1 : 0);
5267 }
else if (var == QLatin1String(
"replace-trailing-space-save") && checkBoolValue(val, &state)) {
5268 qCWarning(LOG_KTE) <<
i18n(
5269 "Using deprecated modeline 'replace-trailing-space-save'. "
5270 "Please replace with 'remove-trailing-spaces all;', see "
5271 "https://docs.kde.org/?application=katepart&branch=stable5&path=config-variables.html#variable-remove-trailing-spaces");
5272 m_config->setRemoveSpaces(state ? 2 : 0);
5273 }
else if (var == QLatin1String(
"overwrite-mode") && checkBoolValue(val, &state)) {
5274 m_config->setOvr(state);
5275 }
else if (var == QLatin1String(
"keep-extra-spaces") && checkBoolValue(val, &state)) {
5276 m_config->setKeepExtraSpaces(state);
5277 }
else if (var == QLatin1String(
"tab-indents") && checkBoolValue(val, &state)) {
5278 m_config->setTabIndents(state);
5279 }
else if (var == QLatin1String(
"show-tabs") && checkBoolValue(val, &state)) {
5280 m_config->setShowTabs(state);
5281 }
else if (var == QLatin1String(
"show-trailing-spaces") && checkBoolValue(val, &state)) {
5282 m_config->setShowSpaces(state ? KateDocumentConfig::Trailing : KateDocumentConfig::None);
5283 }
else if (var == QLatin1String(
"space-indent") && checkBoolValue(val, &state)) {
5285 spaceIndent = state;
5286 }
else if (var == QLatin1String(
"smart-home") && checkBoolValue(val, &state)) {
5287 m_config->setSmartHome(state);
5288 }
else if (var == QLatin1String(
"newline-at-eof") && checkBoolValue(val, &state)) {
5289 m_config->setNewLineAtEof(state);
5293 else if (var == QLatin1String(
"tab-width") && checkIntValue(val, &n)) {
5294 m_config->setTabWidth(n);
5295 }
else if (var == QLatin1String(
"indent-width") && checkIntValue(val, &n)) {
5296 m_config->setIndentationWidth(n);
5297 }
else if (var == QLatin1String(
"indent-mode")) {
5298 m_config->setIndentationMode(val);
5299 }
else if (var == QLatin1String(
"word-wrap-column") && checkIntValue(val, &n) && n > 0) {
5300 m_config->setWordWrapAt(n);
5304 else if (var == QLatin1String(
"eol") || var == QLatin1String(
"end-of-line")) {
5305 const auto l = {QLatin1String(
"unix"), QLatin1String(
"dos"), QLatin1String(
"mac")};
5306 if ((n = indexOf(l, val.
toLower())) != -1) {
5309 m_config->setEol(n);
5310 m_config->setAllowEolDetection(
false);
5312 }
else if (var == QLatin1String(
"bom") || var == QLatin1String(
"byte-order-mark") || var == QLatin1String(
"byte-order-marker")) {
5313 if (checkBoolValue(val, &state)) {
5314 m_config->setBom(state);
5316 }
else if (var == QLatin1String(
"remove-trailing-spaces")) {
5318 if (val == QLatin1String(
"1") || val == QLatin1String(
"modified") || val == QLatin1String(
"mod") || val == QLatin1String(
"+")) {
5319 m_config->setRemoveSpaces(1);
5320 }
else if (val == QLatin1String(
"2") || val == QLatin1String(
"all") || val == QLatin1String(
"*")) {
5321 m_config->setRemoveSpaces(2);
5323 m_config->setRemoveSpaces(0);
5325 }
else if (var == QLatin1String(
"syntax") || var == QLatin1String(
"hl")) {
5326 setHighlightingMode(val);
5327 }
else if (var == QLatin1String(
"mode")) {
5329 }
else if (var == QLatin1String(
"encoding")) {
5331 }
else if (var == QLatin1String(
"default-dictionary")) {
5332 setDefaultDictionary(val);
5333 }
else if (var == QLatin1String(
"automatic-spell-checking") && checkBoolValue(val, &state)) {
5334 onTheFlySpellCheckingEnabled(state);
5338 else if (contains(vvl, var)) {
5339 setViewVariable(var, val, m_views);
5341 m_storedVariables[var] = val;
5353 if (!replaceTabsSet && spaceIndent >= 0) {
5354 m_config->setReplaceTabsDyn(spaceIndent > 0);
5358void KTextEditor::DocumentPrivate::setViewVariable(
const QString &var,
const QString &val, std::span<KTextEditor::View *> views)
5363 for (
auto view : views) {
5364 auto v =
static_cast<ViewPrivate *
>(view);
5367 if (checkBoolValue(val, &state)) {
5370 if (v->config()->
setValue(var, help)) {
5371 }
else if (v->rendererConfig()->
setValue(var, help)) {
5373 }
else if (var == QLatin1String(
"dynamic-word-wrap") && checkBoolValue(val, &state)) {
5374 v->config()->setDynWordWrap(state);
5375 }
else if (var == QLatin1String(
"block-selection") && checkBoolValue(val, &state)) {
5376 v->setBlockSelection(state);
5379 }
else if (var == QLatin1String(
"icon-bar-color") && checkColorValue(val, c)) {
5380 v->rendererConfig()->setIconBarColor(c);
5383 else if (var == QLatin1String(
"background-color") && checkColorValue(val, c)) {
5384 v->rendererConfig()->setBackgroundColor(c);
5385 }
else if (var == QLatin1String(
"selection-color") && checkColorValue(val, c)) {
5386 v->rendererConfig()->setSelectionColor(c);
5387 }
else if (var == QLatin1String(
"current-line-color") && checkColorValue(val, c)) {
5388 v->rendererConfig()->setHighlightedLineColor(c);
5389 }
else if (var == QLatin1String(
"bracket-highlight-color") && checkColorValue(val, c)) {
5390 v->rendererConfig()->setHighlightedBracketColor(c);
5391 }
else if (var == QLatin1String(
"word-wrap-marker-color") && checkColorValue(val, c)) {
5392 v->rendererConfig()->setWordWrapMarkerColor(c);
5393 }
else if (var == QLatin1String(
"font") || (checkIntValue(val, &n) && n > 0 && var == QLatin1String(
"font-size"))) {
5396 if (var == QLatin1String(
"font")) {
5398 _f.setFixedPitch(QFont(val).fixedPitch());
5403 v->rendererConfig()->setFont(_f);
5404 }
else if (var == QLatin1String(
"scheme")) {
5405 v->rendererConfig()->setSchema(val);
5410bool KTextEditor::DocumentPrivate::checkBoolValue(QString val,
bool *result)
5413 static const auto trueValues = {QLatin1String(
"1"), QLatin1String(
"on"), QLatin1String(
"true")};
5414 if (contains(trueValues, val)) {
5419 static const auto falseValues = {QLatin1String(
"0"), QLatin1String(
"off"), QLatin1String(
"false")};
5420 if (contains(falseValues, val)) {
5427bool KTextEditor::DocumentPrivate::checkIntValue(
const QString &val,
int *result)
5430 *result = val.
toInt(&ret);
5434bool KTextEditor::DocumentPrivate::checkColorValue(
const QString &val, QColor &c)
5443 auto it = m_storedVariables.find(name);
5444 if (it == m_storedVariables.end()) {
5452 QString s = QStringLiteral(
"kate: ");
5456 readVariableLine(s);
5461void KTextEditor::DocumentPrivate::slotModOnHdDirty(
const QString &path)
5463 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskModified)) {
5465 m_modOnHdReason = OnDiskModified;
5467 if (!m_modOnHdTimer.isActive()) {
5468 m_modOnHdTimer.start();
5473void KTextEditor::DocumentPrivate::slotModOnHdCreated(
const QString &path)
5475 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskCreated)) {
5477 m_modOnHdReason = OnDiskCreated;
5479 if (!m_modOnHdTimer.isActive()) {
5480 m_modOnHdTimer.start();
5485void KTextEditor::DocumentPrivate::slotModOnHdDeleted(
const QString &path)
5487 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != OnDiskDeleted)) {
5489 m_modOnHdReason = OnDiskDeleted;
5491 if (!m_modOnHdTimer.isActive()) {
5492 m_modOnHdTimer.start();
5497void KTextEditor::DocumentPrivate::slotDelayedHandleModOnHd()
5500 const QByteArray oldDigest = checksum();
5501 if (!oldDigest.
isEmpty() && !url().isEmpty() && url().isLocalFile()) {
5503 if (m_modOnHdReason != OnDiskDeleted && m_modOnHdReason != OnDiskCreated && createDigest() && oldDigest == checksum()) {
5505 m_modOnHdReason = OnDiskUnmodified;
5506 m_prevModOnHdReason = OnDiskUnmodified;
5513 if (m_modOnHd && !isModified() &&
QFile::exists(url().toLocalFile())
5514 && config()->value(KateDocumentConfig::AutoReloadIfStateIsInVersionControl).toBool()) {
5519 const QStringList args{QStringLiteral(
"cat-file"), QStringLiteral(
"-e"),
QString::fromUtf8(oldDigest.
toHex())};
5521 git.
start(fullGitPath, args);
5528 m_modOnHdReason = OnDiskUnmodified;
5529 m_prevModOnHdReason = OnDiskUnmodified;
5539 Q_EMIT modifiedOnDisk(
this, m_modOnHd, m_modOnHdReason);
5544 return m_buffer->digest();
5547bool KTextEditor::DocumentPrivate::createDigest()
5551 if (url().isLocalFile()) {
5552 QFile f(url().toLocalFile());
5556 const QString header = QStringLiteral(
"blob %1").
arg(f.size());
5559 digest = crypto.result();
5564 m_buffer->setDigest(digest);
5568QString KTextEditor::DocumentPrivate::reasonedMOHString()
const
5573 switch (m_modOnHdReason) {
5574 case OnDiskModified:
5575 return i18n(
"The file '%1' was modified on disk.", str);
5578 return i18n(
"The file '%1' was created on disk.", str);
5581 return i18n(
"The file '%1' was deleted or moved on disk.", str);
5590void KTextEditor::DocumentPrivate::removeTrailingSpacesAndAddNewLineAtEof()
5593 const int remove = config()->removeSpaces();
5594 const bool newLineAtEof = config()->newLineAtEof();
5595 if (remove == 0 && !newLineAtEof) {
5600 const bool wordWrapEnabled = config()->wordWrap();
5601 if (wordWrapEnabled) {
5608 const int lines = this->lines();
5610 for (
int line = 0; line < lines; ++line) {
5611 Kate::TextLine textline = plainKateTextLine(line);
5616 if (remove == 2 || textline.markedAsModified() || textline.markedAsSavedOnDisk()) {
5617 const int p = textline.
lastChar() + 1;
5618 const int l = textline.
length() - p;
5620 editRemoveText(line, p, l);
5629 Q_ASSERT(lines > 0);
5630 const auto length = lineLength(lines - 1);
5634 const auto oldEndOfDocumentCursor = documentEnd();
5635 std::vector<KTextEditor::ViewPrivate *> viewsToRestoreCursors;
5636 for (
auto view : std::as_const(m_views)) {
5637 auto v =
static_cast<ViewPrivate *
>(view);
5638 if (v->cursorPosition() == oldEndOfDocumentCursor) {
5639 viewsToRestoreCursors.push_back(v);
5644 editWrapLine(lines - 1, length);
5647 for (
auto v : viewsToRestoreCursors) {
5648 v->setCursorPosition(oldEndOfDocumentCursor);
5656 if (wordWrapEnabled) {
5664 const int lines = this->lines();
5667 const int p = textline.
lastChar() + 1;
5668 const int l = textline.
length() - p;
5678 if (user || !m_fileTypeSetByUser) {
5684 if (fileType.name.isEmpty()) {
5689 m_fileTypeSetByUser = user;
5691 m_fileType = newType;
5693 m_config->configStart();
5698 if ((user || !m_hlSetByUser) && !fileType.hl.isEmpty()) {
5699 int hl(KateHlManager::self()->nameFind(fileType.hl));
5702 m_buffer->setHighlight(hl);
5709 if (!m_indenterSetByUser && !fileType.indenter.isEmpty()) {
5710 config()->setIndentationMode(fileType.indenter);
5714 for (
auto view : std::as_const(m_views)) {
5715 auto v =
static_cast<ViewPrivate *
>(view);
5720 bool bom_settings =
false;
5721 if (m_bomSetByUser) {
5722 bom_settings = m_config->bom();
5724 readVariableLine(fileType.varLine);
5725 if (m_bomSetByUser) {
5726 m_config->setBom(bom_settings);
5728 m_config->configEnd();
5729 for (
auto view : std::as_const(m_views)) {
5730 auto v =
static_cast<ViewPrivate *
>(view);
5741void KTextEditor::DocumentPrivate::slotQueryClose_save(
bool *handled,
bool *abortClosing)
5744 *abortClosing =
true;
5745 if (url().isEmpty()) {
5746 const QUrl res = getSaveFileUrl(
i18n(
"Save File"));
5748 *abortClosing =
true;
5752 *abortClosing =
false;
5755 *abortClosing =
false;
5765 return m_config->configKeys();
5771 return m_config->
value(key);
5777 m_config->setValue(key, value);
5791 bool changed = removeText(range, block);
5792 changed |= insertText(range.
start(), s, block);
5797KateHighlighting *KTextEditor::DocumentPrivate::highlight()
const
5799 return m_buffer->highlight();
5804 m_buffer->ensureHighlighted(i);
5805 return m_buffer->plainLine(i);
5810 return m_buffer->plainLine(i);
5813bool KTextEditor::DocumentPrivate::isEditRunning()
const
5815 return editIsRunning;
5818void KTextEditor::DocumentPrivate::setUndoMergeAllEdits(
bool merge)
5820 if (merge && m_undoMergeAllEdits) {
5825 m_undoManager->undoSafePoint();
5826 m_undoManager->setAllowComplexMerge(merge);
5827 m_undoMergeAllEdits =
merge;
5840 return new Kate::TextRange(m_buffer, range, insertBehaviors, emptyBehavior);
5845 return m_buffer->history().revision();
5850 return m_buffer->history().lastSavedRevision();
5855 m_buffer->history().lockRevision(
revision);
5860 m_buffer->history().unlockRevision(
revision);
5866 qint64 fromRevision,
5869 m_buffer->history().transformCursor(
line, column, insertBehavior, fromRevision, toRevision);
5874 qint64 fromRevision,
5878 int column = cursor.
column();
5879 m_buffer->history().transformCursor(
line, column, insertBehavior, fromRevision, toRevision);
5886 qint64 fromRevision,
5889 m_buffer->history().transformRange(range, insertBehaviors, emptyBehavior, fromRevision, toRevision);
5898 m_annotationModel = model;
5899 Q_EMIT annotationModelChanged(oldmodel, m_annotationModel);
5904 return m_annotationModel;
5909bool KTextEditor::DocumentPrivate::queryClose()
5911 if (!isModified() || (isEmpty() && url().isEmpty())) {
5915 QString docName = documentName();
5918 i18n(
"The document \"%1\" has been modified.\n"
5919 "Do you want to save your changes or discard them?",
5921 i18n(
"Close Document"),
5925 bool abortClose =
false;
5926 bool handled =
false;
5930 sigQueryClose(&handled, &abortClose);
5932 if (url().isEmpty()) {
5933 const QUrl url = getSaveFileUrl(
i18n(
"Save File"));
5942 }
else if (abortClose) {
5945 return waitSaveComplete();
5953void KTextEditor::DocumentPrivate::slotStarted(KIO::Job *job)
5956 if (m_documentState == DocumentIdle) {
5957 m_documentState = DocumentLoading;
5965 if (m_documentState == DocumentLoading) {
5967 m_readWriteStateBeforeLoading = isReadWrite();
5972 setReadWrite(
false);
5982void KTextEditor::DocumentPrivate::slotCompleted()
5986 if (m_documentState == DocumentLoading) {
5987 setReadWrite(m_readWriteStateBeforeLoading);
5988 delete m_loadingMessage;
5989 m_reloading =
false;
5993 if (m_documentState == DocumentSaving || m_documentState == DocumentSavingAs) {
5994 Q_EMIT documentSavedOrUploaded(
this, m_documentState == DocumentSavingAs);
5998 m_documentState = DocumentIdle;
6001void KTextEditor::DocumentPrivate::slotCanceled()
6005 if (m_documentState == DocumentLoading) {
6006 setReadWrite(m_readWriteStateBeforeLoading);
6007 delete m_loadingMessage;
6008 m_reloading =
false;
6010 if (!m_openingError) {
6011 showAndSetOpeningErrorAccess();
6018 m_documentState = DocumentIdle;
6021void KTextEditor::DocumentPrivate::slotTriggerLoadingMessage()
6025 if (m_documentState != DocumentLoading) {
6030 delete m_loadingMessage;
6032 new KTextEditor::Message(
i18n(
"The file <a href=\"%1\">%2</a> is still loading.", url().toDisplayString(
QUrl::PreferLocalFile), url().fileName()));
6037 QAction *
cancel =
new QAction(
i18n(
"&Abort Loading"),
nullptr);
6039 m_loadingMessage->addAction(cancel);
6043 postMessage(m_loadingMessage);
6046void KTextEditor::DocumentPrivate::slotAbortLoading()
6049 if (!m_loadingJob) {
6055 m_loadingJob->kill(KJob::EmitResult);
6056 m_loadingJob =
nullptr;
6059void KTextEditor::DocumentPrivate::slotUrlChanged(
const QUrl &url)
6063 Q_EMIT documentUrlChanged(
this);
6066bool KTextEditor::DocumentPrivate::save()
6070 if ((m_documentState != DocumentIdle) && (m_documentState != DocumentPreSavingAs)) {
6075 if (m_documentState == DocumentIdle) {
6076 m_documentState = DocumentSaving;
6078 m_documentState = DocumentSavingAs;
6082 Q_EMIT aboutToSave(
this);
6088bool KTextEditor::DocumentPrivate::saveAs(
const QUrl &url)
6099 if (m_documentState != DocumentIdle) {
6104 m_documentState = DocumentPreSavingAs;
6110QUrl KTextEditor::DocumentPrivate::startUrlForFileDialog()
6112 QUrl startUrl = url();
6122 const auto views = mainWindow->views();
6123 for (
auto view : views) {
6135QString KTextEditor::DocumentPrivate::defaultDictionary()
const
6137 return m_defaultDictionary;
6140QList<QPair<KTextEditor::MovingRange *, QString>> KTextEditor::DocumentPrivate::dictionaryRanges()
const
6142 return m_dictionaryRanges;
6145void KTextEditor::DocumentPrivate::clearDictionaryRanges()
6147 for (
auto i = m_dictionaryRanges.cbegin(); i != m_dictionaryRanges.cend(); ++i) {
6150 m_dictionaryRanges.clear();
6151 if (m_onTheFlyChecker) {
6152 m_onTheFlyChecker->refreshSpellCheck();
6154 Q_EMIT dictionaryRangesPresent(
false);
6157void KTextEditor::DocumentPrivate::setDictionary(
const QString &newDictionary, KTextEditor::Range range,
bool blockmode)
6161 setDictionary(newDictionary, rangeOnLine(range, i));
6164 setDictionary(newDictionary, range);
6167 Q_EMIT dictionaryRangesPresent(!m_dictionaryRanges.isEmpty());
6170void KTextEditor::DocumentPrivate::setDictionary(
const QString &newDictionary, KTextEditor::Range range)
6172 KTextEditor::Range newDictionaryRange = range;
6173 if (!newDictionaryRange.
isValid() || newDictionaryRange.
isEmpty()) {
6176 QList<QPair<KTextEditor::MovingRange *, QString>> newRanges;
6178 for (
auto i = m_dictionaryRanges.begin(); i != m_dictionaryRanges.end();) {
6179 qCDebug(LOG_KTE) <<
"new iteration" << newDictionaryRange;
6180 if (newDictionaryRange.
isEmpty()) {
6183 QPair<KTextEditor::MovingRange *, QString> pair = *i;
6184 QString dictionarySet = pair.second;
6185 KTextEditor::MovingRange *dictionaryRange = pair.first;
6186 qCDebug(LOG_KTE) << *dictionaryRange << dictionarySet;
6187 if (dictionaryRange->
contains(newDictionaryRange) && newDictionary == dictionarySet) {
6188 qCDebug(LOG_KTE) <<
"dictionaryRange contains newDictionaryRange";
6191 if (newDictionaryRange.
contains(*dictionaryRange)) {
6192 delete dictionaryRange;
6193 i = m_dictionaryRanges.erase(i);
6194 qCDebug(LOG_KTE) <<
"newDictionaryRange contains dictionaryRange";
6198 KTextEditor::Range intersection = dictionaryRange->
toRange().
intersect(newDictionaryRange);
6200 if (dictionarySet == newDictionary) {
6202 QList<KTextEditor::Range> remainingRanges = KateSpellCheckManager::rangeDifference(newDictionaryRange, intersection);
6203 Q_ASSERT(remainingRanges.
size() == 1);
6204 newDictionaryRange = remainingRanges.
first();
6206 qCDebug(LOG_KTE) <<
"dictionarySet == newDictionary";
6209 QList<KTextEditor::Range> remainingRanges = KateSpellCheckManager::rangeDifference(*dictionaryRange, intersection);
6210 for (
auto j = remainingRanges.
begin(); j != remainingRanges.
end(); ++j) {
6213 newRanges.
push_back({remainingRange, dictionarySet});
6215 i = m_dictionaryRanges.erase(i);
6216 delete dictionaryRange;
6221 m_dictionaryRanges += newRanges;
6223 KTextEditor::MovingRange *newDictionaryMovingRange =
6226 m_dictionaryRanges.push_back({newDictionaryMovingRange, newDictionary});
6228 if (m_onTheFlyChecker && !newDictionaryRange.
isEmpty()) {
6229 m_onTheFlyChecker->refreshSpellCheck(newDictionaryRange);
6233void KTextEditor::DocumentPrivate::setDefaultDictionary(
const QString &dict)
6235 if (m_defaultDictionary == dict) {
6239 m_defaultDictionary = dict;
6241 if (m_onTheFlyChecker) {
6242 m_onTheFlyChecker->updateConfig();
6243 refreshOnTheFlyCheck();
6245 Q_EMIT defaultDictionaryChanged(
this);
6248void KTextEditor::DocumentPrivate::onTheFlySpellCheckingEnabled(
bool enable)
6250 if (isOnTheFlySpellCheckingEnabled() == enable) {
6255 Q_ASSERT(m_onTheFlyChecker ==
nullptr);
6256 m_onTheFlyChecker =
new KateOnTheFlyChecker(
this);
6258 delete m_onTheFlyChecker;
6259 m_onTheFlyChecker =
nullptr;
6262 for (
auto view : std::as_const(m_views)) {
6263 static_cast<ViewPrivate *
>(view)->reflectOnTheFlySpellCheckStatus(enable);
6267bool KTextEditor::DocumentPrivate::isOnTheFlySpellCheckingEnabled()
const
6269 return m_onTheFlyChecker !=
nullptr;
6272QString KTextEditor::DocumentPrivate::dictionaryForMisspelledRange(KTextEditor::Range range)
const
6274 if (!m_onTheFlyChecker) {
6277 return m_onTheFlyChecker->dictionaryForMisspelledRange(range);
6281void KTextEditor::DocumentPrivate::clearMisspellingForWord(
const QString &word)
6283 if (m_onTheFlyChecker) {
6284 m_onTheFlyChecker->clearMisspellingForWord(word);
6288void KTextEditor::DocumentPrivate::refreshOnTheFlyCheck(KTextEditor::Range range)
6290 if (m_onTheFlyChecker) {
6291 m_onTheFlyChecker->refreshSpellCheck(range);
6297 deleteDictionaryRange(movingRange);
6302 deleteDictionaryRange(movingRange);
6307 qCDebug(LOG_KTE) <<
"deleting" << movingRange;
6309 auto finder = [=](
const QPair<KTextEditor::MovingRange *, QString> &item) ->
bool {
6310 return item.first == movingRange;
6313 auto it = std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder);
6315 if (it != m_dictionaryRanges.end()) {
6316 m_dictionaryRanges.erase(it);
6320 Q_ASSERT(std::find_if(m_dictionaryRanges.begin(), m_dictionaryRanges.end(), finder) == m_dictionaryRanges.end());
6323bool KTextEditor::DocumentPrivate::containsCharacterEncoding(KTextEditor::Range range)
6325 KateHighlighting *highlighting = highlight();
6327 const int rangeStartLine = range.
start().
line();
6328 const int rangeStartColumn = range.
start().
column();
6329 const int rangeEndLine = range.
end().
line();
6330 const int rangeEndColumn = range.
end().
column();
6332 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6333 const Kate::TextLine textLine = kateTextLine(line);
6334 const int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6335 const int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6336 for (
int col = startColumn; col < endColumn; ++col) {
6338 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6348int KTextEditor::DocumentPrivate::computePositionWrtOffsets(
const OffsetList &offsetList,
int pos)
6350 int previousOffset = 0;
6351 for (
auto i = offsetList.cbegin(); i != offsetList.cend(); ++i) {
6352 if (i->first > pos) {
6355 previousOffset = i->second;
6357 return pos + previousOffset;
6361 KTextEditor::DocumentPrivate::OffsetList &decToEncOffsetList,
6362 KTextEditor::DocumentPrivate::OffsetList &encToDecOffsetList)
6366 int decToEncCurrentOffset = 0;
6367 int encToDecCurrentOffset = 0;
6371 KateHighlighting *highlighting = highlight();
6374 const int rangeStartLine = range.
start().
line();
6375 const int rangeStartColumn = range.
start().
column();
6376 const int rangeEndLine = range.
end().
line();
6377 const int rangeEndColumn = range.
end().
column();
6381 int startColumn = (
line == rangeStartLine) ? rangeStartColumn : 0;
6382 int endColumn = (
line == rangeEndLine) ? rangeEndColumn : textLine.
length();
6383 for (
int col = startColumn; col < endColumn;) {
6385 const KatePrefixStore &prefixStore = highlighting->getCharacterEncodingsPrefixStore(attr);
6388 if (!matchingPrefix.
isEmpty()) {
6390 const QChar &c = characterEncodingsHash.
value(matchingPrefix);
6391 const bool isNullChar = c.
isNull();
6395 i += matchingPrefix.
length();
6396 col += matchingPrefix.
length();
6398 decToEncCurrentOffset = decToEncCurrentOffset - (isNullChar ? 0 : 1) + matchingPrefix.
length();
6399 encToDecCurrentOffset = encToDecCurrentOffset - matchingPrefix.
length() + (isNullChar ? 0 : 1);
6400 newI += (isNullChar ? 0 : 1);
6401 decToEncOffsetList.
push_back(QPair<int, int>(newI, decToEncCurrentOffset));
6402 encToDecOffsetList.
push_back(QPair<int, int>(i, encToDecCurrentOffset));
6412 if (previous < range.
end()) {
6418void KTextEditor::DocumentPrivate::replaceCharactersByEncoding(
KTextEditor::Range range)
6420 KateHighlighting *highlighting = highlight();
6423 const int rangeStartLine = range.
start().
line();
6424 const int rangeStartColumn = range.
start().
column();
6425 const int rangeEndLine = range.
end().
line();
6426 const int rangeEndColumn = range.
end().
column();
6428 for (
int line = range.
start().
line(); line <= rangeEndLine; ++line) {
6429 textLine = kateTextLine(line);
6430 int startColumn = (line == rangeStartLine) ? rangeStartColumn : 0;
6431 int endColumn = (line == rangeEndLine) ? rangeEndColumn : textLine.length();
6432 for (
int col = startColumn; col < endColumn;) {
6434 const QHash<QChar, QString> &reverseCharacterEncodingsHash = highlighting->getReverseCharacterEncodings(attr);
6435 auto it = reverseCharacterEncodingsHash.
find(textLine.
at(col));
6436 if (it != reverseCharacterEncodingsHash.
end()) {
6438 col += (*it).length();
6452 return highlight()->getEmbeddedHighlightingModes();
6457 return highlight()->higlightingModeForLocation(
this, position);
6472 if (line < 0 || line >=
lines() || column < 0) {
6473 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6481 if (column < tl.
length()) {
6483 }
else if (column == tl.
length()) {
6487 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6490 return KSyntaxHighlighting::Theme::TextStyle::Normal;
6493 return highlight()->defaultStyleForAttribute(attribute);
6496bool KTextEditor::DocumentPrivate::isComment(
int line,
int column)
6498 return defStyleNum(line, column) == KSyntaxHighlighting::Theme::TextStyle::Comment;
6503 const int offset = down ? 1 : -1;
6504 const int lineCount =
lines();
6505 while (startLine >= 0 && startLine < lineCount) {
6507 if (tl.markedAsModified() || tl.markedAsSavedOnDisk()) {
6510 startLine += offset;
6519 delete m_activeTemplateHandler.data();
6520 m_activeTemplateHandler = handler;
6533 qCWarning(LOG_KTE) <<
"trying to post a message to a view of another document:" << message->
text();
6543 closeAction->
setToolTip(
i18nc(
"Close the message being displayed",
"Close message"));
6549 const auto messageActions = message->
actions();
6550 managedMessageActions.
reserve(messageActions.size());
6552 action->setParent(
nullptr);
6553 managedMessageActions.
append(std::shared_ptr<QAction>(
action));
6555 m_messageHash.insert(message, managedMessageActions);
6559 view->postMessage(message, managedMessageActions);
6561 for (
auto view : std::as_const(m_views)) {
6562 static_cast<ViewPrivate *
>(view)->
postMessage(message, managedMessageActions);
6567 connect(message, &
Message::closed,
this, &DocumentPrivate::messageDestroyed);
6575 Q_ASSERT(m_messageHash.contains(message));
6576 m_messageHash.remove(message);
6580#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)