MUSX Document Model
Loading...
Searching...
No Matches
EnigmaString.h
1/*
2 * Copyright (C) 2025, Robert Patterson
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22#pragma once
23
24#include <cassert>
25#include <string>
26#include <string_view>
27#include <vector>
28#include <functional>
29#include <memory>
30#include <unordered_set>
31
32#include "musx/dom/Fundamentals.h"
33#include "musx/dom/MusxInstance.h"
34
35namespace musx {
36
37namespace dom {
38class FontInfo;
39class Document;
40class TextsBase;
41
42namespace options {
44}
45
46} // namespace dom
47
48namespace util {
49
53{
61 {
62 None,
63 MusicFont,
64 TextFont,
66 };
67
69 EnigmaStyles(const std::weak_ptr<dom::Document>& document);
70
73
74 std::shared_ptr<dom::FontInfo> font;
78 int tracking{};
79};
80
83{
84 std::string text;
86};
87
89
157{
158public:
160 template <typename CharT>
161 static std::string fromU8(const CharT* s)
162 {
163 static_assert(std::is_same<CharT, char>::value || std::is_same<CharT, decltype(u8'a')>::value,
164 "fromU8() only accepts char or char8_t pointers");
165 return std::string(reinterpret_cast<const char*>(s));
166 }
167
169 static std::string toU8(char32_t cp);
170
172 static std::string toU8(const std::u32string& value);
173
180 {
187
195 };
196
203 {
215 Ascii,
216
228 Unicode,
229
241 Smufl
242 };
243
296
298 static bool startsWithFontCommand(const std::string& text);
299
301 static bool startsWithStyleCommand(const std::string& text);
302
304 static std::optional<dom::options::AccidentalInsertSymbolType> commandIsAccidentalType(std::string_view commandText);
305
326 static std::vector<std::string> parseComponents(const std::string& input, size_t* parsedLength = nullptr);
327
332 using TextChunkCallback = std::function<bool(
333 const std::string& text,
334 const EnigmaStyles& styles
335 )>;
336
346 using TextInsertCallback = std::function<std::optional<std::string>(
347 const std::vector<std::string>& parsedCommand
348 )>;
349
351 static inline TextInsertCallback defaultInsertsCallback = [](const std::vector<std::string>&) { return std::nullopt; };
352
378 static bool parseEnigmaText(const std::shared_ptr<dom::Document>& document, dom::Cmper forPartId, const std::string& rawText,
379 const TextChunkCallback& onText, const TextInsertCallback& onInsert,
380 const EnigmaParsingOptions& options = {}, const EnigmaParsingContext* parsingContext = nullptr)
381 {
382 return parseEnigmaTextImpl(document, forPartId, rawText, onText, onInsert, options, parsingContext, EnigmaStyles(document));
383 }
384
394 static bool parseEnigmaText(const std::shared_ptr<dom::Document>& document, dom::Cmper forPartId, const std::string& rawText, const TextChunkCallback& onText,
395 const EnigmaParsingOptions& options = {}, const EnigmaParsingContext* parsingContext = nullptr)
396 {
397 return parseEnigmaTextImpl(document, forPartId, rawText, onText, defaultInsertsCallback, options, parsingContext, EnigmaStyles(document));
398 }
399
408 static bool parseStyleCommand(std::vector<std::string> components, EnigmaStyles& styles);
409
411 static std::string trimTags(const std::string& input);
412
414 static std::string plainTextFromChunks(const std::vector<EnigmaTextChunk>& chunks);
415
416private:
417 static bool parseEnigmaTextImpl(const std::shared_ptr<dom::Document>& document, dom::Cmper forPartId, const std::string& rawText,
418 const TextChunkCallback& onText, const TextInsertCallback& onInsert,
419 const EnigmaParsingOptions& options, const EnigmaParsingContext* parsingContext,
420 const EnigmaStyles& startingStyles);
421};
422
430{
431private:
433 dom::Cmper m_forPartId;
434 std::optional<int> m_forPageNumber;
436
437public:
440 : m_rawText(nullptr), m_forPartId(dom::SCORE_PARTID), m_insertFunc(EnigmaString::defaultInsertsCallback)
441 {}
442
449 std::optional<dom::Cmper> forPageId = std::nullopt,
451 : m_rawText(std::move(rawText)), m_forPartId(forPartId), m_forPageNumber(forPageId), m_insertFunc(insertFunc)
452 {}
453
455 explicit operator bool() const noexcept
456 { return static_cast<bool>(m_rawText); }
457
458 std::string affixText;
460
466 std::string getText(bool trimTags = false,
468 const std::unordered_set<std::string_view>& ignoreTags = {}) const;
469
477 const EnigmaString::TextInsertCallback& onInsert,
478 const EnigmaString::EnigmaParsingOptions& options = {}) const;
479
485 const EnigmaString::EnigmaParsingOptions& options = {}) const
486 {
488 }
489
494 std::vector<EnigmaTextChunk> collectEnigmaTextChunks(
495 const EnigmaString::TextInsertCallback& onInsert,
496 const EnigmaString::EnigmaParsingOptions& options = {}) const;
497
501 std::vector<EnigmaTextChunk> collectEnigmaTextChunks(
502 const EnigmaString::EnigmaParsingOptions& options = {}) const;
503
508 dom::MusxInstance<dom::FontInfo> parseFirstFontInfo() const;
509
511 dom::MusxInstance<dom::TextsBase> getRawText() const { return m_rawText; }
512
513 // If there is ever a need for a non-const version of the pointer, we can always
514 // look it up again.
515
517 dom::Cmper getRequestedPartId() const { return m_forPartId; }
518
520 std::optional<int> getPageNumber() const { return m_forPageNumber; }
521};
522
523} // namespace util
524} // namespace musx
Wrapper class for interpreting and rendering Enigma-style strings with insert handling.
Definition EnigmaString.h:430
bool affixIsPrefix
True if affixText is a prefix; false if it is a suffix.
Definition EnigmaString.h:459
std::string getText(bool trimTags=false, EnigmaString::AccidentalStyle accidentalStyle=EnigmaString::AccidentalStyle::Ascii, const std::unordered_set< std::string_view > &ignoreTags={}) const
Return displayable text with Enigma tags converted.
Definition EnigmaString.cpp:653
dom::MusxInstance< dom::FontInfo > parseFirstFontInfo() const
Returns a shared pointer to a FontInfo instance that reflects the first font information in the text.
Definition EnigmaString.cpp:667
bool parseEnigmaText(const EnigmaString::TextChunkCallback &onText, const EnigmaString::EnigmaParsingOptions &options={}) const
Parse the Enigma text into structured chunks with insert handling.
Definition EnigmaString.h:484
dom::Cmper getRequestedPartId() const
Get the requested part id.
Definition EnigmaString.h:517
std::optional< int > getPageNumber() const
Get the page number that was supplied, if any.
Definition EnigmaString.h:520
dom::MusxInstance< dom::TextsBase > getRawText() const
Get the raw text pointer.
Definition EnigmaString.h:511
std::vector< EnigmaTextChunk > collectEnigmaTextChunks(const EnigmaString::TextInsertCallback &onInsert, const EnigmaString::EnigmaParsingOptions &options={}) const
Collect the Enigma text into styled chunks with insert handling.
Definition EnigmaString.cpp:635
EnigmaParsingContext(dom::MusxInstance< dom::TextsBase > rawText, dom::Cmper forPartId, std::optional< dom::Cmper > forPageId=std::nullopt, EnigmaString::TextInsertCallback insertFunc=EnigmaString::defaultInsertsCallback)
Constructor.
Definition EnigmaString.h:448
bool parseEnigmaText(const EnigmaString::TextChunkCallback &onText, const EnigmaString::TextInsertCallback &onInsert, const EnigmaString::EnigmaParsingOptions &options={}) const
Parse the Enigma text into structured chunks with insert handling.
Definition EnigmaString.cpp:612
EnigmaParsingContext()
Null constructor.
Definition EnigmaString.h:439
std::string affixText
Prefix or suffix to be passed in parsing options.
Definition EnigmaString.h:458
Static class that provides utilities to extract information from enigma strings. Enigma strings use t...
Definition EnigmaString.h:157
static std::string trimTags(const std::string &input)
Trims all enigma tags from an enigma string, leaving just the plain text.
Definition EnigmaString.cpp:568
static std::string fromU8(const CharT *s)
Convert u8"" literals to std::string in a way that works both in C++17 and C++20+.
Definition EnigmaString.h:161
static std::optional< dom::options::AccidentalInsertSymbolType > commandIsAccidentalType(std::string_view commandText)
Returns the accidental insert symbol type if the input command is an accidental insert.
Definition EnigmaString.cpp:284
static bool startsWithStyleCommand(const std::string &text)
Returns true if the enigma string starts with a style insert.
Definition EnigmaString.cpp:152
static bool parseStyleCommand(std::vector< std::string > components, EnigmaStyles &styles)
Incorporates an enigma font insert into the supplied dom::FontInfo instance.
Definition EnigmaString.cpp:230
static bool startsWithFontCommand(const std::string &text)
Returns true if the enigma string starts with a font insert.
Definition EnigmaString.cpp:140
AccidentalStyle
Enumeration to specify the type of accidental substitution representation.
Definition EnigmaString.h:203
@ Smufl
Use SMuFL notation-specific accidentals.
@ Ascii
Use ASCII substitutions for accidentals.
@ Unicode
Use Unicode text accidentals.
static std::string toU8(char32_t cp)
Converts a 32-bit codepoint to a utf8-encoded std::string.
Definition EnigmaString.cpp:106
static bool parseEnigmaText(const std::shared_ptr< dom::Document > &document, dom::Cmper forPartId, const std::string &rawText, const TextChunkCallback &onText, const TextInsertCallback &onInsert, const EnigmaParsingOptions &options={}, const EnigmaParsingContext *parsingContext=nullptr)
Parses an Enigma-formatted string, handling font inserts and escaped carets.
Definition EnigmaString.h:378
static TextInsertCallback defaultInsertsCallback
Inserts callback to take all default insert subsitutions determined by parseEnigmaText.
Definition EnigmaString.h:351
AccidentalInsertHandling
Enumeration to specify the default handling for accidental insert commands. Like all Enigma commands,...
Definition EnigmaString.h:180
@ ParseToGlyphs
Parse accidental insert commands into glyph font changes and character strings.
@ Substitute
Substitute accidental insert commands with textual representations.
std::function< bool(const std::string &text, const EnigmaStyles &styles)> TextChunkCallback
Iteration function type that the parser calls back when the font has changed or when recursively pars...
Definition EnigmaString.h:335
static std::string plainTextFromChunks(const std::vector< EnigmaTextChunk > &chunks)
Concatenate the plain text from collected Enigma text chunks.
Definition EnigmaString.cpp:603
static bool parseEnigmaText(const std::shared_ptr< dom::Document > &document, dom::Cmper forPartId, const std::string &rawText, const TextChunkCallback &onText, const EnigmaParsingOptions &options={}, const EnigmaParsingContext *parsingContext=nullptr)
Simplified version of parseEnigmaText that strips unhandled inserts. Useful in particular when the ca...
Definition EnigmaString.h:394
static std::vector< std::string > parseComponents(const std::string &input, size_t *parsedLength=nullptr)
Parses an enigma text insert into its constituent components.
Definition EnigmaString.cpp:166
std::function< std::optional< std::string >(const std::vector< std::string > &parsedCommand)> TextInsertCallback
Iteration function type that the parser calls back when it encounters an Enigma text insert that requ...
Definition EnigmaString.h:348
AccidentalInsertSymbolType
Insert symbol types for accidentals.
Definition Options.h:1472
std::shared_ptr< const T > MusxInstance
Defines the type of a musx instance stored in a pool.
Definition MusxInstance.h:40
int32_t Evpu
EVPU value (288 per inch)
Definition Fundamentals.h:59
uint16_t Cmper
Enigma "comperator" key type.
Definition Fundamentals.h:57
object model for musx file (enigmaxml)
Definition BaseClasses.h:38
Options for configuring how Enigma strings are parsed.
Definition EnigmaString.h:251
bool ignoreStyleTags
If value is true, font & style tags are ignored. Note that you may still get get font and style chang...
Definition EnigmaString.h:287
EnigmaParsingOptions()
constructor
Definition EnigmaString.h:253
EnigmaParsingOptions(AccidentalStyle accidentalStyle)
constructor for accidental substitution
Definition EnigmaString.h:258
AccidentalStyle substitutionStyle
Specifies the accidental substitution style used when insertHandling is Substitute.
Definition EnigmaString.h:276
std::unordered_set< std::string_view > ignoreTags
Skip tags in this set. Primarily used by the "partname" insert to avoid a situation where the partnam...
Definition EnigmaString.h:294
AccidentalInsertHandling insertHandling
Specifies how accidental insert commands are handled during parsing.
Definition EnigmaString.h:268
bool stripUnknownTags
Specifies whether to strip unknown tags or dump them into the output string.
Definition EnigmaString.h:281
Text styles for enigma strings.
Definition EnigmaString.h:53
std::shared_ptr< dom::FontInfo > font
the font to use
Definition EnigmaString.h:74
CategoryTracking
Specifies is the current enigma style tracks an expressions marking category font....
Definition EnigmaString.h:61
@ NumberFont
tracks the category's number font (not implemented in Finale U.I.)
@ TextFont
tracks the category's text font
@ MusicFont
tracks the category's music font
int tracking
inter-character tracking in EMs (1/1000 font size)
Definition EnigmaString.h:78
EnigmaStyles createDeepCopy() const
Creates a deep copy of the styles, including copying any shared pointer instances.
Definition EnigmaString.cpp:99
dom::Evpu superscript
superscript setting added to baseline (positive means up)
Definition EnigmaString.h:77
dom::Evpu baseline
baseline setting (positive means up)
Definition EnigmaString.h:76
CategoryTracking categoryFont
how this font is tracked against a marking category
Definition EnigmaString.h:75
A text chunk with the Enigma styles active for that chunk.
Definition EnigmaString.h:83
std::string text
the chunk of text
Definition EnigmaString.h:84
EnigmaStyles styles
the styles active for the chunk
Definition EnigmaString.h:85