| 69 | } |
| 70 | |
| 71 | GrepOutputItem::List grepFile(const QString &filename, const QRegExp &re) |
| 72 | { |
| 73 | GrepOutputItem::List res; |
| 74 | QFile file(filename); |
| 75 | |
| 76 | if(!file.open(QIODevice::ReadOnly)) |
| 77 | return res; |
| 78 | int lineno = 0; |
| 79 | |
| 80 | // detect encoding (unicode files can be fed forever, so stop when confidence reaches 99%) |
| 81 | KEncodingProber prober; |
| 82 | while(!file.atEnd() && prober.state() == KEncodingProber::Probing && prober.confidence() < 0.99) { |
| 83 | prober.feed(file.read(0xFF)); |
| 84 | } |
| 85 | |
| 86 | // reads file with detected encoding |
| 87 | file.seek(0); |
| 88 | // TODO: consider using QIODevice::readLine() and QStringDecoder in place of QTextStream. |
| 89 | // The reason is the following paragraph in the documentation of QStringConverter::encodingForName(): |
| 90 | // If the name is not the name of a codec listed in the Encoding enumeration, std::nullopt |
| 91 | // is returned. Such a name may, none the less, be accepted by the QStringConverter |
| 92 | // constructor when Qt is built with ICU, if ICU provides a converter with the given name. |
| 93 | // The code inside the following `if` block replaced the line `stream.setCodec(prober.encoding().constData());` |
| 94 | // during porting from Qt 5 to Qt 6. The function QTextStream::setCodec(const char *codecName) |
| 95 | // removed in Qt 6 had probably supported ICU codec names. |
| 96 | QTextStream stream(&file); |
| 97 | if (prober.confidence() > 0.7) { |
| 98 | const auto encoding = QStringConverter::encodingForName(prober.encoding().constData()); |
| 99 | if (encoding) { |
| 100 | stream.setEncoding(*encoding); |
| 101 | } |
| 102 | } |
| 103 | while( !stream.atEnd() ) |
| 104 | { |
| 105 | QString data = stream.readLine(); |
| 106 | |
| 107 | // remove line terminators (in order to not match them) |
| 108 | for (int pos = data.length()-1; pos >= 0 && (data[pos] == QLatin1Char('\r') || data[pos] == QLatin1Char('\n')); pos--) { |
| 109 | data.chop(1); |
| 110 | } |
| 111 | |
| 112 | int offset = 0; |
| 113 | // allow empty string matching result in an infinite loop ! |
| 114 | while( re.indexIn(data, offset)!=-1 && re.cap(0).length() > 0 ) |
| 115 | { |
| 116 | int start = re.pos(0); |
| 117 | int end = start + re.cap(0).length(); |
| 118 | |
| 119 | DocumentChangePointer change = DocumentChangePointer(new DocumentChange( |
| 120 | IndexedString(filename), |
| 121 | KTextEditor::Range(lineno, start, lineno, end), |
| 122 | re.cap(0), QString())); |
| 123 | |
| 124 | res << GrepOutputItem(change, data, false); |
| 125 | offset = end; |
| 126 | } |
| 127 | lineno++; |
| 128 | } |