commit 9e2c8796a3761177a76200ee7029e34743316e37
Author: Juergen Spitzmueller <[email protected]>
Date: Fri Oct 10 11:49:28 2025 +0200
Bring InsetMathRef on par with InsetRef (#13179)
File format change.
---
development/FORMAT | 5 +
lib/lyx2lyx/lyx_2_6.py | 338 +++++++++++++++++++++++++++++++++-
src/frontends/qt/GuiRef.cpp | 13 +-
src/mathed/InsetMathCommand.cpp | 4 +-
src/mathed/InsetMathCommand.h | 2 +-
src/mathed/InsetMathRef.cpp | 389 +++++++++++++++++++++++++++++++---------
src/mathed/InsetMathRef.h | 4 +
src/mathed/MathFactory.cpp | 17 +-
src/mathed/MathParser.cpp | 11 +-
src/version.h | 4 +-
10 files changed, 680 insertions(+), 107 deletions(-)
diff --git a/development/FORMAT b/development/FORMAT
index 504628ea42..1900f2fce4 100644
--- a/development/FORMAT
+++ b/development/FORMAT
@@ -7,6 +7,11 @@ changes happened in particular if possible. A good example
would be
-----------------------
+2025-10-10 Jürgen Spitzmüller <[email protected]>
+ * Format incremented to 645: Support options and params
+ in InsetMathRef. Syntax:
+ \cmd[options]{labels}[features]
+
2025-10-05 Jürgen Spitzmüller <[email protected]>
* Format incremented to 644:
- Support formatted cross references for examples
diff --git a/lib/lyx2lyx/lyx_2_6.py b/lib/lyx2lyx/lyx_2_6.py
index 8f184b8ee4..cc94ab147f 100644
--- a/lib/lyx2lyx/lyx_2_6.py
+++ b/lib/lyx2lyx/lyx_2_6.py
@@ -237,17 +237,353 @@ def convert_refname(document):
i = j
+def revert_mathref(document):
+ "Revert advanced formatted refs to LaTeX"
+
+ package = "refstyle"
+ i = find_token(document.header, "\\crossref_package", 0)
+ if i == -1:
+ document.warning("Missing \\crossref_package header!")
+ else:
+ package = get_value(document.header, "\\crossref_package", i)
+
+ regexp =
re.compile(r"(.*\\)(ref|pageref|cpageref|vref|vpageref|formatted|prettyref|eqref|nameref|labelonly)(\[|\{)(.*)")
+ # \cmd[opt]{arg}[opt]
+ reg_opt1 =
re.compile(r"(.*\\)(ref|pageref|cpageref|vref|vpageref|formatted|prettyref|eqref|nameref|labelonly)(\[[^\]]+\])(\{[^\}]+\})(\[[^\]]+\])(.*)")
+ # \cmd[opt]{arg}
+ reg_opt2 =
re.compile(r"(.*\\)(ref|pageref|cpageref|vref|vpageref|formatted|prettyref|eqref|nameref|labelonly)(\[[^\]]\])(\{[^\}]+\})(.*)")
+ # \cmd{arg}[opt]
+ reg_opt3 =
re.compile(r"(.*\\)(ref|pageref|cpageref|vref|vpageref|formatted|prettyref|eqref|nameref|labelonly)(\{[^\}]+\})(\[[^\]]+\])(.*)")
+ need_zref_clever = False
+ need_zref_vario = False
+ need_cleveref = False
+ need_refstyle = False
+ need_varioref = False
+ i = 0
+ while True:
+ i = find_token(document.body, "\\begin_inset Formula", i)
+ if i == -1:
+ break
+ j = find_end_of_inset(document.body, i)
+ if j == -1:
+ document.warning("Can't find end of inset at line %d of body!" % i)
+ i += 1
+ continue
+ k = find_re(document.body, regexp, i, j)
+ if k == -1:
+ i = j
+ continue
+
+ pretext = ""
+ posttext = ""
+ cmd = ""
+ opt = ""
+ arg = ""
+ features = []
+ l = i
+ while True:
+ m = reg_opt1.match(document.body[k])
+ if m:
+ pretext = m.group(1)
+ cmd = m.group(2)
+ opt = m.group(3)
+ arg = m.group(4)
+ features = m.group(5)[1:-1].split(",")
+ posttext = m.group(6)
+ else:
+ m = reg_opt2.match(document.body[k])
+ if m:
+ pretext = m.group(1)
+ cmd = m.group(2)
+ opt = m.group(3)
+ arg = m.group(4)
+ posttext = m.group(5)
+ else:
+ m = reg_opt3.match(document.body[k])
+ if m:
+ pretext = m.group(1)
+ cmd = m.group(2)
+ arg = m.group(3)
+ features = m.group(4)[1:-1].split(",")
+ posttext = m.group(5)
+ else:
+ l += 1
+ k = find_re(document.body, regexp, l, j)
+ if k == -1 or l == j:
+ i = j
+ break
+
+ arguments = arg[1:-1].split(",")
+
+ use_nolink = "nolink" in features and find_token(document.header,
"\\use_hyperref true", 0) != -1
+
+ # labelonly
+ if cmd == "labelonly":
+ # strip prefixes if requested
+ if "noprefix" in features:
+ npargs = []
+ for argu in arguments:
+ if ":" in argu:
+ npargs.append(argu.split(":", 1)[1])
+ else:
+ npargs.append(argu)
+ arg = "{" + ",".join(npargs) + "}"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+
+ use_range = False
+ if len(arguments) == 2 and (cmd == "vref" or cmd == "vpageref")
and package != "zref":
+ use_range = True
+ elif len(arguments) != 2 or "range" not in features:
+ use_range = False
+ elif cmd == "vref" or cmd == "vpageref" or cmd == "cpageref" or
(cmd == "formatted" and "prettyref" not in package):
+ use_range = True
+
+ if cmd == "vref" or cmd == "vpageref":
+ if not use_range and "nolink" not in features and (package !=
"zref" or ("caps" not in features and opt == "")):
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ if package == "zref":
+ cmd = "z" + cmd
+ need_zref_vario = True
+ else:
+ need_varioref = True
+ if use_range:
+ cmd += "range"
+ if use_nolink:
+ cmd += "*"
+ realopt = []
+ if package == "zref":
+ realopt = opt[1:-1].split(",")
+ if "caps" in features:
+ realopt.append("S")
+ realopt = list(filter(None, realopt))
+ if len(realopt) > 0:
+ cmd += "[" + ",".join(realopt) + "]"
+ first = True
+ cmd += "{"
+ for argu in arguments:
+ if not first:
+ if use_range:
+ cmd += "}{"
+ else:
+ cmd += ","
+ first = False
+ cmd += argu
+ cmd += "}"
+ document.body[k] = pretext + cmd + posttext
+ continue
+
+ # cpageref
+ if cmd == "cpageref":
+ if package == "cleveref":
+ if not use_range and "caps" not in features:
+ # just remove the opts
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ need_cleveref = True
+ if "caps" in features:
+ cmd = cmd.title()
+ first = True
+ cmd += "{"
+ for argu in arguments:
+ if not first:
+ if use_range:
+ cmd += "}{"
+ else:
+ cmd += ","
+ first = False
+ cmd += argu
+ cmd += "}"
+ document.body[k] = pretext + cmd + posttext
+ continue
+ if package == "zref":
+ if not use_range and "caps" not in features and not
use_nolink:
+ # just remove the opts
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ need_zref_clever = True
+ cmd = "z" + cmd
+ if use_nolink:
+ cmd += "*"
+ realopt = opt[1:-1].split(",")
+ if "caps" in features:
+ realopt.append("S")
+ if use_range:
+ realopt.append("range")
+ realopt = list(filter(None, realopt))
+ if len(realopt) > 0:
+ cmd += "[" + ",".join(realopt) + "]"
+ first = True
+ cmd += "{"
+ for argu in arguments:
+ if not first:
+ if use_range:
+ cmd += "}{"
+ else:
+ cmd += ","
+ first = False
+ cmd += argu
+ cmd += "}"
+ document.body[k] = pretext + cmd + posttext
+ continue
+ else:
+ if "nolink" in features:
+ cmd = "pageref*"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+
+ if len(arguments) > 1 and package == "cleveref":
+ if cmd == "ref":
+ need_cleveref = True
+ document.body[k] = pretext + "labelcref" + arg + posttext
+ continue
+ if cmd == "pageref":
+ need_cleveref = True
+ document.body[k] = pretext + "labelcpageref" + arg +
posttext
+ continue
+
+ if len(arguments) > 1 and package == "zref":
+ if cmd == "ref" or cmd == "pageref":
+ need_zref_clever = True
+ cmd = "zcref"
+ if use_nolink:
+ cmd += "*"
+ realopt = opt[1:-1].split(",")
+ if "caps" in features:
+ realopt.append("noname")
+ if cmd == "pageref":
+ realopt.append("page")
+ realopt = list(filter(None, realopt))
+ if len(realopt) > 0:
+ cmd += "[" + ",".join(realopt) + "]"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+
+ # formatted
+ if cmd == "formatted":
+ # prettyref
+ if "prettyref" in package:
+ cmd = "prettyref"
+ # refstyle
+ if package == "refstyle":
+ if len(arguments) == 1 and not "plural" in features and
not "caps" in features:
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ need_refstyle = True
+ npargs = []
+ prfx = ""
+ for argu in arguments:
+ document.warning("argu: %s" % argu)
+ if ":" in argu:
+ npargs.append(argu.split(":", 1)[1])
+ if prfx == "":
+ prfx = argu.split(":", 1)[0]
+ else:
+ npargs.append(argu)
+ cmd = prfx + "ref"
+ if "caps" in features:
+ cmd = cmd.title()
+ if "plural" in features:
+ cmd += "[s]"
+ arg = "{" + ",".join(npargs) + "}"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ # cleveref
+ if package == "cleveref":
+ if len(arguments) == 1 and not "caps" in features:
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ need_cleveref = True
+ if "caps" in features:
+ cmd = "Cref"
+ else:
+ cmd = "cref"
+ if use_range:
+ cmd += "range"
+ if use_nolink:
+ cmd += "*"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ # zref
+ if package == "zref":
+ if len(arguments) == 1 and not "caps" in features:
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+ need_zref_clever = True
+ cmd = "zcref"
+ realopt = opt[1:-1].split(",")
+ if "caps" in features:
+ realopt.append("S")
+ if use_range:
+ realopt.append("range")
+ if use_nolink:
+ cmd += "*"
+ realopt = list(filter(None, realopt))
+ if len(realopt) > 0:
+ cmd += "[" + ",".join(realopt) + "]"
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+
+ # Rest (\ref, \eqref, \prettyref
+ if len(arguments) > 1:
+ cmds = []
+ first = True
+ for argu in arguments:
+ if first:
+ cmds.append(cmd + "{" + argu + "}")
+ first = False
+ else:
+ cmds.append("\\" + cmd + "{" + argu + "}")
+ cmd = ", ".join(cmds)
+ document.body[k] = pretext + cmd + posttext
+ continue
+ # remove the opts
+ document.body[k] = pretext + cmd + arg + posttext
+ continue
+
+ i = j
+
+ # preamble
+ if need_zref_clever:
+ add_to_preamble(
+ document,
+ ["\\usepackage{zref-clever}"]
+ )
+ if need_zref_vario:
+ add_to_preamble(
+ document,
+ ["\\usepackage{zref-vario}"]
+ )
+ if need_cleveref:
+ add_to_preamble(
+ document,
+ ["\\usepackage{cleveref}"]
+ )
+ if need_varioref:
+ add_to_preamble(
+ document,
+ ["\\usepackage{varioref}"]
+ )
+ if need_refstyle:
+ add_to_preamble(
+ document,
+ ["\\usepackage{refstyle}"]
+ )
+
##
# Conversion hub
#
supported_versions = ["2.6.0", "2.6"]
convert = [
- [644, [convert_refname]]
+ [644, [convert_refname]],
+ [645, []]
]
revert = [
+ [644, [revert_mathref]],
[643, [revert_ling_xrefs]]
]
diff --git a/src/frontends/qt/GuiRef.cpp b/src/frontends/qt/GuiRef.cpp
index 63b7332ce0..ffaa916470 100644
--- a/src/frontends/qt/GuiRef.cpp
+++ b/src/frontends/qt/GuiRef.cpp
@@ -176,18 +176,17 @@ void GuiRef::enableBoxes()
bool const allow_caps = use_refstyle || use_cleveref || use_zref;
bool const allow_nohyper = !isLabelOnly && (!isFormatted ||
use_cleveref || use_zref)
&& (reftype != "cpageref" || use_zref);
- bool const intext = bufferview()->cursor().inTexted();
- pluralCB->setEnabled(intext && isFormatted && allow_plural);
- capsCB->setEnabled(intext && (isFormatted || zref_clever || reftype ==
"cpageref")
+ pluralCB->setEnabled(isFormatted && allow_plural);
+ capsCB->setEnabled((isFormatted || zref_clever || reftype == "cpageref")
&& allow_caps);
- noprefixCB->setEnabled(intext && isLabelOnly);
+ noprefixCB->setEnabled(isLabelOnly);
// disabling of hyperlinks not supported by formatted references
- nolinkCB->setEnabled(hyper_on && intext && allow_nohyper);
+ nolinkCB->setEnabled(hyper_on && allow_nohyper);
// options only supported by zref currently
refOptionsLE->setEnabled(use_zref && (isFormatted || zref_clever));
refOptionsLA->setEnabled(use_zref && (isFormatted || zref_clever));
bool const allow_range_list_switch = selectedLV->topLevelItemCount() ==
2
- && (isFormatted || reftype == "cpageref") && !use_prettyref &&
intext;
+ && (isFormatted || reftype == "cpageref") && !use_prettyref;
if (reftype == "vref" || reftype == "vpageref")
rangeListCO->setCurrentIndex(rangeListCO->findData("range"));
rangeListCO->setEnabled(allow_range_list_switch);
@@ -572,8 +571,6 @@ void GuiRef::updateContents()
typeCO->clear();
- // FIXME Bring InsetMathRef on par with InsetRef
- // (see #11104)
bool const have_cpageref =
buffer().params().xref_package == "cleveref"
|| buffer().params().xref_package == "zref";
diff --git a/src/mathed/InsetMathCommand.cpp b/src/mathed/InsetMathCommand.cpp
index dcebf2d9a5..e1e7a2ff54 100644
--- a/src/mathed/InsetMathCommand.cpp
+++ b/src/mathed/InsetMathCommand.cpp
@@ -21,8 +21,8 @@ using namespace std;
namespace lyx {
-InsetMathCommand::InsetMathCommand(Buffer * buf, docstring const & name, bool
needs_math_mode)
- : InsetMathNest(buf, 2), name_(name), needs_math_mode_(needs_math_mode),
+InsetMathCommand::InsetMathCommand(Buffer * buf, docstring const & name, bool
needs_math_mode, idx_type ncells)
+ : InsetMathNest(buf, ncells), name_(name),
needs_math_mode_(needs_math_mode),
set_label_(false)
{
lock_ = true;
diff --git a/src/mathed/InsetMathCommand.h b/src/mathed/InsetMathCommand.h
index 2a0c0dfa25..b93de4390c 100644
--- a/src/mathed/InsetMathCommand.h
+++ b/src/mathed/InsetMathCommand.h
@@ -26,7 +26,7 @@ class InsetMathCommand : public InsetMathNest {
public:
///
explicit InsetMathCommand(Buffer * buf, docstring const & name,
- bool needs_math_mode = true);
+ bool needs_math_mode = true, idx_type ncells = 2);
///
marker_type marker(BufferView const *) const override { return
marker_type::NO_MARKER; }
///
diff --git a/src/mathed/InsetMathRef.cpp b/src/mathed/InsetMathRef.cpp
index edf10365ea..9d7a05a848 100644
--- a/src/mathed/InsetMathRef.cpp
+++ b/src/mathed/InsetMathRef.cpp
@@ -25,6 +25,8 @@
#include "MathStream.h"
#include "MathSupport.h"
#include "ParIterator.h"
+#include "PDFOptions.h"
+#include "frontends/alert.h"
#include "xml.h"
#include "insets/InsetCommand.h"
@@ -37,16 +39,17 @@
#include <ostream>
using namespace std;
+using namespace lyx::support;
namespace lyx {
InsetMathRef::InsetMathRef(Buffer * buf)
- : InsetMathCommand(buf, from_ascii("ref"), false)
+ : InsetMathCommand(buf, from_ascii("ref"), false, 3)
{}
InsetMathRef::InsetMathRef(Buffer * buf, docstring const & data)
- : InsetMathCommand(buf, data, false)
+ : InsetMathCommand(buf, data, false, 3)
{}
@@ -262,6 +265,18 @@ string const InsetMathRef::createDialogStr(string const &
type) const
InsetCommandParams icp(REF_CODE, (type.empty()
? to_ascii(commandname()) : type));
icp["reference"] = asString(cell(0));
+ if (!cell(1).empty())
+ icp["options"] = asString(cell(1));
+ if (hasFeature("plural"))
+ icp["plural"] = from_ascii("true");
+ if (hasFeature("caps"))
+ icp["caps"] = from_ascii("true");
+ if (hasFeature("noprefix"))
+ icp["noprefix"] = from_ascii("true");
+ if (hasFeature("nolink"))
+ icp["nolink"] = from_ascii("true");
+ if (hasFeature("range"))
+ icp["tuple"] = from_ascii("range");
return InsetCommand::params2string(icp);
}
@@ -272,10 +287,33 @@ docstring const InsetMathRef::getTarget() const
}
+bool InsetMathRef::hasFeature(string const & string) const
+{
+ vector<docstring> const features =
getVectorFromString(asString(cell(2)));
+ for (auto const & f : features) {
+ if (from_ascii(string) == f)
+ return true;
+ }
+ return false;
+}
+
+
void InsetMathRef::changeTarget(docstring const & target)
{
InsetCommandParams icp(REF_CODE, to_ascii(commandname()));
icp["reference"] = target;
+ if (!cell(1).empty())
+ icp["options"] = asString(cell(1));
+ if (hasFeature("plural"))
+ icp["plural"] = from_ascii("true");
+ if (hasFeature("caps"))
+ icp["caps"] = from_ascii("true");
+ if (hasFeature("noprefix"))
+ icp["noprefix"] = from_ascii("true");
+ if (hasFeature("nolink"))
+ icp["nolink"] = from_ascii("true");
+ if (hasFeature("range"))
+ icp["tuple"] = from_ascii("range");
MathData md(buffer_);
Buffer & buf = buffer();
if (createInsetMath_fromDialogStr(
@@ -287,6 +325,21 @@ void InsetMathRef::changeTarget(docstring const & target)
}
+bool InsetMathRef::useRange() const
+{
+ docstring const & cmd = commandname();
+ vector<docstring> const refs = getVectorFromString(asString(cell(0)));
+ if (refs.size() == 2 && (cmd == "vref" || cmd == "vpageref")
+ && buffer().masterParams().xref_package != "zref")
+ return true;
+ if (refs.size() != 2 || !hasFeature("range"))
+ return false;
+ return cmd == "vref" || cmd == "vpageref"
+ || (cmd == "formatted" &&
!prefixIs(buffer().masterParams().xref_package, "prettyref"))
+ || (cmd == "cpageref");
+}
+
+
void InsetMathRef::writeMath(TeXMathStream & os) const
{
docstring const & cmd = commandname();
@@ -295,112 +348,270 @@ void InsetMathRef::writeMath(TeXMathStream & os) const
LYXERR0("Unassigned buffer_ in InsetMathRef::write!");
LYXERR0("LaTeX output may be wrong!");
}
- // are we writing to the LyX file?
if (!os.latex()) {
- // if so, then this is easy
- InsetMathCommand::writeMath(os);
+ // we are writing to the LyX file
+ ModeSpecifier specifier(os, currentMode(), lockedMode(),
asciiOnly());
+ MathEnsurer ensurer(os, false);
+ os << '\\' << cmd;
+ if (!cell(1).empty())
+ os << '[' << cell(1) << ']';
+ os << '{' << cell(0) << '}';
+ if (!cell(2).empty())
+ os << '[' << cell(2) << ']';
return;
}
+ bool const use_prettyref =
+ prefixIs(buffer().masterParams().xref_package, "prettyref");
bool const use_refstyle =
buffer_ && buffer().params().xref_package == "refstyle";
- bool special_case = cmd == "formatted" ||
- cmd == "vref" ||
- cmd == "vpageref" ||
- cmd == "cpageref" ||
- cmd == "labelonly" ||
- (cmd == "eqref" && use_refstyle);
- // we need to translate 'formatted' to prettyref or refstyle-type
- // commands and just output the label with labelonly
+ bool const use_cleveref = buffer().masterParams().xref_package ==
"cleveref";
+ bool const use_zref = buffer().masterParams().xref_package == "zref";
+ vector<docstring> labels = getVectorFromString(asString(cell(0)));
+ int const nlabels = labels.size();
+ bool const use_nolink =
buffer().masterParams().pdfoptions().use_hyperref && hasFeature("nolink");
+ // we need to translate 'formatted' to the appropriate commands
+ // (depending on xref package) and just output the label with labelonly
// most of this is borrowed from InsetRef and should be kept in
// sync with that.
ModeSpecifier specifier(os, currentMode(), lockedMode(), asciiOnly());
MathEnsurer ensurer(os, false);
- if (!special_case) {
- os << from_ascii("\\") << cmd << "{" << cell(0) <<
from_ascii("}");
- }
- else if (cmd == "vref" || cmd == "vpageref") {
- os << from_ascii("\\");
- if (buffer_ && buffer().params().xref_package == "zref")
+ if (cmd == "vref" || cmd == "vpageref") {
+ os << "\\";
+ if (use_zref)
os << "z";
- os << cmd << "{" << cell(0) << from_ascii("}");
- }
- else if (cmd == "cpageref") {
- os << from_ascii("\\");
- if (buffer_ && buffer().params().xref_package == "zref")
- os << "z";
- if (buffer_ && (buffer().params().xref_package == "cleveref"
- || buffer().params().xref_package == "zref"))
- os << cmd;
+ os << cmd;
+ if (useRange())
+ os << "range";
+ if (use_nolink)
+ os << "*";
+ docstring opts = asString(cell(1));
+ if (use_zref && hasFeature("caps")) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "S";
+ }
+ if (use_zref && !opts.empty())
+ os << "[" << opts << "]";
+ bool first = true;
+ os << "{";
+ for (auto const & l : labels) {
+ if (!first) {
+ if (useRange())
+ os << "}{";
+ else
+ os << ",";
+ }
+ os << l;
+ first = false;
+ }
+ os << "}";
+ } else if (cmd == "cpageref" && use_cleveref) {
+ if (hasFeature("caps"))
+ os << "\\Cpageref";
else
- os << "pageref";
- os << "{" << cell(0) << from_ascii("}");
- }
- else if (use_refstyle && cmd == "eqref") {
+ os << "\\cpageref";
+ if (useRange())
+ os << "range";
+ bool first = true;
+ os << "{";
+ for (auto const & l : labels) {
+ if (!first) {
+ if (useRange())
+ os << "}{";
+ else
+ os << ",";
+ }
+ os << l;
+ first = false;
+ }
+ os << "}";
+ } else if (cmd == "cpageref" && use_zref) {
+ os << "\\zcpageref";
+ if (use_nolink)
+ os << "*";
+ docstring opts = asString(cell(1));
+ if (hasFeature("caps")) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "S";
+ }
+ if (useRange()) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "range";
+ }
+ if (!opts.empty())
+ os << "[" << opts << "]";
+ bool first = true;
+ os << "{";
+ for (auto const & l : labels) {
+ if (!first)
+ os << ",";
+ os << l;
+ first = false;
+ }
+ os << "}";
+ } else if (cmd == "cpageref") {
+ bool first = true;
+ for (auto const & label : labels) {
+ if (!first)
+ os << ", ";
+ os << "\\pageref";
+ if (use_nolink)
+ os << "*";
+ os << '{' << label << '}';
+ first = false;
+ }
+ } else if (nlabels > 1 && cmd == "ref" && use_cleveref) {
+ os << "\\labelcref" << '{' << cell(0) << '}';
+ } else if (nlabels > 1 && cmd == "pageref" && use_cleveref) {
+ os << "\\labelcpageref" << '{' << cell(0) << '}';
+ } else if (use_refstyle && cmd == "eqref") {
// we advertise this as printing "(n)", so we'll do that, at
least
// for refstyle, since refstlye's own \eqref prints, by default,
// "equation n". if one wants \eqref, one can get it by using a
// formatted label in this case.
- os << '(' << from_ascii("\\ref{") << cell(0) <<
from_ascii("})");
- }
- else if (cmd == "formatted") {
- if (buffer_ &&
support::prefixIs(buffer().params().xref_package, "prettyref"))
- os << "\\prettyref{" << cell(0) << "}";
- else {
- odocstringstream ods;
- // get the label we are referencing
- for (auto const & d : cell(0)) {
- ods << d;
+ os << '(' << from_ascii("\\ref");
+ if (use_nolink)
+ os << "*";
+ os << "{" << cell(0) << from_ascii("})");
+ } else if (cmd == "formatted") {
+ odocstringstream ods;
+ // get the label we are referencing
+ for (auto const & d : cell(0))
+ ods << d;
+ docstring const ref = ods.str();
+
+ vector<docstring> lbls;
+ docstring prefix;
+ docstring const fcmd =
+ InsetRef::getFormattedCmd(ref, lbls, prefix,
+
buffer().params().xref_package,
+ hasFeature("caps"),
useRange());
+ os << fcmd;
+ if (use_nolink && (use_cleveref || use_zref))
+ os << "*";
+ if (hasFeature("plural") && use_refstyle)
+ os << "[s]";
+ else if (use_zref) {
+ docstring opts = asString(cell(1));
+ if (hasFeature("caps")) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "S";
+ }
+ if (useRange()) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "range";
+ }
+ if (!opts.empty())
+ os << "[" << opts << "]";
+ }
+ bool first = true;
+ os << "{";
+ vector<docstring>::const_iterator it = lbls.begin();
+ vector<docstring>::const_iterator en = lbls.end();
+ for (size_t i = 0; it != en; ++it, ++i) {
+ if (!first) {
+ if (use_prettyref) {
+ os << "}";
+ if (lbls.size() == 2)
+ os << buffer().B_("[[reference
1]] and [[reference2]]");
+ else if (i > 0 && i == lbls.size() - 1)
+ os << buffer().B_("[[reference
1, ...]], and [[reference n]]");
+ else
+ os << buffer().B_("[[reference
1]], [[reference2, ...]]");
+ os << "\\ref{";
+ } else if (useRange() && !use_zref)
+ os << "}{";
+ else
+ os << ",";
+ }
+ if (::contains(*it, ' ') && !useRange() && use_refstyle
+ &&
buffer().masterParams().isRefStyleSupported(prefix))
+ // refstyle bug: labels with blanks need to be
grouped for known commands
+ // otherwise the blanks will be gobbled
+ os << "{" << *it << "}";
+ else {
+ if (use_prettyref && !::contains(*it, ':'))
+ // warn on invalid label
+ frontend::Alert::warning(_("Invalid
label!"),
+ bformat(_("The
label `%1$s' does not have a prefix (e.g., `sec:'), "
+
"which is needed for formatted references with prettyref.\n"
+ "You
will most likely run into a LaTeX error."),
+ *it),
true);
+ os << *it;
}
- docstring const ref = ods.str();
-
- /*
- At the moment, the 'plural', 'nolink' and 'caps'
options will
- not work here. Also ranges. The reason is that we
handle these as
- 'internal' LyX argumemts, but those are not handled by
- InsetCommandParams::getCommand, which is what is used
- in createInsetMath_fromDialogStr to interpret the data
- coming from the dialog.
- If this is fixed, then what follows will get the info
- we need.
- Fixing it, I think, would mean sub-classing
- InsetCommandParams to InsetRefParams, and the overriding
- getCommand.
- *******************************************************
- // reset
- ods.str(docstring());
- ods.clear();
- // get the options from the optional argument
- for (auto const & d : cell(1))
- ods << d;
- docstring const options = ods.str();
- bool const caps = support::contains(options, 'C');
- bool const plural = support::contains(options, 's');
- */
- vector<docstring> label;
+ first = false;
+ }
+ os << "}";
+ } else if (cmd == "labelonly") {
+ if (!hasFeature("noprefix"))
+ os << cell(0);
+ else {
docstring prefix;
- docstring const fcmd =
- InsetRef::getFormattedCmd(ref, label, prefix,
buffer().params().xref_package);
- os << fcmd;
- //if (plural)
- // os << "[s]";
- bool first = true;
- os << "{";
- for (auto const & l : label) {
- if (!first) {
-// if (useRange())
-// os << "}{";
-// else
- os << ",";
- }
- os << l;
- first = false;
+ vector <docstring> slrefs;
+ for (auto const & r : labels) {
+ docstring suffix = split(r, prefix, ':');
+ if (suffix.empty()) {
+ LYXERR0("Label `" << r << "' contains
no `:' separator.");
+ slrefs.push_back(r);
+ } else
+ slrefs.push_back(suffix);
}
- os << "}";
+ os << getStringFromVector(slrefs);
+ }
+ } else if (nlabels > 1 && cmd == "ref" && use_zref) {
+ os << "\\zcref";
+ if (use_nolink)
+ os << "*";
+ docstring opts = asString(cell(1));
+ if (hasFeature("caps")) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "noname";
+ }
+ if (use_zref && !opts.empty())
+ os << "[" << opts << "]";
+ os << '{' << cell(0) << '}';
+ } else if (nlabels > 1 && cmd == "pageref" && use_zref) {
+ os << "\\zcref";
+ if (use_nolink)
+ os << "*";
+ docstring opts = asString(cell(1));
+ if (hasFeature("caps")) {
+ if (!opts.empty())
+ opts +=", ";
+ opts += "noname, page";
+ }
+ if (!opts.empty())
+ os << "[" << opts << "]";
+ os << '{' << cell(0) << '}';
+ } else if (nlabels == 1) {
+ os << "\\" << cmd;
+ if (use_nolink)
+ os << "*";
+ os << "{" << cell(0) << "}";
+ } else {
+ bool first = true;
+ vector<docstring>::const_iterator it = labels.begin();
+ vector<docstring>::const_iterator en = labels.end();
+ for (size_t i = 0; it != en; ++it, ++i) {
+ if (!first) {
+ if (labels.size() == 2)
+ os << buffer().B_("[[reference 1]] and
[[reference2]]");
+ else if (i > 0 && i == labels.size() - 1)
+ os << buffer().B_("[[reference 1,
...]], and [[reference n]]");
+ else
+ os << buffer().B_("[[reference 1]],
[[reference2, ...]]");
+ }
+ os << "\\" << cmd;
+ if (use_nolink)
+ os << "*";
+ os << '{' << *it << '}';
+ first = false;
}
- }
- else if (cmd == "labelonly") {
- // noprefix does not work here, for reasons given above.
- os << cell(0);
}
}
diff --git a/src/mathed/InsetMathRef.h b/src/mathed/InsetMathRef.h
index 23e3e8fdff..8cd04ac208 100644
--- a/src/mathed/InsetMathRef.h
+++ b/src/mathed/InsetMathRef.h
@@ -78,6 +78,10 @@ protected:
///
bool getStatus(Cursor &, FuncRequest const &, FuncStatus &) const
override;
private:
+ ///
+ bool hasFeature(std::string const & string) const;
+ ///
+ bool useRange() const;
///
Inset * clone() const override;
};
diff --git a/src/mathed/MathFactory.cpp b/src/mathed/MathFactory.cpp
index 1f37fd849e..5c24158f38 100644
--- a/src/mathed/MathFactory.cpp
+++ b/src/mathed/MathFactory.cpp
@@ -863,7 +863,22 @@ bool createInsetMath_fromDialogStr(docstring const & str,
MathData & md)
InsetCommand::string2params(to_utf8(str), icp);
Encoding const * const utf8 = encodings.fromLyXName("utf8");
OutputParams op(utf8);
- mathed_parse_cell(md, icp.getCommand(op, false, true));
+ odocstringstream ods;
+ ods << icp.getCommand(op, false, true);
+ vector<docstring> features;
+ if (icp["plural"] == from_ascii("true"))
+ features.push_back(from_ascii("plural"));
+ if (icp["caps"] == from_ascii("true"))
+ features.push_back(from_ascii("caps"));
+ if (icp["noprefix"] == from_ascii("true"))
+ features.push_back(from_ascii("noprefix"));
+ if (icp["nolink"] == from_ascii("true"))
+ features.push_back(from_ascii("nolink"));
+ if (icp["tuple"] != from_ascii("list"))
+ features.push_back(from_ascii("range"));
+ if (!features.empty())
+ ods << "[" << getStringFromVector(features) << "]";
+ mathed_parse_cell(md, ods.str());
} else if (name == "mathspace") {
InsetSpaceParams isp(true);
InsetSpace::string2params(to_utf8(str), isp);
diff --git a/src/mathed/MathParser.cpp b/src/mathed/MathParser.cpp
index 24ccae6957..99ee7d5d6a 100644
--- a/src/mathed/MathParser.cpp
+++ b/src/mathed/MathParser.cpp
@@ -1574,11 +1574,16 @@ bool Parser::parse1(InsetMathGrid & grid, unsigned
flags,
|| t.cs() == "vpageref" || t.cs() == "vref"
|| t.cs() == "formatted" || t.cs() == "labelonly") {
cell->emplace_back(new InsetMathRef(buf, t.cs()));
- docstring const opt = parse_verbatim_option();
+ docstring const opt1 = parse_verbatim_option();
docstring const ref = parse_verbatim_item();
- if (!opt.empty()) {
+ docstring const opt2 = parse_verbatim_option();
+ if (!opt1.empty()) {
cell->back().nucleus()->cell(1).push_back(
- MathAtom(new InsetMathString(buf,
opt)));
+ MathAtom(new InsetMathString(buf,
opt1)));
+ }
+ if (!opt2.empty()) {
+ cell->back().nucleus()->cell(2).push_back(
+ MathAtom(new InsetMathString(buf,
opt2)));
}
cell->back().nucleus()->cell(0).push_back(
MathAtom(new InsetMathString(buf,
ref)));
diff --git a/src/version.h b/src/version.h
index 9bb07d31ba..0f833454ad 100644
--- a/src/version.h
+++ b/src/version.h
@@ -32,8 +32,8 @@ extern char const * const lyx_version_info;
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
-#define LYX_FORMAT_LYX 644 // spitz: linguistics xrefs
-#define LYX_FORMAT_TEX2LYX 644
+#define LYX_FORMAT_LYX 645 // spitz: math ref features
+#define LYX_FORMAT_TEX2LYX 645
#if LYX_FORMAT_TEX2LYX != LYX_FORMAT_LYX
#ifndef _MSC_VER
--
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs