static void do_find (TextEditor me) { if (! theFindString) return; // e.g. when the user does "Find again" before having done any "Find" long left, right; autostring32 text = GuiText_getStringAndSelectionPosition (my textWidget, & left, & right); char32 *location = str32str (& text [right], theFindString); if (location) { long index = location - text.peek(); GuiText_setSelection (my textWidget, index, index + str32len (theFindString)); GuiText_scrollToSelection (my textWidget); #ifdef _WIN32 GuiThing_show (my d_windowForm); #endif } else { /* Try from the start of the document. */ location = str32str (text.peek(), theFindString); if (location) { long index = location - text.peek(); GuiText_setSelection (my textWidget, index, index + str32len (theFindString)); GuiText_scrollToSelection (my textWidget); #ifdef _WIN32 GuiThing_show (my d_windowForm); #endif } else { Melder_beep (); } } }
int Melder_fatal (Melder_9_ARGS) { MelderThread_LOCK (theMelder_fatal_mutex); const char32 *s1 = arg1. _arg ? arg1. _arg : U""; int64 length1 = str32len (s1); const char32 *s2 = arg2. _arg ? arg2. _arg : U""; int64 length2 = str32len (s2); const char32 *s3 = arg3. _arg ? arg3. _arg : U""; int64 length3 = str32len (s3); const char32 *s4 = arg4. _arg ? arg4. _arg : U""; int64 length4 = str32len (s4); const char32 *s5 = arg5. _arg ? arg5. _arg : U""; int64 length5 = str32len (s5); const char32 *s6 = arg6. _arg ? arg6. _arg : U""; int64 length6 = str32len (s6); const char32 *s7 = arg7. _arg ? arg7. _arg : U""; int64 length7 = str32len (s7); const char32 *s8 = arg8. _arg ? arg8. _arg : U""; int64 length8 = str32len (s8); const char32 *s9 = arg9. _arg ? arg9. _arg : U""; int64 length9 = str32len (s9); str32cpy (theFatalBuffer, theCrashMessage); int64 length = str32len (theFatalBuffer); if (length + length1 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s1); length += length1; } if (length + length2 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s2); length += length2; } if (length + length3 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s3); length += length3; } if (length + length4 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s4); length += length4; } if (length + length5 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s5); length += length5; } if (length + length6 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s6); length += length6; } if (length + length7 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s7); length += length7; } if (length + length8 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s8); length += length8; } if (length + length9 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s9); length += length9; } trace (U"FATAL: ", theFatalBuffer); theMelder. fatal (theFatalBuffer); abort (); return 0; }
bool Melder_stringMatchesCriterion (const char32 *value, int which_kMelder_string, const char32 *criterion) { if (! value) { value = U""; // regard null strings as empty strings, as is usual in Praat } if (! criterion) { criterion = U""; // regard null strings as empty strings, as is usual in Praat } if (which_kMelder_string <= kMelder_string_NOT_EQUAL_TO) { bool matchPositiveCriterion = str32equ (value, criterion); return ( which_kMelder_string == kMelder_string_EQUAL_TO ) == matchPositiveCriterion; } if (which_kMelder_string <= kMelder_string_DOES_NOT_CONTAIN) { bool matchPositiveCriterion = !! str32str (value, criterion); return ( which_kMelder_string == kMelder_string_CONTAINS ) == matchPositiveCriterion; } if (which_kMelder_string <= kMelder_string_DOES_NOT_START_WITH) { bool matchPositiveCriterion = str32nequ (value, criterion, str32len (criterion)); return ( which_kMelder_string == kMelder_string_STARTS_WITH ) == matchPositiveCriterion; } if (which_kMelder_string <= kMelder_string_DOES_NOT_END_WITH) { int criterionLength = str32len (criterion), valueLength = str32len (value); bool matchPositiveCriterion = ( criterionLength <= valueLength && str32equ (value + valueLength - criterionLength, criterion) ); return (which_kMelder_string == kMelder_string_ENDS_WITH) == matchPositiveCriterion; } if (which_kMelder_string == kMelder_string_MATCH_REGEXP) { char32 *place = nullptr; regexp *compiled_regexp = CompileRE_throwable (criterion, 0); if (ExecRE (compiled_regexp, nullptr, value, nullptr, 0, '\0', '\0', nullptr, nullptr, nullptr)) place = compiled_regexp -> startp [0]; free (compiled_regexp); return !! place; } return false; // should not occur }
void SimpleString_append_c (SimpleString me, const char32 *str) { if (! str) { return; } long myLength = str32len (my string); my string = (char32 *) Melder_realloc (my string, (myLength + str32len (str) + 1) * (int64) sizeof (char32)); str32cpy (& my string[myLength], str); }
int Melder_fatal (Melder_1_ARG) { MelderThread_LOCK (theMelder_fatal_mutex); const char32 *s1 = arg1. _arg ? arg1. _arg : U""; int64 length1 = str32len (s1); str32cpy (theFatalBuffer, theCrashMessage); int64 length = str32len (theFatalBuffer); if (length + length1 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s1); length += length1; } trace (U"FATAL: ", theFatalBuffer); theMelder. fatal (theFatalBuffer); abort (); return 0; }
static bool getSelectedLines (TextEditor me, long *firstLine, long *lastLine) { long left, right; char32 *text = GuiText_getStringAndSelectionPosition (my textWidget, & left, & right); long textLength = str32len (text); Melder_assert (left >= 0); Melder_assert (left <= right); Melder_assert (right <= textLength); long i = 0; *firstLine = 1; /* * Cycle through the text in order to see how many linefeeds we pass. */ for (; i < left; i ++) { if (text [i] == '\n') { (*firstLine) ++; } } if (left == right) return false; *lastLine = *firstLine; for (; i < right; i ++) { if (text [i] == '\n') { (*lastLine) ++; } } Melder_free (text); return true; }
void TextTier_changeLabels (I, long from, long to, const char32 *search, const char32 *replace, int use_regexp, long *nmatches, long *nstringmatches) { iam (TextTier); try { if (from == 0) { from = 1; } if (to == 0) { to = my points -> size; } if (from > to || from < 1 || to > my points -> size) { Melder_throw (U"Incorrect specification of where to act."); } if (use_regexp && str32len (search) == 0) Melder_throw (U"The regex search string cannot be empty.\n" U"You may search for an empty string with the expression \"^$\""); long nmarks = to - from + 1; autoNUMvector<char32 *> marks (1, nmarks); for (long i = from; i <= to; i++) { TextPoint point = (TextPoint) my points -> item[i]; marks[i - from + 1] = point -> mark; // Shallow copy. } autostring32vector newmarks (strs_replace (marks.peek(), 1, nmarks, search, replace, 0, nmatches, nstringmatches, use_regexp), 1, nmarks); for (long i = from; i <= to; i++) { TextPoint point = (TextPoint) my points -> item[i]; Melder_free (point -> mark); point -> mark = newmarks[i - from + 1]; // Transfer of ownership. newmarks[i - from + 1] = 0; } } catch (MelderError) { Melder_throw (me, U": no labels changed."); } }
void structWordList :: v_info () { structData :: v_info (); long n = WordList_count (this); if (! our length) our length = str32len (our string); MelderInfo_writeLine (U"Number of words: ", n); MelderInfo_writeLine (U"Number of characters: ", length - n); }
static autoTextGrid SpeechSynthesizer_and_Sound_and_IntervalTier_align2 (SpeechSynthesizer me, Sound thee, IntervalTier him, long istart, long iend, double silenceThreshold, double minSilenceDuration, double minSoundingDuration, double trimDuration) { try { if (istart < 1 || iend < istart || iend > his intervals.size) { Melder_throw (U"Not avalid interval range."); } OrderedOf<structTextGrid> textgrids; TextInterval tb = his intervals.at [istart]; TextInterval te = his intervals.at [iend]; autoTextGrid result = TextGrid_create (tb -> xmin, te -> xmax, U"sentence clause word phoneme", U""); for (long iint = istart; iint <= iend; iint ++) { TextInterval ti = his intervals.at [iint]; if (ti -> text && str32len (ti -> text) > 0) { autoSound sound = Sound_extractPart (thee, ti -> xmin, ti -> xmax, kSound_windowShape_RECTANGULAR, 1, true); autoTextGrid grid = SpeechSynthesizer_and_Sound_and_TextInterval_align2 (me, sound.peek(), ti, silenceThreshold, minSilenceDuration, minSoundingDuration, trimDuration); textgrids. addItem_move (grid.move()); } } if (textgrids.size == 0) { Melder_throw (U"Nothing could be aligned. Was your IntervalTier empty?"); } autoTextGrid aligned = TextGrids_to_TextGrid_appendContinuous (& textgrids, true); return aligned; } catch (MelderError) { Melder_throw (U"No aligned TextGrid created."); } }
void structWordList :: v_writeBinary (FILE *f) { long currentLength, previousLength; if (! length) length = str32len (string); binputi4 (length, f); if (length > 0) { char32 *current = string, *kar = current; for (kar = current; *kar != U'\n'; kar ++) { } currentLength = kar - current; for (long i = 0; i < currentLength; i ++) fputc ((int) current [i], f); // TODO: check for (;;) { char32 *previous = current, *kar1, *kar2; int numberOfSame; previousLength = currentLength; current = previous + previousLength + 1; if (*current == U'\0') break; kar1 = previous, kar2 = current; while (*kar2 != U'\n' && *kar2 == *kar1) { kar1 ++, kar2 ++; } numberOfSame = kar2 - current; if (numberOfSame > 127) numberOfSame = 127; // clip fputc (128 + numberOfSame, f); while (*kar2 != U'\n') kar2 ++; currentLength = kar2 - current; for (long i = 0; i < currentLength - numberOfSame; i ++) fputc ((int) current [numberOfSame + i], f); // TODO: check } } }
void IntervalTier_changeLabels (I, long from, long to, const char32 *search, const char32 *replace, int use_regexp, long *nmatches, long *nstringmatches) { iam (IntervalTier); try { if (from == 0) { from = 1; } if (to == 0) { to = my intervals -> size; } if (from > to || from < 1 || to > my intervals -> size) { Melder_throw (U"Incorrect specification of where to act."); } if (use_regexp && str32len (search) == 0) Melder_throw (U"The regex search string cannot be empty.\n" U"You may search for an empty string with the expression \"^$\""); long nlabels = to - from + 1; autoNUMvector<char32 *> labels (1, nlabels); for (long i = from; i <= to; i++) { TextInterval interval = (TextInterval) my intervals -> item[i]; labels[i - from + 1] = interval -> text; // Shallow copy. } autostring32vector newlabels (strs_replace (labels.peek(), 1, nlabels, search, replace, 0, nmatches, nstringmatches, use_regexp), 1, nlabels); for (long i = from; i <= to; i++) { TextInterval interval = (TextInterval) my intervals -> item[i]; Melder_free (interval -> text); interval -> text = newlabels[i - from + 1]; // Transfer of ownership. newlabels[i - from + 1] = 0; } } catch (MelderError) { Melder_throw (me, U": labels not changed."); } }
static long Strings_totalLength (Strings me) { long totalLength = 0; for (long i = 1; i <= my numberOfStrings; i ++) { totalLength += str32len (my strings [i]); } return totalLength; }
int Melder_fatal (Melder_4_ARGS) { MelderThread_LOCK (theMelder_fatal_mutex); const char32 *s1 = arg1. _arg ? arg1. _arg : U""; int64 length1 = str32len (s1); const char32 *s2 = arg2. _arg ? arg2. _arg : U""; int64 length2 = str32len (s2); const char32 *s3 = arg3. _arg ? arg3. _arg : U""; int64 length3 = str32len (s3); const char32 *s4 = arg4. _arg ? arg4. _arg : U""; int64 length4 = str32len (s4); str32cpy (theFatalBuffer, theCrashMessage); int64 length = str32len (theFatalBuffer); if (length + length1 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s1); length += length1; } if (length + length2 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s2); length += length2; } if (length + length3 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s3); length += length3; } if (length + length4 < Melder_FATAL_BUFFER_SIZE) { str32cpy (theFatalBuffer + length, s4); length += length4; } trace (U"FATAL: ", theFatalBuffer); theMelder. fatal (theFatalBuffer); abort (); return 0; }
const char32 * Melder_truncate (const char32 *string, int64 width) { if (++ iPadBuffer == NUMBER_OF_BUFFERS) iPadBuffer = 0; int64 length = str32len (string); int64 tooLong = length - width; if (tooLong <= 0) return string; MelderString_ncopy (& thePadBuffers [iPadBuffer], string, width); return thePadBuffers [iPadBuffer]. string; }
void Melder_assert_ (const char *fileName, int lineNumber, const char *condition) { /* * This function tries to make sure that it allocates no heap memory. * Hence, character conversion is done inline rather than with Melder_peek8to32(), * and Melder_integer() is also avoided. */ MelderThread_LOCK (theMelder_fatal_mutex); static char32 fileNameBuffer [1000], conditionBuffer [1000], lineNumberBuffer [40]; Melder_8to32_inline (fileName, fileNameBuffer, kMelder_textInputEncoding_UTF8); Melder_8to32_inline (condition, conditionBuffer, kMelder_textInputEncoding_UTF8); static char lineNumberBuffer8 [40]; sprintf (lineNumberBuffer8, "%d", lineNumber); Melder_8to32_inline (lineNumberBuffer8, lineNumberBuffer, kMelder_textInputEncoding_UTF8); str32cpy (theFatalBuffer, theCrashMessage); str32cpy (theFatalBuffer + str32len (theFatalBuffer), U"Assertion failed in file \""); str32cpy (theFatalBuffer + str32len (theFatalBuffer), fileNameBuffer); str32cpy (theFatalBuffer + str32len (theFatalBuffer), U"\" at line "); str32cpy (theFatalBuffer + str32len (theFatalBuffer), lineNumberBuffer); str32cpy (theFatalBuffer + str32len (theFatalBuffer), U":\n "); str32cpy (theFatalBuffer + str32len (theFatalBuffer), conditionBuffer); str32cpy (theFatalBuffer + str32len (theFatalBuffer), U"\n"); trace (U"FATAL: ", theFatalBuffer); theMelder. fatal (theFatalBuffer); // ...but this call will use heap memory... abort (); }
void SpellingChecker_addNewWord (SpellingChecker me, const char32 *word) { try { autostring32 generic = Melder_calloc (char32, 3 * str32len (word) + 1); Longchar_genericize32 (word, generic.peek()); my userDictionary -> addString_copy (generic.transfer()); } catch (MelderError) { Melder_throw (me, U": word \"", word, U"\" not added."); } }
static long Strings_maximumLength (Strings me) { long maximumLength = 0; for (long i = 1; i <= my numberOfStrings; i ++) { long length = str32len (my strings [i]); if (length > maximumLength) { maximumLength = length; } } return maximumLength; }
const char32 * Melder_pad (const char32 *string, int64 width) { if (++ iPadBuffer == NUMBER_OF_BUFFERS) iPadBuffer = 0; int64 length = str32len (string); int64 tooShort = width - length; if (tooShort <= 0) return string; MelderString_copy (& thePadBuffers [iPadBuffer], string); for (int64 i = 0; i < tooShort; i ++) MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' '); return thePadBuffers [iPadBuffer]. string; }
void SpellingChecker_addNewWord (SpellingChecker me, const char32 *word) { try { if (! my userDictionary) my userDictionary = SortedSetOfString_create (); autostring32 generic = Melder_calloc (char32, 3 * str32len (word) + 1); Longchar_genericize32 (word, generic.peek()); SortedSetOfString_addString (my userDictionary, generic.transfer()); } catch (MelderError) { Melder_throw (me, U": word \"", word, U"\" not added."); } }
static void insert (CategoriesEditor me, int position) { autostring32 text = GuiText_getString (my text); if (str32len (text.peek()) != 0) { autoSimpleString str = SimpleString_create (text.peek()); autoCategoriesEditorInsert command = CategoriesEditorInsert_create (me, str.move(), position); Command_do (command.peek()); if (my history) { CommandHistory_insertItem_move (my history.peek(), command.move()); } updateWidgets (me); } }
static void menu_cb_pasteHistory (ScriptEditor me, EDITOR_ARGS_DIRECT) { char32 *history = UiHistory_get (); if (! history || history [0] == U'\0') Melder_throw (U"No history."); long length = str32len (history); if (history [length - 1] != U'\n') { UiHistory_write (U"\n"); history = UiHistory_get (); length = str32len (history); } if (history [0] == U'\n') { history ++; length --; } long first = 0, last = 0; char32 *text = GuiText_getStringAndSelectionPosition (my textWidget, & first, & last); Melder_free (text); GuiText_replace (my textWidget, first, last, history); GuiText_setSelection (my textWidget, first, first + length); GuiText_scrollToSelection (my textWidget); }
int NUMstring_containsPrintableCharacter (const char32 *s) { long len; if (s == NULL || ( (len = str32len (s)) == 0)) { return 0; } for (long i = 0; i < len; i++) { if (isgraph ((int) s[i])) { return 1; } } return 0; }
autoStrings Strings_createAsCharacters (const char32 *string) { try { autoStrings me = Thing_new (Strings); my numberOfStrings = str32len (string); my strings = NUMvector<char32 *> (1, my numberOfStrings); for (long i = 1; i <= my numberOfStrings; i++) { my strings[i] = Melder_dup (Melder_character (*string++)); } return me; } catch (MelderError) { Melder_throw (U"Strings from characters not created."); } }
void NUMstring_chopWhiteSpaceAtExtremes_inline (char32 *string) { int64 start = 0; while (iswspace ((int) string[start]) != 0) { start++; } int64 end = str32len (string); while (end != start && iswspace((int) string[end - 1]) != 0) { end--; } int64 n = end - start; memmove (string, string + start, (size_t) (n * (int64) sizeof (char32))); string[n] = 0; }
char32 * Melder_dup (const char32 *string /* cattable */) { if (! string) return NULL; int64 size = (int64) str32len (string) + 1; // guaranteed to be positive if (sizeof (size_t) < 8 && size > SIZE_MAX / sizeof (char32)) Melder_throw (U"Can never allocate ", Melder_bigInteger (size), U" characters. Use a 64-bit edition of Praat instead?"); char32 *result = (char32 *) malloc ((size_t) size * sizeof (char32)); // guarded conversion if (result == NULL) Melder_throw (U"Out of memory: there is not enough room to duplicate a text of ", Melder_bigInteger (size - 1), U" characters."); str32cpy (result, string); if (Melder_debug == 34) { Melder_casual (U"Melder_dup\t", Melder_pointer (result), U"\t", Melder_bigInteger (size), U"\t4"); } totalNumberOfAllocations += 1; totalAllocationSize += size * (int64) sizeof (char32); return result; }
WordList Strings_to_WordList (Strings me) { try { long totalLength = 0; /* * Check whether the strings are generic and sorted. */ for (long i = 1; i <= my numberOfStrings; i ++) { char32 *string = my strings [i], *p; for (p = & string [0]; *p; p ++) { if (*p > 126) Melder_throw (U"String \"", string, U"\" not generic.\nPlease convert to backslash trigraphs first."); } if (i > 1 && str32cmp (my strings [i - 1], string) > 0) { Melder_throw (U"String \"", string, U"\" not sorted.\nPlease sort first."); } totalLength += str32len (string); } autoWordList thee = Thing_new (WordList); thy length = totalLength + my numberOfStrings; thy string = Melder_calloc (char32, thy length + 1); /* * Concatenate the strings into the word list. */ char32 *q = thy string; for (long i = 1; i <= my numberOfStrings; i ++) { long length = str32len (my strings [i]); str32cpy (q, my strings [i]); q += length; *q ++ = '\n'; } *q = U'\0'; Melder_assert (q - thy string == thy length); return thee.transfer(); } catch (MelderError) { Melder_throw (me, U": not converted to WordList."); } }
bool WordList_hasWord (WordList me, const char32 *word) { long p, d; int cf; if (str32len (word) > 3333) return false; Longchar_genericize32 (word, buffer); if (! my length) my length = str32len (my string); p = my length / 2, d = p / 2; while (d > 20) { p = gotoStart (me, p); cf = compare (buffer, my string + p); if (cf == 0) return true; if (cf < 0) p -= d; else p += d; d /= 2; } p = gotoStart (me, p); cf = compare (buffer, my string + p); if (cf == 0) return true; if (cf > 0) { for (;;) { p = gotoNext (me, p); if (p >= my length) return false; cf = compare (buffer, my string + p); if (cf == 0) return true; if (cf < 0) return false; } } else { for (;;) { p = gotoPrevious (me, p); if (p < 0) return false; cf = compare (buffer, my string + p); if (cf == 0) return true; if (cf > 0) return false; } } return false; // should not occur }
const char32 * Melder_padOrTruncate (const char32 *string, int64 width) { if (++ iPadBuffer == NUMBER_OF_BUFFERS) iPadBuffer = 0; int64 length = str32len (string); int64 tooLong = length - width; if (tooLong == 0) return string; if (tooLong < 0) { int64 tooShort = - tooLong; MelderString_copy (& thePadBuffers [iPadBuffer], string); for (int64 i = 0; i < tooShort; i ++) MelderString_appendCharacter (& thePadBuffers [iPadBuffer], U' '); } else { MelderString_ncopy (& thePadBuffers [iPadBuffer], string, width); } return thePadBuffers [iPadBuffer]. string; }
double PairDistribution_Distributions_getFractionCorrect (PairDistribution me, Distributions dist, long column) { try { double correct = 0.0; long pairmin = 1; char32 string [1000]; Distributions_checkSpecifiedColumnNumberWithinRange (dist, column); autoPairDistribution thee = Data_copy (me); Collection_sort (thy pairs.get(), PairProbability_compare); double total = PairDistributions_getTotalWeight_checkPositive (thee.peek()); do { long pairmax = pairmin, length, ipair; double sum = 0.0, sumDist = 0.0; char32 *firstInput = ((PairProbability) thy pairs -> item [pairmin]) -> string1; for (ipair = pairmin + 1; ipair <= thy pairs -> size; ipair ++) { PairProbability prob = static_cast <PairProbability> (thy pairs -> item [ipair]); if (! str32equ (prob -> string1, firstInput)) { pairmax = ipair - 1; break; } } if (ipair > thy pairs -> size) pairmax = thy pairs -> size; for (ipair = pairmin; ipair <= pairmax; ipair ++) { PairProbability prob = static_cast <PairProbability> (thy pairs -> item [ipair]); double p = prob -> weight / total, pout = 0.0; Melder_sprint (string, 1000, prob -> string1, U" \\-> ", prob -> string2); for (long idist = 1; idist <= dist -> numberOfRows; idist ++) { if (str32equ (string, dist -> rowLabels [idist])) { pout = dist -> data [idist] [column]; break; } } sum += p * pout; } Melder_sprint (string, 1000, firstInput, U" \\-> "); length = str32len (string); for (long idist = 1; idist <= dist -> numberOfRows; idist ++) { if (str32nequ (string, dist -> rowLabels [idist], length)) { sumDist += dist -> data [idist] [column]; } } if (sumDist != 0.0) correct += sum / sumDist; pairmin = pairmax + 1; } while (pairmin <= thy pairs -> size); return correct; } catch (MelderError) { Melder_throw (me, U" & ", dist, U": could not compute our fraction correct."); } }
static void gui_button_cb_replace (CategoriesEditor me, GuiButtonEvent /* event */) { long posCount; autoNUMvector<long> posList (GuiList_getSelectedPositions (my list, & posCount), 1); if (posCount > 0) { autostring32 text = GuiText_getString (my text); if (str32len (text.peek()) != 0) { autoSimpleString str = SimpleString_create (text.peek()); autoCategoriesEditorReplace command = CategoriesEditorReplace_create (me, str.move(), posList.peek(), posCount); Command_do (command.peek()); if (my history) { CommandHistory_insertItem_move (my history.peek(), command.move()); } updateWidgets (me); } } }