mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Merge branch 'master' into f7
This commit is contained in:
@@ -12,14 +12,14 @@ Zeros = "Zéros"
|
||||
Tangent = "Tangente"
|
||||
Intersection = "Intersection"
|
||||
Preimage = "Antécédent"
|
||||
SelectLowerBound = "Selectionner la borne inférieure"
|
||||
SelectUpperBound = "Selectionner la borne supérieure"
|
||||
SelectLowerBound = "Sélectionner la borne inférieure"
|
||||
SelectUpperBound = "Sélectionner la borne supérieure"
|
||||
NoMaximumFound = "Aucun maximum trouvé"
|
||||
NoMinimumFound = "Aucun minimum trouvé"
|
||||
NoZeroFound = "Aucun zéro trouvé"
|
||||
NoIntersectionFound = "Aucune intersection trouvée"
|
||||
NoPreimageFound = "Aucun antécédent trouvé"
|
||||
DerivativeFunctionColumn = "Colonne de la fonction derivée"
|
||||
HideDerivativeColumn = "Masquer la fonction derivée"
|
||||
DerivativeFunctionColumn = "Colonne de la fonction dérivée"
|
||||
HideDerivativeColumn = "Masquer la fonction dérivée"
|
||||
AllowedCharactersAZaz09 = "Caractères autorisés : A-Z, a-z, 0-9, _"
|
||||
ReservedName = "Nom réservé"
|
||||
|
||||
@@ -20,6 +20,6 @@ Cartesian = "Algébrique "
|
||||
Polar = "Exponentielle "
|
||||
Brightness = "Luminosité"
|
||||
SoftwareVersion = "Version du logiciel"
|
||||
SerialNumber = "Numéro serie"
|
||||
SerialNumber = "Numéro série"
|
||||
UpdatePopUp = "Rappel mise à jour"
|
||||
BetaPopUp = "Rappel version bêta"
|
||||
|
||||
@@ -79,7 +79,7 @@ SolutionsController::SolutionsController(Responder * parentResponder, EquationSt
|
||||
{
|
||||
m_delta2Layout = HorizontalLayout::Builder(VerticalOffsetLayout::Builder(CodePointLayout::Builder('2', KDFont::SmallFont), VerticalOffsetLayoutNode::Position::Superscript), LayoutHelper::String("-4ac", 4, KDFont::SmallFont));
|
||||
const char * deltaB = "Δ=b";
|
||||
static_cast<HorizontalLayout&>(m_delta2Layout).addOrMergeChildAtIndex(LayoutHelper::String(deltaB, 3, KDFont::SmallFont), 0, false);
|
||||
static_cast<HorizontalLayout&>(m_delta2Layout).addOrMergeChildAtIndex(LayoutHelper::String(deltaB, strlen(deltaB), KDFont::SmallFont), 0, false);
|
||||
for (int i = 0; i < EquationStore::k_maxNumberOfExactSolutions; i++) {
|
||||
m_exactValueCells[i].setParentResponder(m_contentView.selectableTableView());
|
||||
}
|
||||
|
||||
@@ -90,6 +90,20 @@ Responder * HistogramController::tabController() const {
|
||||
return (parentResponder()->parentResponder()->parentResponder()->parentResponder());
|
||||
}
|
||||
|
||||
void pad(char * buffer, int bufferSize, int * currentNumberOfChar, int maxGlyphLengthWithPadding) {
|
||||
assert(*currentNumberOfChar <= bufferSize);
|
||||
size_t currentGlyphLength = UTF8Helper::StringGlyphLength(buffer, *currentNumberOfChar);
|
||||
bool addedPadding = false;
|
||||
while (currentGlyphLength < maxGlyphLengthWithPadding && *currentNumberOfChar < bufferSize) {
|
||||
*currentNumberOfChar = *currentNumberOfChar + UTF8Decoder::CodePointToChars(' ', buffer + *currentNumberOfChar, bufferSize - *currentNumberOfChar);
|
||||
addedPadding = true;
|
||||
currentGlyphLength++;
|
||||
}
|
||||
if (addedPadding) {
|
||||
buffer[*currentNumberOfChar-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramController::reloadBannerView() {
|
||||
if (selectedSeriesIndex() < 0) {
|
||||
return;
|
||||
@@ -107,7 +121,7 @@ void HistogramController::reloadBannerView() {
|
||||
// Add lower bound
|
||||
if (selectedSeriesIndex() >= 0) {
|
||||
double lowerBound = m_store->startOfBarAtIndex(selectedSeriesIndex(), *m_selectedBarIndex);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(lowerBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(lowerBound, buffer+numberOfChar, bufferSize-numberOfChar, Constant::LargeNumberOfSignificantDigits);
|
||||
}
|
||||
|
||||
numberOfChar+= UTF8Decoder::CodePointToChars(';', buffer + numberOfChar, bufferSize - numberOfChar);
|
||||
@@ -115,15 +129,12 @@ void HistogramController::reloadBannerView() {
|
||||
// Add upper bound
|
||||
if (selectedSeriesIndex() >= 0) {
|
||||
double upperBound = m_store->endOfBarAtIndex(selectedSeriesIndex(), *m_selectedBarIndex);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(upperBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(upperBound, buffer+numberOfChar, bufferSize-numberOfChar, Constant::LargeNumberOfSignificantDigits);
|
||||
}
|
||||
numberOfChar+= UTF8Decoder::CodePointToChars('[', buffer + numberOfChar, bufferSize - numberOfChar);
|
||||
|
||||
// Padding
|
||||
for (int i = numberOfChar; i < k_maxIntervalLegendLength; i++) {
|
||||
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
|
||||
}
|
||||
buffer[k_maxIntervalLegendLength] = 0;
|
||||
pad(buffer, bufferSize, &numberOfChar, k_maxIntervalLegendLength);
|
||||
m_view.bannerView()->intervalView()->setText(buffer);
|
||||
|
||||
// Add Size Data
|
||||
@@ -135,13 +146,10 @@ void HistogramController::reloadBannerView() {
|
||||
double size = 0;
|
||||
if (selectedSeriesIndex() >= 0) {
|
||||
size = m_store->heightOfBarAtIndex(selectedSeriesIndex(), *m_selectedBarIndex);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(size, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(size, buffer+numberOfChar, bufferSize-numberOfChar, Constant::LargeNumberOfSignificantDigits);
|
||||
}
|
||||
// Padding
|
||||
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
|
||||
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
|
||||
}
|
||||
buffer[k_maxLegendLength] = 0;
|
||||
pad(buffer, bufferSize, &numberOfChar, k_maxLegendLength);
|
||||
m_view.bannerView()->sizeView()->setText(buffer);
|
||||
|
||||
// Add Frequency Data
|
||||
@@ -152,13 +160,10 @@ void HistogramController::reloadBannerView() {
|
||||
numberOfChar += legendLength;
|
||||
if (selectedSeriesIndex() >= 0) {
|
||||
double frequency = size/m_store->sumOfOccurrences(selectedSeriesIndex());
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(frequency, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
numberOfChar += PoincareHelpers::ConvertFloatToText<double>(frequency, buffer+numberOfChar, bufferSize - numberOfChar, Constant::LargeNumberOfSignificantDigits);
|
||||
}
|
||||
// Padding
|
||||
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
|
||||
numberOfChar+= UTF8Decoder::CodePointToChars(' ', buffer + numberOfChar, bufferSize - numberOfChar);
|
||||
}
|
||||
buffer[k_maxLegendLength] = 0;
|
||||
pad(buffer, bufferSize, &numberOfChar, k_maxLegendLength);
|
||||
m_view.bannerView()->frequencyView()->setText(buffer);
|
||||
|
||||
m_view.bannerView()->reload();
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
namespace TextInputHelpers {
|
||||
|
||||
const char * CursorPositionInCommand(const char * text);
|
||||
const char * CursorPositionInCommand(const char * text, const char * stoppingPosition = nullptr);
|
||||
/* Returns the pointer to the char that should be right of the cursor, which is
|
||||
* the first char between :
|
||||
* - The first EmptyChar (which is the position of the first argument)
|
||||
|
||||
@@ -34,47 +34,62 @@ static inline void InsertSpacesAtLocation(int spacesCount, char * buffer, int bu
|
||||
}
|
||||
|
||||
bool TextArea::handleEventWithText(const char * text, bool indentation, bool forceCursorRightOfText) {
|
||||
constexpr int bufferSize = TextField::maxBufferSize();
|
||||
char buffer[bufferSize];
|
||||
|
||||
size_t textLength = strlcpy(buffer, text, bufferSize);
|
||||
|
||||
// Add indentation spaces
|
||||
if (*text == 0) {
|
||||
return false;
|
||||
}
|
||||
/* Compute the indentation. If the text cannot be inserted with the
|
||||
* indentation, stop here. */
|
||||
int spacesCount = 0;
|
||||
int totalIndentationSize = 0;
|
||||
int textLen = strlen(text);
|
||||
char * insertionPosition = const_cast<char *>(cursorLocation());
|
||||
if (indentation) {
|
||||
// Compute the indentation
|
||||
int spacesCount = indentationBeforeCursor();
|
||||
const char * teaxtAreaBuffer = contentView()->text();
|
||||
if (cursorLocation() > teaxtAreaBuffer && UTF8Helper::PreviousCodePointIs(teaxtAreaBuffer, cursorLocation(), ':')) {
|
||||
spacesCount = indentationBeforeCursor();
|
||||
const char * textAreaBuffer = contentView()->text();
|
||||
if (insertionPosition > textAreaBuffer && UTF8Helper::PreviousCodePointIs(textAreaBuffer, insertionPosition, ':')) {
|
||||
spacesCount += k_indentationSpaces;
|
||||
}
|
||||
|
||||
// Check the text will not overflow the buffer
|
||||
int totalIndentationSize = UTF8Helper::CountOccurrences(text, '\n') * spacesCount;
|
||||
if (contentView()->getText()->textLength() + textLength + totalIndentationSize >= contentView()->getText()->bufferSize() || textLength == 0) {
|
||||
totalIndentationSize = UTF8Helper::CountOccurrences(text, '\n') * spacesCount;
|
||||
if (contentView()->getText()->textLength() + textLen + totalIndentationSize >= contentView()->getText()->bufferSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UTF8Helper::PerformAtCodePoints(
|
||||
buffer, '\n',
|
||||
[](int codePointOffset, void * text, int indentation) {
|
||||
int offset = codePointOffset + UTF8Decoder::CharSizeOfCodePoint('\n');
|
||||
InsertSpacesAtLocation(indentation, (char *)text + offset, TextField::maxBufferSize() - offset); //TODO
|
||||
},
|
||||
[](int c1, void * c2, int c3) {},
|
||||
(void *)buffer,
|
||||
spacesCount);
|
||||
}
|
||||
const char * cursorPositionInCommand = TextInputHelpers::CursorPositionInCommand(buffer);
|
||||
|
||||
// Remove the Empty code points
|
||||
UTF8Helper::RemoveCodePoint(buffer, UCodePointEmpty, &cursorPositionInCommand);
|
||||
|
||||
// Insert the text
|
||||
if (insertTextAtLocation(buffer, cursorLocation())) {
|
||||
// Set the cursor location
|
||||
const char * nextCursorLocation = cursorLocation() + (forceCursorRightOfText ? strlen(buffer) : cursorPositionInCommand - buffer);
|
||||
setCursorLocation(nextCursorLocation);
|
||||
if (!insertTextAtLocation(text, insertionPosition)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert the indentation
|
||||
if (indentation) {
|
||||
UTF8Helper::PerformAtCodePoints(
|
||||
insertionPosition,
|
||||
'\n',
|
||||
[](int codePointOffset, void * text, int indentation, int bufferLength) {
|
||||
int offset = codePointOffset + UTF8Decoder::CharSizeOfCodePoint('\n');
|
||||
InsertSpacesAtLocation(indentation, (char *)text + offset, bufferLength);
|
||||
},
|
||||
[](int c1, void * c2, int c3, int c4) {},
|
||||
(void *)insertionPosition,
|
||||
spacesCount,
|
||||
contentView()->getText()->bufferSize() - (insertionPosition - contentView()->getText()->text()),
|
||||
UCodePointNull,
|
||||
true,
|
||||
nullptr,
|
||||
insertionPosition + textLen);
|
||||
}
|
||||
const char * endOfInsertedText = insertionPosition + textLen + totalIndentationSize;
|
||||
const char * cursorPositionInCommand = TextInputHelpers::CursorPositionInCommand(insertionPosition, endOfInsertedText);
|
||||
|
||||
// Remove the Empty code points
|
||||
UTF8Helper::RemoveCodePoint(insertionPosition, UCodePointEmpty, &cursorPositionInCommand, endOfInsertedText);
|
||||
|
||||
// Set the cursor location
|
||||
const char * nextCursorLocation = forceCursorRightOfText ? endOfInsertedText : cursorPositionInCommand;
|
||||
setCursorLocation(nextCursorLocation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -136,14 +151,14 @@ int TextArea::indentationBeforeCursor() const {
|
||||
* indentation size when encountering spaces, reset it to 0 when encountering
|
||||
* another code point, until reaching the beginning of the line. */
|
||||
UTF8Helper::PerformAtCodePoints(const_cast<TextArea *>(this)->contentView()->text(), ' ',
|
||||
[](int codePointOffset, void * indentationSize, int context){
|
||||
[](int codePointOffset, void * indentationSize, int context1, int context2){
|
||||
int * castedSize = (int *) indentationSize;
|
||||
*castedSize = *castedSize + 1;
|
||||
},
|
||||
[](int codePointOffset, void * indentationSize, int context){
|
||||
[](int codePointOffset, void * indentationSize, int context1, int context2){
|
||||
*((int *) indentationSize) = 0;
|
||||
},
|
||||
&indentationSize, 0, '\n', false, cursorLocation());
|
||||
&indentationSize, 0, -1, '\n', false, cursorLocation());
|
||||
return indentationSize;
|
||||
}
|
||||
|
||||
@@ -380,10 +395,10 @@ bool TextArea::TextArea::ContentView::insertTextAtLocation(const char * text, co
|
||||
// Scan for \n and 0
|
||||
const char * nullLocation = UTF8Helper::PerformAtCodePoints(
|
||||
text, '\n',
|
||||
[](int codePointOffset, void * lineBreak, int indentation) {
|
||||
[](int codePointOffset, void * lineBreak, int context1, int context2) {
|
||||
*((bool *)lineBreak) = true;
|
||||
},
|
||||
[](int c1, void * c2, int c3) { },
|
||||
[](int c1, void * c2, int c3, int c4) { },
|
||||
&lineBreak, 0);
|
||||
|
||||
assert(UTF8Helper::CodePointIs(nullLocation, 0));
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
|
||||
namespace TextInputHelpers {
|
||||
|
||||
const char * CursorPositionInCommand(const char * text) {
|
||||
const char * CursorPositionInCommand(const char * text, const char * stoppingPosition) {
|
||||
assert(stoppingPosition == nullptr || text <= stoppingPosition);
|
||||
UTF8Decoder decoder(text);
|
||||
const char * currentPointer = text;
|
||||
CodePoint codePoint = decoder.nextCodePoint();
|
||||
while (codePoint != UCodePointNull) {
|
||||
while ((stoppingPosition == nullptr || currentPointer < stoppingPosition) && codePoint != UCodePointNull) {
|
||||
if (codePoint == UCodePointEmpty) {
|
||||
return currentPointer;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ tests += $(addprefix ion/test/,\
|
||||
keyboard.cpp\
|
||||
storage.cpp\
|
||||
utf8_decoder.cpp\
|
||||
utf8_helper.cpp\
|
||||
)
|
||||
|
||||
TEST_EXT_FLASH_REPROGRAM ?= 0
|
||||
|
||||
@@ -24,7 +24,7 @@ void CopyAndRemoveCodePoint(char * dst, size_t dstSize, const char * src, CodePo
|
||||
|
||||
/* Remove all code points c. and update an index that should be lower if code
|
||||
* points where removed before it. Ensure null-termination of dst. */
|
||||
void RemoveCodePoint(char * buffer, CodePoint c, const char * * indexToDUpdate = nullptr);
|
||||
void RemoveCodePoint(char * buffer, CodePoint c, const char * * indexToDUpdate = nullptr, const char * stoppingPosition = nullptr);
|
||||
|
||||
/* Copy src into dst until end of dst or code point c, with null termination. Return the length of the copy */
|
||||
size_t CopyUntilCodePoint(char * dst, size_t dstSize, const char * src, CodePoint c);
|
||||
@@ -50,8 +50,19 @@ size_t CopyUntilCodePoint(char * dst, size_t dstSize, const char * src, CodePoin
|
||||
* ^start of string ^r ^initialPosition
|
||||
*
|
||||
* */
|
||||
typedef void (*CodePointAction)(int codePointOffset, void * contextPointer, int contextInt);
|
||||
const char * PerformAtCodePoints(const char * string, CodePoint c, CodePointAction actionCodePoint, CodePointAction actionOtherCodePoint, void * contextPointer, int contextInt, CodePoint stoppingCodePoint = UCodePointNull, bool goingRight = true, const char * initialPosition = nullptr);
|
||||
typedef void (*CodePointAction)(int codePointOffset, void * contextPointer, int contextInt1, int contextInt2);
|
||||
const char * PerformAtCodePoints(
|
||||
const char * string,
|
||||
CodePoint c,
|
||||
CodePointAction actionCodePoint,
|
||||
CodePointAction actionOtherCodePoint,
|
||||
void * contextPointer,
|
||||
int contextInt1,
|
||||
int contextInt2 = -1,
|
||||
CodePoint stoppingCodePoint = UCodePointNull,
|
||||
bool goingRight = true,
|
||||
const char * initialPosition = nullptr,
|
||||
const char * stoppingPosition = nullptr);
|
||||
|
||||
bool PreviousCodePointIs(const char * buffer, const char * location, CodePoint c);
|
||||
bool CodePointIs(const char * location, CodePoint c);
|
||||
@@ -68,6 +79,10 @@ int RemovePreviousCodePoint(const char * text, char * location, CodePoint * c);
|
||||
const char * CodePointAtGlyphOffset(const char * buffer, int position);
|
||||
size_t GlyphOffsetAtCodePoint(const char * buffer, const char * position);
|
||||
|
||||
/* Return the number of glyphs in a string.
|
||||
* For instance, strlen("∑") = 3 but StringGlyphLength("∑") = 1 */
|
||||
size_t StringGlyphLength(const char * s, int maxSize = -1);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -110,7 +110,7 @@ void CopyAndRemoveCodePoint(char * dst, size_t dstSize, const char * src, CodePo
|
||||
*(dst + minInt(bufferIndex, dstSize - 1)) = 0;
|
||||
}
|
||||
|
||||
void RemoveCodePoint(char * buffer, CodePoint c, const char * * pointerToUpdate) {
|
||||
void RemoveCodePoint(char * buffer, CodePoint c, const char * * pointerToUpdate, const char * stoppingPosition) {
|
||||
UTF8Decoder decoder(buffer);
|
||||
const char * currentPointer = buffer;
|
||||
CodePoint codePoint = decoder.nextCodePoint();
|
||||
@@ -118,7 +118,7 @@ void RemoveCodePoint(char * buffer, CodePoint c, const char * * pointerToUpdate)
|
||||
size_t bufferIndex = 0;
|
||||
size_t codePointCharSize = UTF8Decoder::CharSizeOfCodePoint(c);
|
||||
|
||||
while (codePoint != UCodePointNull) {
|
||||
while (codePoint != UCodePointNull && (stoppingPosition == nullptr || currentPointer < stoppingPosition)) {
|
||||
if (codePoint != c) {
|
||||
int copySize = nextPointer - currentPointer;
|
||||
memmove(buffer + bufferIndex, currentPointer, copySize);
|
||||
@@ -131,7 +131,16 @@ void RemoveCodePoint(char * buffer, CodePoint c, const char * * pointerToUpdate)
|
||||
codePoint = decoder.nextCodePoint();
|
||||
nextPointer = decoder.stringPosition();
|
||||
}
|
||||
*(buffer + bufferIndex) = 0;
|
||||
if (codePoint == UCodePointNull) {
|
||||
*(buffer + bufferIndex) = 0;
|
||||
} else {
|
||||
assert(stoppingPosition != nullptr);
|
||||
// Find the null-terminating code point
|
||||
const char * nullTermination = CodePointSearch(currentPointer, UCodePointNull);
|
||||
/* Copy what remains of the buffer after the stopping position for code
|
||||
* point removal */
|
||||
memmove(buffer + bufferIndex, stoppingPosition, nullTermination - stoppingPosition + 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CopyUntilCodePoint(char * dst, size_t dstSize, const char * src, CodePoint c) {
|
||||
@@ -150,7 +159,7 @@ size_t CopyUntilCodePoint(char * dst, size_t dstSize, const char * src, CodePoin
|
||||
return copySize;
|
||||
}
|
||||
|
||||
const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction actionCodePoint, CodePointAction actionOtherCodePoint, void * contextPointer, int contextInt, CodePoint stoppingCodePoint, bool goingRight, const char * initialPosition) {
|
||||
const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction actionCodePoint, CodePointAction actionOtherCodePoint, void * contextPointer, int contextInt1, int contextInt2, CodePoint stoppingCodePoint, bool goingRight, const char * initialPosition, const char * stoppingPosition) {
|
||||
/* If we are decoding towards the left, we must have a starting position. If
|
||||
* we are decoding towards the right, the starting position is the start of
|
||||
* string. */
|
||||
@@ -162,22 +171,22 @@ const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction ac
|
||||
* translations. We can do a classic char search. */
|
||||
if (goingRight) {
|
||||
const char * i = s;
|
||||
while (*i != stoppingCodePoint && *i != 0) {
|
||||
while (*i != stoppingCodePoint && *i != 0 && i != stoppingPosition) {
|
||||
if (*i == c) {
|
||||
actionCodePoint(i - s, contextPointer, contextInt);
|
||||
actionCodePoint(i - s, contextPointer, contextInt1, contextInt2);
|
||||
} else {
|
||||
actionOtherCodePoint(i - s, contextPointer, contextInt);
|
||||
actionOtherCodePoint(i - s, contextPointer, contextInt1, contextInt2);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
const char * i = initialPosition - 1;
|
||||
while (i >= s && *i != stoppingCodePoint) {
|
||||
while (i >= s && *i != stoppingCodePoint && i != stoppingPosition) {
|
||||
if (*i == c) {
|
||||
actionCodePoint(i - s, contextPointer, contextInt);
|
||||
actionCodePoint(i - s, contextPointer, contextInt1, contextInt2);
|
||||
} else {
|
||||
actionOtherCodePoint(i - s, contextPointer, contextInt);
|
||||
actionOtherCodePoint(i - s, contextPointer, contextInt1, contextInt2);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
@@ -188,11 +197,11 @@ const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction ac
|
||||
UTF8Decoder decoder(s);
|
||||
const char * codePointPointer = decoder.stringPosition();
|
||||
CodePoint codePoint = decoder.nextCodePoint();
|
||||
while (codePoint != stoppingCodePoint && codePoint != UCodePointNull) {
|
||||
while (codePoint != stoppingCodePoint && codePoint != UCodePointNull && codePointPointer != stoppingPosition) {
|
||||
if (codePoint == c) {
|
||||
actionCodePoint(codePointPointer - s, contextPointer, contextInt);
|
||||
actionCodePoint(codePointPointer - s, contextPointer, contextInt1, contextInt2);
|
||||
} else {
|
||||
actionOtherCodePoint(codePointPointer - s, contextPointer, contextInt);
|
||||
actionOtherCodePoint(codePointPointer - s, contextPointer, contextInt1, contextInt2);
|
||||
}
|
||||
codePointPointer = decoder.stringPosition();
|
||||
codePoint = decoder.nextCodePoint();
|
||||
@@ -206,11 +215,11 @@ const char * PerformAtCodePoints(const char * s, CodePoint c, CodePointAction ac
|
||||
UTF8Decoder decoder(s, initialPosition);
|
||||
CodePoint codePoint = decoder.previousCodePoint();
|
||||
const char * codePointPointer = decoder.stringPosition();
|
||||
while (codePointPointer >= s && codePoint != stoppingCodePoint) {
|
||||
while (codePointPointer >= s && codePoint != stoppingCodePoint && codePointPointer != stoppingPosition) {
|
||||
if (codePoint == c) {
|
||||
actionCodePoint(codePointPointer - s, contextPointer, contextInt);
|
||||
actionCodePoint(codePointPointer - s, contextPointer, contextInt1, contextInt2);
|
||||
} else {
|
||||
actionOtherCodePoint(codePointPointer - s, contextPointer, contextInt);
|
||||
actionOtherCodePoint(codePointPointer - s, contextPointer, contextInt1, contextInt2);
|
||||
}
|
||||
if (codePointPointer > s) {
|
||||
codePoint = decoder.previousCodePoint();
|
||||
@@ -326,5 +335,20 @@ size_t GlyphOffsetAtCodePoint(const char * buffer, const char * position) {
|
||||
return glyphIndex;
|
||||
}
|
||||
|
||||
size_t StringGlyphLength(const char * s, int maxSize) {
|
||||
if (maxSize == 0) {
|
||||
return 0;
|
||||
}
|
||||
UTF8Decoder decoder(s);
|
||||
CodePoint codePoint = decoder.nextCodePoint();
|
||||
size_t glyphIndex = 0;
|
||||
while (codePoint != UCodePointNull && (maxSize < 0 || ((decoder.stringPosition() - s) <= maxSize))) {
|
||||
if (!codePoint.isCombining()) {
|
||||
glyphIndex++;
|
||||
}
|
||||
codePoint = decoder.nextCodePoint();
|
||||
}
|
||||
return glyphIndex;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
14
ion/test/utf8_helper.cpp
Normal file
14
ion/test/utf8_helper.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <quiz.h>
|
||||
#include <ion/unicode/utf8_helper.h>
|
||||
|
||||
void assert_string_glyph_length_is(const char * string, int maxSize, size_t result) {
|
||||
quiz_assert(UTF8Helper::StringGlyphLength(string, maxSize) == result);
|
||||
}
|
||||
|
||||
QUIZ_CASE(ion_utf8_helper_glyph_length) {
|
||||
assert_string_glyph_length_is("123", -1, 3);
|
||||
assert_string_glyph_length_is("1ᴇ3", -1, 3);
|
||||
assert_string_glyph_length_is("∑∫𝐢", -1, 3);
|
||||
assert_string_glyph_length_is("123", 2, 2);
|
||||
assert_string_glyph_length_is("1ᴇ3", 2, 1);
|
||||
}
|
||||
Reference in New Issue
Block a user