SearchDiskFiles.cpp 5.53 KB
Newer Older
1
/*   Kate search plugin
2 3
 * 
 * Copyright (C) 2011-2013 by Kåre Särs <kare.sars@iki.fi>
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program in a file called COPYING; if not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */

21
#include "SearchDiskFiles.h"
22 23

#include <QDir>
24
#include <QUrl>
25 26
#include <QTextStream>

27

28 29
SearchDiskFiles::SearchDiskFiles(QObject *parent) : QThread(parent)
{}
30

31
SearchDiskFiles::~SearchDiskFiles()
32
{
33 34
    m_cancelSearch = true;
    wait();
35 36
}

37
void SearchDiskFiles::startSearch(const QStringList &files,
38
                                  const QRegularExpression &regexp)
39
{
40 41 42 43
    if (files.size() == 0) {
        emit searchDone();
        return;
    }
44 45 46
    m_cancelSearch = false;
    m_files = files;
    m_regExp = regexp;
47
    m_matchCount = 0;
48
    m_statusTime.restart();
49 50 51
    start();
}

52
void SearchDiskFiles::run()
53 54
{
    foreach (QString fileName, m_files) {
55
        if (m_cancelSearch) {
56
            break;
57
        }
58

59 60 61 62 63
        if (m_statusTime.elapsed() > 100) {
            m_statusTime.restart();
            emit searching(fileName);
        }

Joseph Wenninger's avatar
Joseph Wenninger committed
64
        if (m_regExp.pattern().contains(QStringLiteral("\\n"))) {
65 66 67 68
            searchMultiLineRegExp(fileName);
        }
        else {
            searchSingleLineRegExp(fileName);
69 70 71
        }
    }
    emit searchDone();
72
    m_cancelSearch = true;
73 74
}

75
void SearchDiskFiles::cancelSearch()
76 77 78
{
    m_cancelSearch = true;
}
79 80 81 82 83

bool SearchDiskFiles::searching()
{
    return !m_cancelSearch;
}
84 85 86 87 88 89 90 91 92

void SearchDiskFiles::searchSingleLineRegExp(const QString &fileName)
{
    QFile file (fileName);

    if (!file.open(QFile::ReadOnly)) {
        return;
    }

93
    QTextStream stream(&file);
94 95 96
    QString line;
    int i = 0;
    int column;
97
    QRegularExpressionMatch match;
98 99
    while (!(line=stream.readLine()).isNull()) {
        if (m_cancelSearch) break;
100 101
        match = m_regExp.match(line);
        column = match.capturedStart();
102
        while (column != -1 && !match.captured().isEmpty()) {
103
            // limit line length
104
            if (line.length() > 1024) line = line.left(1024);
105
            QUrl fileUrl =  QUrl::fromUserInput(fileName);
106 107 108 109
            emit matchFound(fileUrl.toString(), fileUrl.fileName(),
                            line, match.capturedLength(),
                            i, column, i, column+match.capturedLength());

110 111
            match = m_regExp.match(line, column + match.capturedLength());
            column = match.capturedStart();
112 113 114
            m_matchCount++;
            // NOTE: This sleep is here so that the main thread will get a chance to
            // handle any stop button clicks if there are a lot of matches
115
            if (m_matchCount%50) msleep(1);
116 117 118 119 120 121 122
        }
        i++;
    }
}

void SearchDiskFiles::searchMultiLineRegExp(const QString &fileName)
{
123
    QFile file(fileName);
124 125 126 127
    int column = 0;
    int line = 0;
    static QString fullDoc;
    static QVector<int> lineStart;
128
    QRegularExpression tmpRegExp = m_regExp;
129 130 131 132 133

    if (!file.open(QFile::ReadOnly)) {
        return;
    }

134
    QTextStream stream(&file);
135
    fullDoc = stream.readAll();
136
    fullDoc.remove(QLatin1Char('\r'));
137 138 139 140

    lineStart.clear();
    lineStart << 0;
    for (int i=0; i<fullDoc.size()-1; i++) {
141
        if (fullDoc[i] == QLatin1Char('\n')) {
142 143 144
            lineStart << i+1;
        }
    }
Joseph Wenninger's avatar
Joseph Wenninger committed
145
    if (tmpRegExp.pattern().endsWith(QStringLiteral("$"))) {
146
        fullDoc += QLatin1Char('\n');
147
        QString newPatern = tmpRegExp.pattern();
Joseph Wenninger's avatar
Joseph Wenninger committed
148
        newPatern.replace(QStringLiteral("$"), QStringLiteral("(?=\\n)"));
149 150
        tmpRegExp.setPattern(newPatern);
    }
151

152 153 154
    QRegularExpressionMatch match;
    match = tmpRegExp.match(fullDoc);
    column = match.capturedStart();
155
    while (column != -1 && !match.captured().isEmpty()) {
156 157 158 159 160 161 162 163 164 165 166 167 168
        if (m_cancelSearch) break;
        // search for the line number of the match
        int i;
        line = -1;
        for (i=1; i<lineStart.size(); i++) {
            if (lineStart[i] > column) {
                line = i-1;
                break;
            }
        }
        if (line == -1) {
            break;
        }
169
        QUrl fileUrl =  QUrl::fromUserInput(fileName);
170 171 172 173
        int startColumn = (column - lineStart[line]);
        int endLine = line + match.captured().count(QLatin1Char('\n'));
        int lastNL = match.captured().lastIndexOf(QLatin1Char('\n'));
        int endColumn = lastNL == -1 ? startColumn + match.captured().length() : match.captured().length() - lastNL-1;
174
        emit matchFound(fileUrl.toString(),fileUrl.fileName(),
175
                        fullDoc.mid(lineStart[line], column - lineStart[line])+match.captured(),
176 177
                        match.capturedLength(),
                        line, startColumn, endLine, endColumn);
178 179
        match = tmpRegExp.match(fullDoc, column + match.capturedLength());
        column = match.capturedStart();
180 181 182
        m_matchCount++;
        // NOTE: This sleep is here so that the main thread will get a chance to
        // handle any stop button clicks if there are a lot of matches
183
        if (m_matchCount%50) msleep(1);
184 185 186
    }
}