* Insert a string into the text buffer. If maxwidth of the Textbuf is zero, * we don't care about the visual-length but only about the physical * length of the string. * @param str String to insert. * @param marked Replace the currently marked text with the new text. * @param caret Move the caret to this point in the insertion string. * @param insert_location Position at which to insert the
| 155 | * @return True on successful change of Textbuf, or false otherwise. |
| 156 | */ |
| 157 | bool Textbuf::InsertString(std::string_view str, bool marked, std::optional<size_t> caret, std::optional<size_t> insert_location, std::optional<size_t> replacement_end) |
| 158 | { |
| 159 | uint16_t insertpos = (marked && this->marklength != 0) ? this->markpos : this->caretpos; |
| 160 | if (insert_location.has_value()) { |
| 161 | insertpos = static_cast<uint16_t>(*insert_location); |
| 162 | if (insertpos >= this->buf.size()) return false; |
| 163 | |
| 164 | if (replacement_end.has_value()) { |
| 165 | this->DeleteText(insertpos, static_cast<uint16_t>(*replacement_end), str.empty()); |
| 166 | } |
| 167 | } else { |
| 168 | if (marked) this->DiscardMarkedText(str.empty()); |
| 169 | } |
| 170 | |
| 171 | if (str.empty()) return false; |
| 172 | |
| 173 | uint16_t chars = 0; |
| 174 | uint16_t bytes; |
| 175 | { |
| 176 | Utf8View view(str); |
| 177 | auto cur = view.begin(); |
| 178 | const auto end = view.end(); |
| 179 | while (cur != end) { |
| 180 | if (!IsValidChar(*cur, this->afilter)) break; |
| 181 | |
| 182 | auto next = cur; |
| 183 | ++next; |
| 184 | if (this->buf.size() + next.GetByteOffset() >= this->max_bytes) break; |
| 185 | if (this->chars + chars + 1 > this->max_chars) break; |
| 186 | |
| 187 | cur = next; |
| 188 | chars++; |
| 189 | } |
| 190 | bytes = static_cast<uint16_t>(cur.GetByteOffset()); |
| 191 | } |
| 192 | if (bytes == 0) return false; |
| 193 | |
| 194 | /* Move caret if needed. */ |
| 195 | if (caret.has_value()) this->caretpos = insertpos + static_cast<uint16_t>(*caret); |
| 196 | |
| 197 | if (marked) { |
| 198 | this->markpos = insertpos; |
| 199 | this->markend = insertpos + bytes; |
| 200 | } |
| 201 | |
| 202 | this->buf.insert(insertpos, str.substr(0, bytes)); |
| 203 | |
| 204 | this->chars += chars; |
| 205 | if (!marked && !caret.has_value()) this->caretpos += bytes; |
| 206 | assert(this->buf.size() < this->max_bytes); |
| 207 | assert(this->chars <= this->max_chars); |
| 208 | |
| 209 | this->UpdateStringIter(); |
| 210 | this->UpdateWidth(); |
| 211 | this->UpdateCaretPosition(); |
| 212 | this->UpdateMarkedText(); |
| 213 | |
| 214 | return true; |
no test coverage detected