2
Copyright 2008 David Nolden <david.nolden.kdevelop@art-master.de>
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Library General Public
6
License version 2 as published by the Free Software Foundation.
8
This library is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
Library General Public License for more details.
13
You should have received a copy of the GNU Library General Public License
14
along with this library; see the file COPYING.LIB. If not, write to
15
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16
Boston, MA 02110-1301, USA.
19
#include "coderepresentation.h"
22
#include <KTextEditor/Document>
24
#include <serialization/indexedstring.h>
25
#include <interfaces/idocumentcontroller.h>
26
#include <interfaces/icore.h>
27
#include <editor/modificationrevision.h>
28
#include <ktexteditor/movinginterface.h>
29
#include <ktexteditor/configinterface.h>
33
static bool onDiskChangesForbidden = false;
35
QString CodeRepresentation::rangeText(const KTextEditor::Range& range) const
37
Q_ASSERT(range.end().line() < lines());
39
//Easier for single line ranges which should happen most of the time
40
if(range.onSingleLine())
41
return QString( line( range.start().line() ).mid( range.start().column(), range.columnWidth() ) );
43
//Add up al the requested lines
44
QString rangedText = line(range.start().line()).mid(range.start().column());
46
for(int i = range.start().line() + 1; i <= range.end().line(); ++i)
47
rangedText += '\n' + ((i == range.end().line()) ? line(i).left(range.end().column()) : line(i));
52
static void grepLine(const QString& identifier, const QString& lineText, int lineNumber, QVector<KTextEditor::Range>& ret, bool surroundedByBoundary)
54
if (identifier.isEmpty())
60
pos = lineText.indexOf(identifier, pos);
64
pos += identifier.length();
67
if(!surroundedByBoundary || ( (end == lineText.length() || !lineText[end].isLetterOrNumber() || lineText[end] != '_')
68
&& (start-1 < 0 || !lineText[start-1].isLetterOrNumber() || lineText[start-1] != '_')) )
70
ret << KTextEditor::Range(lineNumber, start, lineNumber, end);
75
class EditorCodeRepresentation : public DynamicCodeRepresentation {
77
explicit EditorCodeRepresentation(KTextEditor::Document* document) : m_document(document) {
78
m_url = IndexedString(m_document->url());
81
QVector< KTextEditor::Range > grep ( const QString& identifier, bool surroundedByBoundary ) const override {
82
QVector< KTextEditor::Range > ret;
84
if (identifier.isEmpty())
87
for(int line = 0; line < m_document->lines(); ++line)
88
grepLine(identifier, m_document->line(line), line, ret, surroundedByBoundary);
93
KDevEditingTransaction::Ptr makeEditTransaction() override {
94
return KDevEditingTransaction::Ptr(new KDevEditingTransaction(m_document));
97
QString line(int line) const override {
98
if(line < 0 || line >= m_document->lines())
100
return m_document->line(line);
103
int lines() const override {
104
return m_document->lines();
107
QString text() const override {
108
return m_document->text();
111
bool setText(const QString& text) override {
114
KDevEditingTransaction t(m_document);
115
ret = m_document->setText(text);
117
ModificationRevision::clearModificationCache(m_url);
121
bool fileExists() const override
123
return QFile(m_document->url().path()).exists();
126
bool replace(const KTextEditor::Range& range, const QString& oldText,
127
const QString& newText, bool ignoreOldText) override {
128
QString old = m_document->text(range);
129
if(oldText != old && !ignoreOldText) {
135
KDevEditingTransaction t(m_document);
136
ret = m_document->replaceText(range, newText);
139
ModificationRevision::clearModificationCache(m_url);
144
QString rangeText(const KTextEditor::Range& range) const override {
145
return m_document->text(range);
149
KTextEditor::Document* m_document;
153
class FileCodeRepresentation : public CodeRepresentation {
155
explicit FileCodeRepresentation(const IndexedString& document) : m_document(document) {
156
QString localFile(document.toUrl().toLocalFile());
158
QFile file( localFile );
159
if ( file.open(QIODevice::ReadOnly) ) {
160
data = QString::fromLocal8Bit(file.readAll());
161
lineData = data.split('\n');
163
m_exists = file.exists();
166
QString line(int line) const override {
167
if(line < 0 || line >= lineData.size())
170
return lineData.at(line);
173
QVector< KTextEditor::Range > grep ( const QString& identifier, bool surroundedByBoundary ) const override {
174
QVector< KTextEditor::Range > ret;
176
if (identifier.isEmpty())
179
for(int line = 0; line < lineData.count(); ++line)
180
grepLine(identifier, lineData.at(line), line, ret, surroundedByBoundary);
185
int lines() const override {
186
return lineData.count();
189
QString text() const override {
193
bool setText(const QString& text) override {
194
Q_ASSERT(!onDiskChangesForbidden);
195
QString localFile(m_document.toUrl().toLocalFile());
197
QFile file( localFile );
198
if ( file.open(QIODevice::WriteOnly) )
200
QByteArray data = text.toLocal8Bit();
202
if(file.write(data) == data.size())
204
ModificationRevision::clearModificationCache(m_document);
211
bool fileExists() const override
217
//We use QByteArray, because the column-numbers are measured in utf-8
218
IndexedString m_document;
220
QStringList lineData;
224
class ArtificialStringData : public QSharedData {
226
explicit ArtificialStringData(const QString& data) {
229
void setData(const QString& data) {
231
m_lineData = m_data.split('\n');
233
QString data() const {
236
const QStringList& lines() const {
242
QStringList m_lineData;
245
class StringCodeRepresentation : public CodeRepresentation {
247
explicit StringCodeRepresentation(QExplicitlySharedDataPointer<ArtificialStringData> _data) : data(_data) {
251
QString line(int line) const override {
252
if(line < 0 || line >= data->lines().size())
255
return data->lines().at(line);
258
int lines() const override {
259
return data->lines().count();
262
QString text() const override {
266
bool setText(const QString& text) override {
271
bool fileExists() const override
276
QVector< KTextEditor::Range > grep ( const QString& identifier, bool surroundedByBoundary ) const override {
277
QVector< KTextEditor::Range > ret;
279
if (identifier.isEmpty())
282
for(int line = 0; line < data->lines().count(); ++line)
283
grepLine(identifier, data->lines().at(line), line, ret, surroundedByBoundary);
289
QExplicitlySharedDataPointer<ArtificialStringData> data;
292
static QHash<IndexedString, QExplicitlySharedDataPointer<ArtificialStringData> > artificialStrings;
294
//Return the representation for the given URL if it exists, or an empty pointer otherwise
295
static QExplicitlySharedDataPointer<ArtificialStringData> representationForPath(const IndexedString& path)
297
if(artificialStrings.contains(path))
298
return artificialStrings[path];
301
IndexedString constructedPath(CodeRepresentation::artificialPath(path.str()));
302
if(artificialStrings.contains(constructedPath))
303
return artificialStrings[constructedPath];
305
return QExplicitlySharedDataPointer<ArtificialStringData>();
309
bool artificialCodeRepresentationExists(const IndexedString& path)
311
return representationForPath(path);
314
CodeRepresentation::Ptr createCodeRepresentation(const IndexedString& path) {
315
if(artificialCodeRepresentationExists(path))
316
return CodeRepresentation::Ptr(new StringCodeRepresentation(representationForPath(path)));
318
IDocument* document = ICore::self()->documentController()->documentForUrl(path.toUrl());
319
if(document && document->textDocument())
320
return CodeRepresentation::Ptr(new EditorCodeRepresentation(document->textDocument()));
322
return CodeRepresentation::Ptr(new FileCodeRepresentation(path));
325
void CodeRepresentation::setDiskChangesForbidden(bool changesForbidden)
327
onDiskChangesForbidden = changesForbidden;
330
QString CodeRepresentation::artificialPath(const QString& name)
332
QUrl url = QUrl::fromLocalFile(name);
333
return QLatin1String("/kdev-artificial/") + url.adjusted(QUrl::NormalizePathSegments).path();
336
InsertArtificialCodeRepresentation::InsertArtificialCodeRepresentation(const IndexedString& file,
340
// make it simpler to use this by converting relative strings into artificial paths
341
if(QUrl(m_file.str()).isRelative())
343
m_file = IndexedString(CodeRepresentation::artificialPath(file.str()));
346
while(artificialStrings.contains(m_file))
349
m_file = IndexedString(CodeRepresentation::artificialPath(QStringLiteral("%1_%2").arg(idx).arg(file.str())));
353
Q_ASSERT(!artificialStrings.contains(m_file));
355
artificialStrings.insert(m_file, QExplicitlySharedDataPointer<ArtificialStringData>(new ArtificialStringData(text)));
358
IndexedString InsertArtificialCodeRepresentation::file()
363
InsertArtificialCodeRepresentation::~InsertArtificialCodeRepresentation() {
364
Q_ASSERT(artificialStrings.contains(m_file));
365
artificialStrings.remove(m_file);
368
void InsertArtificialCodeRepresentation::setText(const QString& text) {
369
Q_ASSERT(artificialStrings.contains(m_file));
370
artificialStrings[m_file]->setData(text);
373
QString InsertArtificialCodeRepresentation::text() const
375
Q_ASSERT(artificialStrings.contains(m_file));
376
return artificialStrings[m_file]->data();
381
// kate: indent-width 4;