File indexing completed on 2024-04-28 09:47:04

0001 /*
0002  *  SPDX-FileCopyrightText: 2002-2004 Jesper K. Pedersen <blackie@kde.org>
0003  *
0004  *  SPDX-License-Identifier: LGPL-2.0-only
0005  **/
0006 
0007 #include "qtregexpconverter.h"
0008 
0009 #include "altnregexp.h"
0010 #include "compoundregexp.h"
0011 #include "concregexp.h"
0012 #include "dotregexp.h"
0013 #include "lookaheadregexp.h"
0014 #include "positionregexp.h"
0015 #include "qtregexphighlighter.h"
0016 #include "regexp.h"
0017 #include "repeatregexp.h"
0018 #include "textrangeregexp.h"
0019 #include "textregexp.h"
0020 
0021 extern RegExp *parseQtRegExp(const QString &qstr, bool *ok);
0022 
0023 bool QtRegExpConverter::canParse()
0024 {
0025     return true;
0026 }
0027 
0028 RegExp *QtRegExpConverter::parse(const QString &txt, bool *ok)
0029 {
0030     return parseQtRegExp(txt, ok);
0031 }
0032 
0033 QString QtRegExpConverter::toString(AltnRegExp *regexp, bool markSelection)
0034 {
0035     QString res;
0036 
0037     bool first = true;
0038     const RegExpList list = regexp->children();
0039     for (RegExp *r : list) {
0040         if (!first) {
0041             res += QLatin1String("|");
0042         }
0043 
0044         first = false;
0045         if (markSelection && !regexp->isSelected() && r->isSelected()) {
0046             res += QStringLiteral("(") + toStr(r, markSelection) + QStringLiteral(")");
0047         } else {
0048             res += toStr(r, markSelection);
0049         }
0050     }
0051     return res;
0052 }
0053 
0054 QString QtRegExpConverter::toString(ConcRegExp *regexp, bool markSelection)
0055 {
0056     QString res;
0057     bool childSelected = false;
0058 
0059     const auto children = regexp->children();
0060     for (const auto child : children) {
0061         QString startPar;
0062         QString endPar;
0063         if (child->precedence() < regexp->precedence()) {
0064             if (markSelection) {
0065                 startPar = QStringLiteral("(?:");
0066             } else {
0067                 startPar = QStringLiteral("(");
0068             }
0069             endPar = QStringLiteral(")");
0070         }
0071 
0072         // Note these two have different tests! They are activated in each their iteration of the loop.
0073         if (markSelection && !childSelected && !regexp->isSelected() && child->isSelected()) {
0074             res += QLatin1String("(");
0075             childSelected = true;
0076         }
0077 
0078         if (markSelection && childSelected && !regexp->isSelected() && !child->isSelected()) {
0079             res += QLatin1String(")");
0080             childSelected = false;
0081         }
0082 
0083         res += startPar + toStr(child, markSelection) + endPar;
0084     }
0085     if (markSelection && childSelected && !regexp->isSelected()) {
0086         res += QLatin1String(")");
0087     }
0088     return res;
0089 }
0090 
0091 QString QtRegExpConverter::toString(LookAheadRegExp *regexp, bool markSelection)
0092 {
0093     if (regexp->lookAheadType() == LookAheadRegExp::POSITIVE) {
0094         return QStringLiteral("(?=") + toStr(regexp->child(), markSelection) + QStringLiteral(")");
0095     } else {
0096         return QStringLiteral("(?!") + toStr(regexp->child(), markSelection) + QStringLiteral(")");
0097     }
0098 }
0099 
0100 QString QtRegExpConverter::toString(TextRangeRegExp *regexp, bool /*markSelection*/)
0101 {
0102     QString txt;
0103 
0104     bool foundCarrot = false;
0105     bool foundDash = false;
0106     bool foundParenthesis = false;
0107 
0108     // Now print the rest of the single characters, but keep "^" as the very
0109     // last element of the characters.
0110     QStringList chars = regexp->chars();
0111     for (int i = 0; i < chars.count(); i++) {
0112         if (chars.at(i).at(0) == QLatin1Char(']')) {
0113             foundParenthesis = true;
0114         } else if (chars.at(i).at(0) == QLatin1Char('-')) {
0115             foundDash = true;
0116         } else if (chars.at(i).at(0) == QLatin1Char('^')) {
0117             foundCarrot = true;
0118         } else {
0119             txt.append(chars.at(i).at(0));
0120         }
0121     }
0122 
0123     // Now insert the ranges.
0124     const auto range = regexp->range();
0125     for (const StringPair &elm : range) {
0126         txt.append(elm.first + QLatin1Char('-') + elm.second);
0127     }
0128 
0129     // Ok, its time to build each part of the regexp, here comes the rule:
0130     // if a ']' is one of the characters, then it must be the first one in the
0131     // list (after then opening '[' and eventually negation '^')
0132     // Next if a '-' is one of the characters, then it must come
0133     // finally if '^' is one of the characters, then it must not be the first
0134     // one!
0135 
0136     QString res = QStringLiteral("[");
0137 
0138     if (regexp->negate()) {
0139         res.append(QLatin1String("^"));
0140     }
0141 
0142     // a ']' must be the first character in teh range.
0143     if (foundParenthesis) {
0144         res.append(QLatin1String("]"));
0145     }
0146 
0147     // a '-' must be the first character ( only coming after a ']')
0148     if (foundDash) {
0149         res.append(QLatin1String("-"));
0150     }
0151 
0152     res += txt;
0153 
0154     // Insert \s,\S,\d,\D,\w, and \W
0155     if (regexp->digit()) {
0156         res += QStringLiteral("\\d");
0157     }
0158 
0159     if (regexp->nonDigit()) {
0160         res += QStringLiteral("\\D");
0161     }
0162 
0163     if (regexp->space()) {
0164         res += QStringLiteral("\\s");
0165     }
0166 
0167     if (regexp->nonSpace()) {
0168         res += QStringLiteral("\\S");
0169     }
0170 
0171     if (regexp->wordChar()) {
0172         res += QStringLiteral("\\w");
0173     }
0174 
0175     if (regexp->nonWordChar()) {
0176         res += QStringLiteral("\\W");
0177     }
0178 
0179     if (foundCarrot) {
0180         res.append(QLatin1Char('^'));
0181     }
0182 
0183     res.append(QLatin1String("]"));
0184 
0185     return res;
0186 }
0187 
0188 QString QtRegExpConverter::toString(CompoundRegExp *regexp, bool markSelection)
0189 {
0190     if (markSelection && !regexp->isSelected() && regexp->child()->isSelected()) {
0191         return QStringLiteral("(") + toStr(regexp->child(), markSelection) + QStringLiteral(")");
0192     } else {
0193         return toStr(regexp->child(), markSelection);
0194     }
0195 }
0196 
0197 QString QtRegExpConverter::toString(DotRegExp * /*regexp*/, bool /*markSelection*/)
0198 {
0199     return QStringLiteral(".");
0200 }
0201 
0202 QString QtRegExpConverter::toString(PositionRegExp *regexp, bool /*markSelection*/)
0203 {
0204     switch (regexp->position()) {
0205     case PositionRegExp::BEGLINE:
0206         return QStringLiteral("^");
0207     case PositionRegExp::ENDLINE:
0208         return QStringLiteral("$");
0209     case PositionRegExp::WORDBOUNDARY:
0210         return QStringLiteral("\\b");
0211     case PositionRegExp::NONWORDBOUNDARY:
0212         return QStringLiteral("\\B");
0213     }
0214     Q_ASSERT(false);
0215     return QString();
0216 }
0217 
0218 QString QtRegExpConverter::toString(RepeatRegExp *regexp, bool markSelection)
0219 {
0220     RegExp *child = regexp->child();
0221     QString cText = toStr(child, markSelection);
0222     QString startPar;
0223     QString endPar;
0224     QString quantity;
0225 
0226     if (markSelection) {
0227         if (!regexp->isSelected() && child->isSelected()) {
0228             startPar = QStringLiteral("(");
0229             endPar = QStringLiteral(")");
0230         } else if (child->precedence() < regexp->precedence()) {
0231             startPar = QStringLiteral("(?:");
0232             endPar = QStringLiteral(")");
0233         }
0234     } else if (child->precedence() < regexp->precedence()) {
0235         startPar = QStringLiteral("(");
0236         endPar = QStringLiteral(")");
0237     }
0238 
0239     if (regexp->min() == 0 && regexp->max() == -1) {
0240         quantity = QStringLiteral("*");
0241     } else if (regexp->min() == 0 && regexp->max() == 1) {
0242         quantity = QStringLiteral("?");
0243     } else if (regexp->min() == 1 && regexp->max() == -1) {
0244         quantity = QStringLiteral("+");
0245     } else if (regexp->max() == -1) {
0246         quantity = QStringLiteral("{") + QString::number(regexp->min()) + QStringLiteral(",") + QStringLiteral("}");
0247     } else {
0248         quantity = QStringLiteral("{") + QString::number(regexp->min()) + QStringLiteral(",") + QString::number(regexp->max()) + QStringLiteral("}");
0249     }
0250 
0251     return startPar + cText + endPar + quantity;
0252 }
0253 
0254 QString QtRegExpConverter::toString(TextRegExp *regexp, bool /*markSelection*/)
0255 {
0256     QList<QChar> list;
0257     list << QLatin1Char('$') << QLatin1Char('^') << QLatin1Char('.') << QLatin1Char('*') << QLatin1Char('+') << QLatin1Char('?') << QLatin1Char('[')
0258          << QLatin1Char(']') << QLatin1Char('\\') << QLatin1Char('{') << QLatin1Char('}') << QLatin1Char('(') << QLatin1Char(')') << QLatin1Char('|');
0259 
0260     QString res = escape(regexp->text(), list, QLatin1Char('\\'));
0261     return res;
0262 }
0263 
0264 QString QtRegExpConverter::name()
0265 {
0266     return QStringLiteral("Qt");
0267 }
0268 
0269 int QtRegExpConverter::features()
0270 {
0271     return WordBoundary | NonWordBoundary | PosLookAhead | NegLookAhead | CharacterRangeNonItems | ExtRange;
0272 }
0273 
0274 RegexpHighlighter *QtRegExpConverter::highlighter(QTextEdit *edit) // krazy:exclude=qclasses
0275 {
0276     return new QtRegexpHighlighter(edit);
0277 }