| 36 | } |
| 37 | |
| 38 | void HTMLAutoCompleteDecorator::notify(const Scintilla::NotificationData *pscn) |
| 39 | { |
| 40 | if (pscn->nmhdr.code == Scintilla::Notification::CharAdded) { |
| 41 | if (pscn->ch == '>') { |
| 42 | const int currentPos = editor->currentPos(); |
| 43 | |
| 44 | // Skip if it is inside any scripting language |
| 45 | if (editor->styleAt(currentPos) >= SCE_HJ_START) return; |
| 46 | |
| 47 | int tagEndPos = editor->positionBefore(currentPos); |
| 48 | int tagStartPos = editor->positionBefore(tagEndPos); |
| 49 | |
| 50 | // Check the char right before the > |
| 51 | const int prevChar = editor->charAt(tagStartPos); |
| 52 | if (prevChar == '-') return; // Assume --> |
| 53 | if (prevChar == '/') return; // <tag/> |
| 54 | |
| 55 | // Go backwards searching for the beginning of the tag |
| 56 | while ((currentPos - tagStartPos) <= MAX_TAG_LENGTH) { |
| 57 | const int c = editor->charAt(tagStartPos); |
| 58 | |
| 59 | // While backing up, save the position of the last whitespace character we encounter |
| 60 | if (std::isspace(c) != 0) { |
| 61 | tagEndPos = tagStartPos; |
| 62 | } |
| 63 | |
| 64 | // Found the start (yes this can be fooled but this is by far the easiest for now) |
| 65 | if (c == '<') break; |
| 66 | |
| 67 | // Reached the beginning of the document |
| 68 | if (tagStartPos == 0) return; |
| 69 | |
| 70 | tagStartPos = editor->positionBefore(tagStartPos); |
| 71 | } |
| 72 | |
| 73 | // For sanity, check the length of the tag name |
| 74 | if (tagEndPos - tagStartPos >= MAX_TAG_NAME_LENGTH) return; |
| 75 | |
| 76 | QByteArray tag = editor->get_text_range(editor->positionAfter(tagStartPos), tagEndPos); |
| 77 | |
| 78 | if (tag.isEmpty()) return; // <> |
| 79 | if (tag[0] == '/') return; // </div> |
| 80 | if (tag[0] == '?') return; // <?php> |
| 81 | if (tag[0] == '!') return; // <!-- and <!doctype |
| 82 | if (voidTags.contains(tag)) return; // Some tags are not expected to have closing tags |
| 83 | |
| 84 | // All good to go now, wrap it and insert it |
| 85 | tag.prepend("</"); |
| 86 | tag.append('>'); |
| 87 | |
| 88 | const UndoAction ua(editor); |
| 89 | editor->insertText(currentPos, tag.constData()); |
| 90 | } |
| 91 | } |
| 92 | } |