mirror of
https://github.com/servo/servo.git
synced 2025-06-21 15:49:04 +01:00
style: Reformat a bunch of signatures in wrapper.rs
This commit is contained in:
parent
4e6fd5693a
commit
8a51a4eb01
1 changed files with 114 additions and 87 deletions
|
@ -187,7 +187,7 @@ impl<'ln> GeckoNode<'ln> {
|
||||||
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
|
/// WARNING: This logic is duplicated in Gecko's FlattenedTreeParentIsParent.
|
||||||
/// Make sure to mirror any modifications in both places.
|
/// Make sure to mirror any modifications in both places.
|
||||||
fn flattened_tree_parent_is_parent(&self) -> bool {
|
fn flattened_tree_parent_is_parent(&self) -> bool {
|
||||||
use ::gecko_bindings::structs::*;
|
use gecko_bindings::structs::*;
|
||||||
let flags = self.flags();
|
let flags = self.flags();
|
||||||
if flags & (NODE_MAY_BE_IN_BINDING_MNGR as u32 |
|
if flags & (NODE_MAY_BE_IN_BINDING_MNGR as u32 |
|
||||||
NODE_IS_IN_SHADOW_TREE as u32) != 0 {
|
NODE_IS_IN_SHADOW_TREE as u32) != 0 {
|
||||||
|
@ -448,12 +448,14 @@ impl<'le> fmt::Debug for GeckoElement<'le> {
|
||||||
|
|
||||||
impl<'le> GeckoElement<'le> {
|
impl<'le> GeckoElement<'le> {
|
||||||
/// Parse the style attribute of an element.
|
/// Parse the style attribute of an element.
|
||||||
pub fn parse_style_attribute<R>(value: &str,
|
pub fn parse_style_attribute<R>(
|
||||||
url_data: &UrlExtraData,
|
value: &str,
|
||||||
quirks_mode: QuirksMode,
|
url_data: &UrlExtraData,
|
||||||
reporter: &R)
|
quirks_mode: QuirksMode,
|
||||||
-> PropertyDeclarationBlock
|
reporter: &R,
|
||||||
where R: ParseErrorReporter
|
) -> PropertyDeclarationBlock
|
||||||
|
where
|
||||||
|
R: ParseErrorReporter,
|
||||||
{
|
{
|
||||||
parse_style_attribute(value, url_data, reporter, quirks_mode)
|
parse_style_attribute(value, url_data, reporter, quirks_mode)
|
||||||
}
|
}
|
||||||
|
@ -480,7 +482,7 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
/// Returns true if this element has descendants for lazy frame construction.
|
/// Returns true if this element has descendants for lazy frame construction.
|
||||||
pub fn descendants_need_frames(&self) -> bool {
|
pub fn descendants_need_frames(&self) -> bool {
|
||||||
self.flags() & (NODE_DESCENDANTS_NEED_FRAMES as u32) != 0
|
self.flags() & (NODE_DESCENDANTS_NEED_FRAMES as u32) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this element needs lazy frame construction.
|
/// Returns true if this element needs lazy frame construction.
|
||||||
|
@ -507,7 +509,8 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
/// Returns true if this element has a shadow root.
|
/// Returns true if this element has a shadow root.
|
||||||
fn has_shadow_root(&self) -> bool {
|
fn has_shadow_root(&self) -> bool {
|
||||||
self.get_extended_slots().map_or(false, |slots| !slots.mShadowRoot.mRawPtr.is_null())
|
self.get_extended_slots()
|
||||||
|
.map_or(false, |slots| !slots.mShadowRoot.mRawPtr.is_null())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the DOM slots for this Element, if they exist.
|
/// Returns a reference to the DOM slots for this Element, if they exist.
|
||||||
|
@ -517,10 +520,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the extended DOM slots for this Element.
|
/// Returns a reference to the extended DOM slots for this Element.
|
||||||
fn get_extended_slots(&self) -> Option<&structs::FragmentOrElement_nsExtendedDOMSlots> {
|
fn get_extended_slots(
|
||||||
self.get_dom_slots().and_then(|s| {
|
&self,
|
||||||
unsafe { s.mExtendedSlots.mPtr.as_ref() }
|
) -> Option<&structs::FragmentOrElement_nsExtendedDOMSlots> {
|
||||||
})
|
self.get_dom_slots()
|
||||||
|
.and_then(|s| unsafe { s.mExtendedSlots.mPtr.as_ref() })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -534,7 +538,8 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_xbl_binding_with_content(&self) -> Option<GeckoXBLBinding> {
|
fn get_xbl_binding_with_content(&self) -> Option<GeckoXBLBinding> {
|
||||||
self.get_xbl_binding().and_then(|b| b.get_binding_with_content())
|
self.get_xbl_binding()
|
||||||
|
.and_then(|b| b.get_binding_with_content())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -551,23 +556,23 @@ impl<'le> GeckoElement<'le> {
|
||||||
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
// FIXME(heycam): Having trouble with bindgen on nsXULElement,
|
||||||
// where the binding parent is stored in a member variable
|
// where the binding parent is stored in a member variable
|
||||||
// rather than in slots. So just get it through FFI for now.
|
// rather than in slots. So just get it through FFI for now.
|
||||||
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) }
|
unsafe {
|
||||||
|
bindings::Gecko_GetBindingParent(self.0).map(GeckoElement)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let binding_parent =
|
let binding_parent = unsafe {
|
||||||
unsafe { self.get_non_xul_xbl_binding_parent_raw_content().as_ref() }
|
self.get_non_xul_xbl_binding_parent_raw_content().as_ref()
|
||||||
.map(GeckoNode::from_content)
|
}.map(GeckoNode::from_content)
|
||||||
.and_then(|n| n.as_element());
|
.and_then(|n| n.as_element());
|
||||||
debug_assert!(binding_parent ==
|
debug_assert!(binding_parent == unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) });
|
||||||
unsafe { bindings::Gecko_GetBindingParent(self.0).map(GeckoElement) });
|
|
||||||
binding_parent
|
binding_parent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
fn get_non_xul_xbl_binding_parent_raw_content(&self) -> *mut nsIContent {
|
||||||
debug_assert!(!self.is_xul_element());
|
debug_assert!(!self.is_xul_element());
|
||||||
self.get_extended_slots().map_or(ptr::null_mut(), |slots| {
|
self.get_extended_slots()
|
||||||
slots.mBindingParent
|
.map_or(ptr::null_mut(), |slots| slots.mBindingParent)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_xbl_binding_parent(&self) -> bool {
|
fn has_xbl_binding_parent(&self) -> bool {
|
||||||
|
@ -639,7 +644,8 @@ impl<'le> GeckoElement<'le> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn may_have_class(&self) -> bool {
|
fn may_have_class(&self) -> bool {
|
||||||
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
|
self.as_node()
|
||||||
|
.get_bool_flag(nsINode_BooleanFlag::ElementMayHaveClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -655,15 +661,13 @@ impl<'le> GeckoElement<'le> {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe { bindings::Gecko_GetBeforeOrAfterPseudo(self.0, is_before).map(GeckoElement) }
|
||||||
bindings::Gecko_GetBeforeOrAfterPseudo(self.0, is_before)
|
|
||||||
.map(GeckoElement)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn may_have_style_attribute(&self) -> bool {
|
fn may_have_style_attribute(&self) -> bool {
|
||||||
self.as_node().get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
|
self.as_node()
|
||||||
|
.get_bool_flag(nsINode_BooleanFlag::ElementMayHaveStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -682,9 +686,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
/// This function is also called after display property changed for SMIL animation.
|
/// This function is also called after display property changed for SMIL animation.
|
||||||
///
|
///
|
||||||
/// Also this function schedules style flush.
|
/// Also this function schedules style flush.
|
||||||
unsafe fn maybe_restyle<'a>(&self,
|
unsafe fn maybe_restyle<'a>(
|
||||||
data: &'a mut ElementData,
|
&self,
|
||||||
animation_only: bool) -> bool {
|
data: &'a mut ElementData,
|
||||||
|
animation_only: bool,
|
||||||
|
) -> bool {
|
||||||
if !data.has_styles() {
|
if !data.has_styles() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -701,9 +707,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set restyle and change hints to the element data.
|
/// Set restyle and change hints to the element data.
|
||||||
pub fn note_explicit_hints(&self,
|
pub fn note_explicit_hints(
|
||||||
restyle_hint: nsRestyleHint,
|
&self,
|
||||||
change_hint: nsChangeHint) {
|
restyle_hint: nsRestyleHint,
|
||||||
|
change_hint: nsChangeHint,
|
||||||
|
) {
|
||||||
use gecko::restyle_damage::GeckoRestyleDamage;
|
use gecko::restyle_damage::GeckoRestyleDamage;
|
||||||
use invalidation::element::restyle_hints::RestyleHint;
|
use invalidation::element::restyle_hints::RestyleHint;
|
||||||
|
|
||||||
|
@ -721,7 +729,11 @@ impl<'le> GeckoElement<'le> {
|
||||||
self.maybe_restyle(d, restyle_hint.has_animation_hint())
|
self.maybe_restyle(d, restyle_hint.has_animation_hint())
|
||||||
});
|
});
|
||||||
if should_restyle {
|
if should_restyle {
|
||||||
maybe_data.as_mut().unwrap().hint.insert(restyle_hint.into());
|
maybe_data
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.hint
|
||||||
|
.insert(restyle_hint.into());
|
||||||
maybe_data.as_mut().unwrap().damage |= damage;
|
maybe_data.as_mut().unwrap().damage |= damage;
|
||||||
} else {
|
} else {
|
||||||
debug!("(Element not styled, discarding hints)");
|
debug!("(Element not styled, discarding hints)");
|
||||||
|
@ -787,9 +799,10 @@ fn selector_flags_to_node_flags(flags: ElementSelectorFlags) -> u32 {
|
||||||
gecko_flags
|
gecko_flags
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_animation_rule(element: &GeckoElement,
|
fn get_animation_rule(
|
||||||
cascade_level: CascadeLevel)
|
element: &GeckoElement,
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
cascade_level: CascadeLevel,
|
||||||
|
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
use gecko_bindings::sugar::ownership::HasSimpleFFI;
|
use gecko_bindings::sugar::ownership::HasSimpleFFI;
|
||||||
// Also, we should try to reuse the PDB, to avoid creating extra rule nodes.
|
// Also, we should try to reuse the PDB, to avoid creating extra rule nodes.
|
||||||
let mut animation_values = AnimationValueMap::default();
|
let mut animation_values = AnimationValueMap::default();
|
||||||
|
@ -837,23 +850,29 @@ impl FontMetricsProvider for GeckoFontMetricsProvider {
|
||||||
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
|
if let Some(sizes) = cache.iter().find(|el| el.0 == *font_name) {
|
||||||
return sizes.1.size_for_generic(font_family);
|
return sizes.1.size_for_generic(font_family);
|
||||||
}
|
}
|
||||||
let sizes = unsafe {
|
let sizes = unsafe { Gecko_GetBaseSize(font_name.as_ptr()) };
|
||||||
Gecko_GetBaseSize(font_name.as_ptr())
|
|
||||||
};
|
|
||||||
cache.push((font_name.clone(), sizes));
|
cache.push((font_name.clone(), sizes));
|
||||||
sizes.size_for_generic(font_family)
|
sizes.size_for_generic(font_family)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn query(&self, font: &Font, font_size: Au, wm: WritingMode,
|
fn query(
|
||||||
in_media_query: bool, device: &Device) -> FontMetricsQueryResult {
|
&self,
|
||||||
|
font: &Font,
|
||||||
|
font_size: Au,
|
||||||
|
wm: WritingMode,
|
||||||
|
in_media_query: bool,
|
||||||
|
device: &Device,
|
||||||
|
) -> FontMetricsQueryResult {
|
||||||
use gecko_bindings::bindings::Gecko_GetFontMetrics;
|
use gecko_bindings::bindings::Gecko_GetFontMetrics;
|
||||||
let gecko_metrics = unsafe {
|
let gecko_metrics = unsafe {
|
||||||
Gecko_GetFontMetrics(device.pres_context(),
|
Gecko_GetFontMetrics(
|
||||||
wm.is_vertical() && !wm.is_sideways(),
|
device.pres_context(),
|
||||||
font.gecko(),
|
wm.is_vertical() && !wm.is_sideways(),
|
||||||
font_size.0,
|
font.gecko(),
|
||||||
// we don't use the user font set in a media query
|
font_size.0,
|
||||||
!in_media_query)
|
// we don't use the user font set in a media query
|
||||||
|
!in_media_query,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let metrics = FontMetrics {
|
let metrics = FontMetrics {
|
||||||
x_height: Au(gecko_metrics.mXSize),
|
x_height: Au(gecko_metrics.mXSize),
|
||||||
|
@ -886,7 +905,9 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
if self.is_native_anonymous() {
|
if self.is_native_anonymous() {
|
||||||
self.closest_non_native_anonymous_ancestor()
|
self.closest_non_native_anonymous_ancestor()
|
||||||
} else {
|
} else {
|
||||||
self.as_node().flattened_tree_parent().and_then(|n| n.as_element())
|
self.as_node()
|
||||||
|
.flattened_tree_parent()
|
||||||
|
.and_then(|n| n.as_element())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,13 +1008,15 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_animation_rule(&self)
|
fn get_animation_rule(
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
&self,
|
||||||
|
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
get_animation_rule(self, CascadeLevel::Animations)
|
get_animation_rule(self, CascadeLevel::Animations)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_transition_rule(&self)
|
fn get_transition_rule(
|
||||||
-> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
&self,
|
||||||
|
) -> Option<Arc<Locked<PropertyDeclarationBlock>>> {
|
||||||
get_animation_rule(self, CascadeLevel::Transitions)
|
get_animation_rule(self, CascadeLevel::Transitions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,20 +1027,17 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool {
|
fn has_attr(&self, namespace: &Namespace, attr: &Atom) -> bool {
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::Gecko_HasAttr(self.0,
|
bindings::Gecko_HasAttr(self.0, namespace.0.as_ptr(), attr.as_ptr())
|
||||||
namespace.0.as_ptr(),
|
|
||||||
attr.as_ptr())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> Option<Atom> {
|
fn get_id(&self) -> Option<Atom> {
|
||||||
if !self.has_id() {
|
if !self.has_id() {
|
||||||
return None
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ptr = unsafe {
|
let ptr = unsafe {
|
||||||
bindings::Gecko_AtomAttrValue(self.0,
|
bindings::Gecko_AtomAttrValue(self.0, atom!("id").as_ptr())
|
||||||
atom!("id").as_ptr())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ptr.is_null() {
|
if ptr.is_null() {
|
||||||
|
@ -1028,11 +1048,10 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn each_class<F>(&self, callback: F)
|
fn each_class<F>(&self, callback: F)
|
||||||
where F: FnMut(&Atom)
|
where
|
||||||
|
F: FnMut(&Atom),
|
||||||
{
|
{
|
||||||
snapshot_helpers::each_class(self.0,
|
snapshot_helpers::each_class(self.0, callback, Gecko_ClassOrClassList)
|
||||||
callback,
|
|
||||||
Gecko_ClassOrClassList)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1299,8 +1318,9 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
.map(GeckoNode::from_content)
|
.map(GeckoNode::from_content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_css_transitions_info(&self)
|
fn get_css_transitions_info(
|
||||||
-> HashMap<TransitionProperty, Arc<AnimationValue>> {
|
&self,
|
||||||
|
) -> HashMap<TransitionProperty, Arc<AnimationValue>> {
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
use gecko_bindings::bindings::Gecko_ElementTransitions_EndValueAt;
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
use gecko_bindings::bindings::Gecko_ElementTransitions_Length;
|
||||||
use gecko_bindings::bindings::Gecko_ElementTransitions_PropertyAt;
|
use gecko_bindings::bindings::Gecko_ElementTransitions_PropertyAt;
|
||||||
|
@ -1320,9 +1340,11 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn might_need_transitions_update(&self,
|
fn might_need_transitions_update(
|
||||||
old_values: Option<&ComputedValues>,
|
&self,
|
||||||
new_values: &ComputedValues) -> bool {
|
old_values: Option<&ComputedValues>,
|
||||||
|
new_values: &ComputedValues,
|
||||||
|
) -> bool {
|
||||||
use properties::longhands::display::computed_value as display;
|
use properties::longhands::display::computed_value as display;
|
||||||
|
|
||||||
let old_values = match old_values {
|
let old_values = match old_values {
|
||||||
|
@ -1527,10 +1549,13 @@ impl<'le> Hash for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
|
impl<'le> PresentationalHintsSynthesizer for GeckoElement<'le> {
|
||||||
fn synthesize_presentational_hints_for_legacy_attributes<V>(&self,
|
fn synthesize_presentational_hints_for_legacy_attributes<V>(
|
||||||
visited_handling: VisitedHandlingMode,
|
&self,
|
||||||
hints: &mut V)
|
visited_handling: VisitedHandlingMode,
|
||||||
where V: Push<ApplicableDeclarationBlock>,
|
hints: &mut V
|
||||||
|
)
|
||||||
|
where
|
||||||
|
V: Push<ApplicableDeclarationBlock>,
|
||||||
{
|
{
|
||||||
use properties::longhands::_x_lang::SpecifiedValue as SpecifiedLang;
|
use properties::longhands::_x_lang::SpecifiedValue as SpecifiedLang;
|
||||||
use properties::longhands::_x_text_zoom::SpecifiedValue as SpecifiedZoom;
|
use properties::longhands::_x_text_zoom::SpecifiedValue as SpecifiedZoom;
|
||||||
|
@ -1826,13 +1851,15 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_non_ts_pseudo_class<F>(&self,
|
fn match_non_ts_pseudo_class<F>(
|
||||||
pseudo_class: &NonTSPseudoClass,
|
&self,
|
||||||
context: &mut LocalMatchingContext<Self::Impl>,
|
pseudo_class: &NonTSPseudoClass,
|
||||||
relevant_link: &RelevantLinkStatus,
|
context: &mut LocalMatchingContext<Self::Impl>,
|
||||||
flags_setter: &mut F)
|
relevant_link: &RelevantLinkStatus,
|
||||||
-> bool
|
flags_setter: &mut F,
|
||||||
where F: FnMut(&Self, ElementSelectorFlags),
|
) -> bool
|
||||||
|
where
|
||||||
|
F: FnMut(&Self, ElementSelectorFlags),
|
||||||
{
|
{
|
||||||
use selectors::matching::*;
|
use selectors::matching::*;
|
||||||
match *pseudo_class {
|
match *pseudo_class {
|
||||||
|
@ -1976,11 +2003,11 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_pseudo_element(&self,
|
fn match_pseudo_element(
|
||||||
pseudo_element: &PseudoElement,
|
&self,
|
||||||
_context: &mut MatchingContext)
|
pseudo_element: &PseudoElement,
|
||||||
-> bool
|
_context: &mut MatchingContext
|
||||||
{
|
) -> bool {
|
||||||
// TODO(emilio): I believe we could assert we are a pseudo-element and
|
// TODO(emilio): I believe we could assert we are a pseudo-element and
|
||||||
// match the proper pseudo-element, given how we rulehash the stuff
|
// match the proper pseudo-element, given how we rulehash the stuff
|
||||||
// based on the pseudo.
|
// based on the pseudo.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue