Skip to content

Commit 1159ccd

Browse files
eyalmazuzripose-jp
authored andcommitted
src/anki/notebuilder: allow filtering only lowest frequency
This feature extends the ``{frequencies}`` marker with the extended marker syntax and adds two new options: ``min-value`` which allows to export only the lowest value frequency out of all the options and ``value-only`` which strips the dictionary name and html list format to keep only raw numbers. This allow memento to support card format that rely on raw frequency values to sort their cards.
1 parent f67347a commit 1159ccd

File tree

2 files changed

+164
-8
lines changed

2 files changed

+164
-8
lines changed

src/anki/notebuilder.cpp

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,53 @@ static bool createScreenshotHelper(
420420
return true;
421421
}
422422

423+
/**
424+
* Parses the frequency string into a double.
425+
* @param frequency The string representation of the current frequency.
426+
* @return Float value of the frequency, nullopt if it could not be parsed.
427+
*/
428+
[[nodiscard]]
429+
static std::optional<double> parseFrequencyValue(const QString &frequency)
430+
{
431+
const QRegularExpression FLOAT_ONLY_REGEX(
432+
"^[+-]?([0-9]+([.][0-9]*)?|[.][0-9]+)"
433+
);
434+
435+
QRegularExpressionMatch numberMatch = FLOAT_ONLY_REGEX.match(frequency);
436+
if (!numberMatch.hasMatch())
437+
{
438+
if (frequency == "")
439+
{
440+
return 20.0;
441+
}
442+
else if (frequency == "★★")
443+
{
444+
return 40.0;
445+
}
446+
else if (frequency == "★★★")
447+
{
448+
return 60.0;
449+
}
450+
else if (frequency == "★★★★")
451+
{
452+
return 80.0;
453+
}
454+
else if (frequency == "★★★★★")
455+
{
456+
return 100.0;
457+
}
458+
return {};
459+
}
460+
461+
bool ok = false;
462+
double frequencyValue = numberMatch.captured().toDouble(&ok);
463+
if (!ok)
464+
{
465+
return {};
466+
}
467+
return frequencyValue;
468+
}
469+
423470
/* End Helper Functions */
424471
/* Begin Marker Functions */
425472

@@ -486,27 +533,92 @@ static QString getFuriganaPlain(const Term &term)
486533
/**
487534
* Builds the HTML string for the frequencies marker.
488535
* @param frequencies The frequencies to use.
536+
* @param args Extended marker syntax args.
489537
* @return The string for the {frequency} marker.
490538
*/
491539
[[nodiscard]]
492-
static QString buildFrequencies(const QList<Frequency> &frequencies)
540+
static QString buildFrequencies(
541+
const QList<Frequency> &frequencies,
542+
const QHash<QString, QString> &args)
493543
{
494544
if (frequencies.isEmpty())
495545
{
496546
return "";
497547
}
498548

549+
constexpr const char *VALUE_ONLY_KEY = "value-only";
550+
constexpr const char *MIN_VALUE_KEY = "min-value";
551+
constexpr const double MIN_VALUE_DEFAULT = 9999999.0;
552+
553+
bool valueOnly = false;
554+
bool minValueOnly = false;
555+
556+
QString minFreqDictionary;
557+
double minFreq = MIN_VALUE_DEFAULT;
558+
QString minFreqStr;
559+
560+
if (args.contains(VALUE_ONLY_KEY))
561+
{
562+
valueOnly = QVariant(args[VALUE_ONLY_KEY]).toBool();
563+
}
564+
if (args.contains(MIN_VALUE_KEY))
565+
{
566+
minValueOnly = QVariant(args[MIN_VALUE_KEY]).toBool();
567+
}
568+
499569
QString freqStr;
500-
freqStr += "<ul>";
570+
if (!valueOnly)
571+
{
572+
freqStr += "<ul>";
573+
}
501574
for (const Frequency &freq : frequencies)
502575
{
503-
freqStr += "<li>";
504-
freqStr += freq.dictionary;
505-
freqStr += freq.dictionary.endsWith(':') ? " " : ": ";
576+
if (!valueOnly)
577+
{
578+
freqStr += "<li>";
579+
freqStr += freq.dictionary;
580+
freqStr += freq.dictionary.endsWith(':') ? " " : ": ";
581+
}
506582
freqStr += freq.freq;
507-
freqStr += "</li>";
583+
if (valueOnly)
584+
{
585+
freqStr += "<br>";
586+
}
587+
else
588+
{
589+
freqStr += "</li>";
590+
}
591+
592+
std::optional<double> freqValue = parseFrequencyValue(freq.freq);
593+
if (minValueOnly && freqValue && *freqValue < minFreq)
594+
{
595+
minFreq = *freqValue;
596+
minFreqStr = freq.freq;
597+
minFreqDictionary = freq.dictionary;
598+
minFreqDictionary += freq.dictionary.endsWith(':') ? " " : ": ";
599+
}
600+
}
601+
if (!valueOnly)
602+
{
603+
freqStr += "</ul>";
604+
}
605+
606+
if (minValueOnly)
607+
{
608+
if (!valueOnly)
609+
{
610+
freqStr = "<ul>";
611+
freqStr += "<li>";
612+
freqStr += minFreqDictionary;
613+
freqStr += minFreqStr;
614+
freqStr += "</li>";
615+
freqStr += "</ul>";
616+
}
617+
else
618+
{
619+
freqStr = std::move(minFreqStr);
620+
}
508621
}
509-
freqStr += "</ul>";
510622

511623
if (freqStr == "<ul></ul>")
512624
{
@@ -1534,7 +1646,7 @@ static MarkerResult processMarkerCommon(
15341646
}
15351647
else if (marker.marker == Anki::Marker::FREQUENCIES)
15361648
{
1537-
result.text = buildFrequencies(exp.frequencies);
1649+
result.text = buildFrequencies(exp.frequencies, marker.args);
15381650
return result;
15391651
}
15401652
else if (marker.marker == Anki::Marker::FREQ_HARMONIC_RANK)

src/gui/widgets/settings/ankisettingshelp.ui

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,50 @@ These will expand to larger expressions in the final card.</string>
17251725
</property>
17261726
</widget>
17271727
</item>
1728+
<item row="6" column="0" alignment="Qt::AlignmentFlag::AlignHCenter">
1729+
<widget class="QLabel" name="labelExtendedFrequencyMinValue">
1730+
<property name="font">
1731+
<font>
1732+
<bold>true</bold>
1733+
</font>
1734+
</property>
1735+
<property name="text">
1736+
<string>min-value</string>
1737+
</property>
1738+
<property name="textInteractionFlags">
1739+
<set>Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse</set>
1740+
</property>
1741+
</widget>
1742+
</item>
1743+
<item row="6" column="1">
1744+
<widget class="QLabel" name="labelExtendedFrequencyMinValueEx">
1745+
<property name="text">
1746+
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Only export the lowest value frequency. Applies to marker &lt;span style=&quot; font-weight:700;&quot;&gt;{frequencies}&lt;/span&gt;. Default value: false.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1747+
</property>
1748+
</widget>
1749+
</item>
1750+
<item row="7" column="0" alignment="Qt::AlignmentFlag::AlignHCenter">
1751+
<widget class="QLabel" name="labelExtendedFrequencyValueOnly">
1752+
<property name="font">
1753+
<font>
1754+
<bold>true</bold>
1755+
</font>
1756+
</property>
1757+
<property name="text">
1758+
<string>value-only</string>
1759+
</property>
1760+
<property name="textInteractionFlags">
1761+
<set>Qt::TextInteractionFlag::TextSelectableByKeyboard|Qt::TextInteractionFlag::TextSelectableByMouse</set>
1762+
</property>
1763+
</widget>
1764+
</item>
1765+
<item row="7" column="1">
1766+
<widget class="QLabel" name="labelExtendedFrequencyValueOnlyEx">
1767+
<property name="text">
1768+
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Export frequency values without the dictionary names. Applies to marker &lt;span style=&quot; font-weight:700;&quot;&gt;{frequencies}&lt;/span&gt;. Default value: false.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
1769+
</property>
1770+
</widget>
1771+
</item>
17281772
</layout>
17291773
</widget>
17301774
</widget>

0 commit comments

Comments
 (0)