| 211 | } |
| 212 | |
| 213 | QString KDevelop::stripAnsiSequences(const QString& str) |
| 214 | { |
| 215 | if (str.isEmpty()) { |
| 216 | return QString(); // fast path |
| 217 | } |
| 218 | |
| 219 | enum { |
| 220 | PLAIN, |
| 221 | ANSI_START, |
| 222 | ANSI_CSI, |
| 223 | ANSI_SEQUENCE, |
| 224 | ANSI_WAITING_FOR_ST, |
| 225 | ANSI_ST_STARTED |
| 226 | } state = PLAIN; |
| 227 | |
| 228 | QString result; |
| 229 | result.reserve(str.size()); |
| 230 | |
| 231 | for (const QChar c : str) { |
| 232 | const auto val = c.unicode(); |
| 233 | switch (state) { |
| 234 | case PLAIN: |
| 235 | if (val == 27) // 'ESC' |
| 236 | state = ANSI_START; |
| 237 | else if (val == 155) // equivalent to 'ESC'-'[' |
| 238 | state = ANSI_CSI; |
| 239 | else |
| 240 | result.append(c); |
| 241 | break; |
| 242 | case ANSI_START: |
| 243 | if (val == 91) // [ |
| 244 | state = ANSI_CSI; |
| 245 | else if (val == 80 || val == 93 || val == 94 || val == 95) // 'P', ']', '^' and '_' |
| 246 | state = ANSI_WAITING_FOR_ST; |
| 247 | else if (val >= 64 && val <= 95) |
| 248 | state = PLAIN; |
| 249 | else |
| 250 | state = ANSI_SEQUENCE; |
| 251 | break; |
| 252 | case ANSI_CSI: |
| 253 | if (val >= 64 && val <= 126) // Anything between '@' and '~' |
| 254 | state = PLAIN; |
| 255 | break; |
| 256 | case ANSI_SEQUENCE: |
| 257 | if (val >= 64 && val <= 95) // Anything between '@' and '_' |
| 258 | state = PLAIN; |
| 259 | break; |
| 260 | case ANSI_WAITING_FOR_ST: |
| 261 | if (val == 7) // 'BEL' |
| 262 | state = PLAIN; |
| 263 | else if (val == 27) // 'ESC' |
| 264 | state = ANSI_ST_STARTED; |
| 265 | break; |
| 266 | case ANSI_ST_STARTED: |
| 267 | if (val == 92) // '\' |
| 268 | state = PLAIN; |
| 269 | else |
| 270 | state = ANSI_WAITING_FOR_ST; |