mirror of
https://github.com/joshuadavidthomas/django-language-server.git
synced 2025-09-15 06:45:23 +00:00
rename
This commit is contained in:
parent
de296ceff4
commit
0b8ca4061c
14 changed files with 321 additions and 370 deletions
|
@ -36,7 +36,7 @@ impl Ast {
|
||||||
pub enum Node {
|
pub enum Node {
|
||||||
Text(String),
|
Text(String),
|
||||||
Comment(String),
|
Comment(String),
|
||||||
Tag(TagNode),
|
Block(BlockNode),
|
||||||
Variable {
|
Variable {
|
||||||
bits: Vec<String>,
|
bits: Vec<String>,
|
||||||
filters: Vec<DjangoFilter>,
|
filters: Vec<DjangoFilter>,
|
||||||
|
@ -44,8 +44,8 @@ pub enum Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
pub enum TagNode {
|
pub enum BlockNode {
|
||||||
Block {
|
Standard {
|
||||||
name: String,
|
name: String,
|
||||||
bits: Vec<String>,
|
bits: Vec<String>,
|
||||||
children: Vec<Node>,
|
children: Vec<Node>,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ast::{Ast, AstError, DjangoFilter, DjangoNode, Node, TagNode};
|
use crate::ast::{Ast, AstError, BlockNode, DjangoFilter, Node};
|
||||||
use crate::tagspecs::TagSpec;
|
use crate::tagspecs::TagSpec;
|
||||||
use crate::tokens::{Token, TokenStream, TokenType};
|
use crate::tokens::{Token, TokenStream, TokenType};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
@ -151,13 +151,13 @@ impl Parser {
|
||||||
if spec.closing.as_deref() == Some(&tag) {
|
if spec.closing.as_deref() == Some(&tag) {
|
||||||
// If we have a current branch, add it to children
|
// If we have a current branch, add it to children
|
||||||
if let Some((name, bits, branch_children)) = current_branch {
|
if let Some((name, bits, branch_children)) = current_branch {
|
||||||
children.push(Node::Tag(TagNode::Branch {
|
children.push(Node::Block(BlockNode::Branch {
|
||||||
name,
|
name,
|
||||||
bits,
|
bits,
|
||||||
children: branch_children,
|
children: branch_children,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
children.push(Node::Tag(TagNode::Closing {
|
children.push(Node::Block(BlockNode::Closing {
|
||||||
name: tag,
|
name: tag,
|
||||||
bits: vec![],
|
bits: vec![],
|
||||||
}));
|
}));
|
||||||
|
@ -169,7 +169,7 @@ impl Parser {
|
||||||
if let Some(branch) = branches.iter().find(|i| i.name == tag) {
|
if let Some(branch) = branches.iter().find(|i| i.name == tag) {
|
||||||
// If we have a current branch, add it to children
|
// If we have a current branch, add it to children
|
||||||
if let Some((name, bits, branch_children)) = current_branch {
|
if let Some((name, bits, branch_children)) = current_branch {
|
||||||
children.push(Node::Tag(TagNode::Branch {
|
children.push(Node::Block(BlockNode::Branch {
|
||||||
name,
|
name,
|
||||||
bits,
|
bits,
|
||||||
children: branch_children,
|
children: branch_children,
|
||||||
|
@ -194,7 +194,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If we get here, it's an unexpected tag
|
// If we get here, it's an unexpected tag
|
||||||
let node = Node::Tag(TagNode::Block {
|
let node = Node::Block(BlockNode::Standard {
|
||||||
name: tag_name.clone(),
|
name: tag_name.clone(),
|
||||||
bits: bits.clone(),
|
bits: bits.clone(),
|
||||||
children: children.clone(),
|
children: children.clone(),
|
||||||
|
@ -208,7 +208,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let node = Node::Tag(TagNode::Block {
|
let node = Node::Block(BlockNode::Standard {
|
||||||
name: tag_name.clone(),
|
name: tag_name.clone(),
|
||||||
bits,
|
bits,
|
||||||
children,
|
children,
|
||||||
|
|
|
@ -4,6 +4,5 @@ expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Text: "<!-- HTML comment -->"
|
- Text: "<!-- HTML comment -->"
|
||||||
- Django:
|
- Comment: Django comment
|
||||||
Comment: Django comment
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,37 +3,33 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- x
|
||||||
- x
|
- ">"
|
||||||
- ">"
|
- "0"
|
||||||
- "0"
|
children:
|
||||||
children:
|
- Text: Positive
|
||||||
- Text: Positive
|
- Block:
|
||||||
- Django:
|
Branch:
|
||||||
Tag:
|
name: elif
|
||||||
Branch:
|
bits:
|
||||||
name: elif
|
- x
|
||||||
bits:
|
- "<"
|
||||||
- x
|
- "0"
|
||||||
- "<"
|
children:
|
||||||
- "0"
|
- Text: Negative
|
||||||
children:
|
- Block:
|
||||||
- Text: Negative
|
Branch:
|
||||||
- Django:
|
name: else
|
||||||
Tag:
|
bits: []
|
||||||
Branch:
|
children:
|
||||||
name: else
|
- Text: Zero
|
||||||
bits: []
|
- Block:
|
||||||
children:
|
Closing:
|
||||||
- Text: Zero
|
name: endif
|
||||||
- Django:
|
bits: []
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endif
|
|
||||||
bits: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,31 +3,27 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: for
|
||||||
name: for
|
bits:
|
||||||
bits:
|
- for
|
||||||
- for
|
- item
|
||||||
- item
|
- in
|
||||||
- in
|
- items
|
||||||
- items
|
children:
|
||||||
children:
|
- Variable:
|
||||||
- Django:
|
bits:
|
||||||
Variable:
|
- item
|
||||||
bits:
|
filters: []
|
||||||
- item
|
- Block:
|
||||||
filters: []
|
Branch:
|
||||||
- Django:
|
name: empty
|
||||||
Tag:
|
bits: []
|
||||||
Branch:
|
children:
|
||||||
name: empty
|
- Text: No items
|
||||||
bits: []
|
- Block:
|
||||||
children:
|
Closing:
|
||||||
- Text: No items
|
name: endfor
|
||||||
- Django:
|
bits: []
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endfor
|
|
||||||
bits: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,18 +3,16 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- user.is_authenticated
|
||||||
- user.is_authenticated
|
children:
|
||||||
children:
|
- Text: Welcome
|
||||||
- Text: Welcome
|
- Block:
|
||||||
- Django:
|
Closing:
|
||||||
Tag:
|
name: endif
|
||||||
Closing:
|
bits: []
|
||||||
name: endif
|
|
||||||
bits: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,12 +3,11 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Variable:
|
||||||
Variable:
|
bits:
|
||||||
bits:
|
- user
|
||||||
- user
|
- name
|
||||||
- name
|
filters:
|
||||||
filters:
|
- name: title
|
||||||
- name: title
|
arguments: []
|
||||||
arguments: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,16 +3,15 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Variable:
|
||||||
Variable:
|
bits:
|
||||||
bits:
|
- value
|
||||||
- value
|
filters:
|
||||||
filters:
|
- name: default
|
||||||
- name: default
|
arguments:
|
||||||
arguments:
|
- "'nothing'"
|
||||||
- "'nothing'"
|
- name: title
|
||||||
- name: title
|
arguments: []
|
||||||
arguments: []
|
- name: upper
|
||||||
- name: upper
|
arguments: []
|
||||||
arguments: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -4,115 +4,101 @@ expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Text: "Welcome, "
|
- Text: "Welcome, "
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- user.is_authenticated
|
||||||
- user.is_authenticated
|
children:
|
||||||
children:
|
- Text: "\n "
|
||||||
- Text: "\n "
|
- Variable:
|
||||||
- Django:
|
bits:
|
||||||
Variable:
|
- user
|
||||||
bits:
|
- name
|
||||||
- user
|
filters:
|
||||||
- name
|
- name: title
|
||||||
filters:
|
arguments: []
|
||||||
- name: title
|
- name: default
|
||||||
arguments: []
|
arguments:
|
||||||
- name: default
|
- "'Guest'"
|
||||||
arguments:
|
- Text: "\n "
|
||||||
- "'Guest'"
|
- Block:
|
||||||
- Text: "\n "
|
Standard:
|
||||||
- Django:
|
name: for
|
||||||
Tag:
|
bits:
|
||||||
Block:
|
- for
|
||||||
name: for
|
- group
|
||||||
bits:
|
- in
|
||||||
- for
|
- user.groups
|
||||||
- group
|
children:
|
||||||
- in
|
- Text: "\n "
|
||||||
- user.groups
|
- Block:
|
||||||
children:
|
Standard:
|
||||||
- Text: "\n "
|
name: if
|
||||||
- Django:
|
bits:
|
||||||
Tag:
|
- if
|
||||||
Block:
|
- forloop.first
|
||||||
name: if
|
children:
|
||||||
bits:
|
- Text: (
|
||||||
- if
|
- Block:
|
||||||
- forloop.first
|
Closing:
|
||||||
children:
|
name: endif
|
||||||
- Text: (
|
bits: []
|
||||||
- Django:
|
- Text: "\n "
|
||||||
Tag:
|
- Variable:
|
||||||
Closing:
|
bits:
|
||||||
name: endif
|
- group
|
||||||
bits: []
|
- name
|
||||||
- Text: "\n "
|
filters: []
|
||||||
- Django:
|
- Text: "\n "
|
||||||
Variable:
|
- Block:
|
||||||
bits:
|
Standard:
|
||||||
- group
|
name: if
|
||||||
- name
|
bits:
|
||||||
filters: []
|
- if
|
||||||
- Text: "\n "
|
- not
|
||||||
- Django:
|
- forloop.last
|
||||||
Tag:
|
children:
|
||||||
Block:
|
- Text: ", "
|
||||||
name: if
|
- Block:
|
||||||
bits:
|
Closing:
|
||||||
- if
|
name: endif
|
||||||
- not
|
bits: []
|
||||||
- forloop.last
|
- Text: "\n "
|
||||||
children:
|
- Block:
|
||||||
- Text: ", "
|
Standard:
|
||||||
- Django:
|
name: if
|
||||||
Tag:
|
bits:
|
||||||
Closing:
|
- if
|
||||||
name: endif
|
- forloop.last
|
||||||
bits: []
|
children:
|
||||||
- Text: "\n "
|
- Text: )
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Closing:
|
||||||
Block:
|
name: endif
|
||||||
name: if
|
bits: []
|
||||||
bits:
|
- Text: "\n "
|
||||||
- if
|
- Block:
|
||||||
- forloop.last
|
Branch:
|
||||||
children:
|
name: empty
|
||||||
- Text: )
|
bits: []
|
||||||
- Django:
|
children:
|
||||||
Tag:
|
- Text: "\n (no groups)\n "
|
||||||
Closing:
|
- Block:
|
||||||
name: endif
|
Closing:
|
||||||
bits: []
|
name: endfor
|
||||||
- Text: "\n "
|
bits: []
|
||||||
- Django:
|
- Text: "\n"
|
||||||
Tag:
|
- Block:
|
||||||
Branch:
|
Branch:
|
||||||
name: empty
|
name: else
|
||||||
bits: []
|
bits: []
|
||||||
children:
|
children:
|
||||||
- Text: "\n (no groups)\n "
|
- Text: "\n Guest\n"
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Closing:
|
||||||
Closing:
|
name: endif
|
||||||
name: endfor
|
bits: []
|
||||||
bits: []
|
|
||||||
- Text: "\n"
|
|
||||||
- Django:
|
|
||||||
Tag:
|
|
||||||
Branch:
|
|
||||||
name: else
|
|
||||||
bits: []
|
|
||||||
children:
|
|
||||||
- Text: "\n Guest\n"
|
|
||||||
- Django:
|
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endif
|
|
||||||
bits: []
|
|
||||||
- Text: "!"
|
- Text: "!"
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -3,38 +3,33 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: for
|
||||||
name: for
|
bits:
|
||||||
bits:
|
- for
|
||||||
- for
|
- item
|
||||||
- item
|
- in
|
||||||
- in
|
- items
|
||||||
- items
|
children:
|
||||||
children:
|
- Block:
|
||||||
- Django:
|
Standard:
|
||||||
Tag:
|
name: if
|
||||||
Block:
|
bits:
|
||||||
name: if
|
- if
|
||||||
bits:
|
- item.active
|
||||||
- if
|
children:
|
||||||
- item.active
|
- Variable:
|
||||||
children:
|
bits:
|
||||||
- Django:
|
- item
|
||||||
Variable:
|
- name
|
||||||
bits:
|
filters: []
|
||||||
- item
|
- Block:
|
||||||
- name
|
Closing:
|
||||||
filters: []
|
name: endif
|
||||||
- Django:
|
bits: []
|
||||||
Tag:
|
- Block:
|
||||||
Closing:
|
Closing:
|
||||||
name: endif
|
name: endfor
|
||||||
bits: []
|
bits: []
|
||||||
- Django:
|
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endfor
|
|
||||||
bits: []
|
|
||||||
errors: []
|
errors: []
|
||||||
|
|
|
@ -4,50 +4,43 @@ expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Text: "<div class=\"container\">\n <h1>Header</h1>\n "
|
- Text: "<div class=\"container\">\n <h1>Header</h1>\n "
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- user.is_authenticated
|
||||||
- user.is_authenticated
|
children:
|
||||||
children:
|
- Text: "\n "
|
||||||
- Text: "\n "
|
- Comment: This if is unclosed which does matter
|
||||||
- Django:
|
- Text: "\n <p>Welcome "
|
||||||
Comment: This if is unclosed which does matter
|
- Variable:
|
||||||
- Text: "\n <p>Welcome "
|
bits:
|
||||||
- Django:
|
- user
|
||||||
Variable:
|
- name
|
||||||
bits:
|
filters: []
|
||||||
- user
|
- Text: "</p>\n <div>\n "
|
||||||
- name
|
- Comment: "This div is unclosed which doesn't matter"
|
||||||
filters: []
|
- Text: "\n "
|
||||||
- Text: "</p>\n <div>\n "
|
- Block:
|
||||||
- Django:
|
Standard:
|
||||||
Comment: "This div is unclosed which doesn't matter"
|
name: for
|
||||||
- Text: "\n "
|
bits:
|
||||||
- Django:
|
- for
|
||||||
Tag:
|
- item
|
||||||
Block:
|
- in
|
||||||
name: for
|
- items
|
||||||
bits:
|
children:
|
||||||
- for
|
- Text: "\n <span>"
|
||||||
- item
|
- Variable:
|
||||||
- in
|
bits:
|
||||||
- items
|
- item
|
||||||
children:
|
filters: []
|
||||||
- Text: "\n <span>"
|
- Text: "</span>\n "
|
||||||
- Django:
|
- Block:
|
||||||
Variable:
|
Closing:
|
||||||
bits:
|
name: endfor
|
||||||
- item
|
bits: []
|
||||||
filters: []
|
- Text: "\n <footer>Page Footer</footer>\n</div>"
|
||||||
- Text: "</span>\n "
|
|
||||||
- Django:
|
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endfor
|
|
||||||
bits: []
|
|
||||||
- Text: "\n <footer>Page Footer</footer>\n</div>"
|
|
||||||
errors:
|
errors:
|
||||||
- UnclosedTag: if
|
- UnclosedTag: if
|
||||||
|
|
|
@ -3,21 +3,19 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: for
|
||||||
name: for
|
bits:
|
||||||
bits:
|
- for
|
||||||
- for
|
- item
|
||||||
- item
|
- in
|
||||||
- in
|
- items
|
||||||
- items
|
children:
|
||||||
children:
|
- Variable:
|
||||||
- Django:
|
bits:
|
||||||
Variable:
|
- item
|
||||||
bits:
|
- name
|
||||||
- item
|
filters: []
|
||||||
- name
|
|
||||||
filters: []
|
|
||||||
errors:
|
errors:
|
||||||
- UnclosedTag: for
|
- UnclosedTag: for
|
||||||
|
|
|
@ -3,14 +3,13 @@ source: crates/djls-template-ast/src/parser.rs
|
||||||
expression: ast
|
expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- user.is_authenticated
|
||||||
- user.is_authenticated
|
children:
|
||||||
children:
|
- Text: Welcome
|
||||||
- Text: Welcome
|
|
||||||
errors:
|
errors:
|
||||||
- UnclosedTag: if
|
- UnclosedTag: if
|
||||||
|
|
|
@ -4,56 +4,49 @@ expression: ast
|
||||||
---
|
---
|
||||||
nodes:
|
nodes:
|
||||||
- Text: "<!DOCTYPE html>\n<html>\n <head>\n <style type=\"text/css\">\n /* Style header */\n .header { color: blue; }\n </style>\n <script type=\"text/javascript\">\n // Init app\n const app = {\n /* Config */\n debug: true\n };\n </script>\n </head>\n <body>\n <!-- Header section -->\n <div class=\"header\" id=\"main\" data-value=\"123\" disabled>\n "
|
- Text: "<!DOCTYPE html>\n<html>\n <head>\n <style type=\"text/css\">\n /* Style header */\n .header { color: blue; }\n </style>\n <script type=\"text/javascript\">\n // Init app\n const app = {\n /* Config */\n debug: true\n };\n </script>\n </head>\n <body>\n <!-- Header section -->\n <div class=\"header\" id=\"main\" data-value=\"123\" disabled>\n "
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Standard:
|
||||||
Block:
|
name: if
|
||||||
name: if
|
bits:
|
||||||
bits:
|
- if
|
||||||
- if
|
- user.is_authenticated
|
||||||
- user.is_authenticated
|
children:
|
||||||
children:
|
- Text: "\n "
|
||||||
- Text: "\n "
|
- Comment: Welcome message
|
||||||
- Django:
|
- Text: "\n <h1>Welcome, "
|
||||||
Comment: Welcome message
|
- Variable:
|
||||||
- Text: "\n <h1>Welcome, "
|
bits:
|
||||||
- Django:
|
- user
|
||||||
Variable:
|
- name
|
||||||
bits:
|
filters:
|
||||||
- user
|
- name: title
|
||||||
- name
|
arguments: []
|
||||||
filters:
|
- name: default
|
||||||
- name: title
|
arguments:
|
||||||
arguments: []
|
- "'Guest'"
|
||||||
- name: default
|
- Text: "!</h1>\n "
|
||||||
arguments:
|
- Block:
|
||||||
- "'Guest'"
|
Standard:
|
||||||
- Text: "!</h1>\n "
|
name: if
|
||||||
- Django:
|
bits:
|
||||||
Tag:
|
- if
|
||||||
Block:
|
- user.is_staff
|
||||||
name: if
|
children:
|
||||||
bits:
|
- Text: "\n <span>Admin</span>\n "
|
||||||
- if
|
- Block:
|
||||||
- user.is_staff
|
Branch:
|
||||||
children:
|
name: else
|
||||||
- Text: "\n <span>Admin</span>\n "
|
bits: []
|
||||||
- Django:
|
children:
|
||||||
Tag:
|
- Text: "\n <span>User</span>\n "
|
||||||
Branch:
|
- Block:
|
||||||
name: else
|
Closing:
|
||||||
bits: []
|
name: endif
|
||||||
children:
|
bits: []
|
||||||
- Text: "\n <span>User</span>\n "
|
- Text: "\n "
|
||||||
- Django:
|
- Block:
|
||||||
Tag:
|
Closing:
|
||||||
Closing:
|
name: endif
|
||||||
name: endif
|
bits: []
|
||||||
bits: []
|
|
||||||
- Text: "\n "
|
|
||||||
- Django:
|
|
||||||
Tag:
|
|
||||||
Closing:
|
|
||||||
name: endif
|
|
||||||
bits: []
|
|
||||||
- Text: "\n </div>\n </body>\n</html>"
|
- Text: "\n </div>\n </body>\n</html>"
|
||||||
errors: []
|
errors: []
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue