mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #11697 from ethereum/sphinx-remix-code-links-extension
Sphinx extension for adding Remix links to code snippets
This commit is contained in:
commit
c980e96b64
36
docs/_static/css/custom.css
vendored
36
docs/_static/css/custom.css
vendored
@ -45,4 +45,40 @@ pre {
|
|||||||
/* menu section headers */
|
/* menu section headers */
|
||||||
.wy-menu .caption {
|
.wy-menu .caption {
|
||||||
color: #65afff !important;
|
color: #65afff !important;
|
||||||
|
|
||||||
|
/* Link to Remix IDE shown next to code snippets */
|
||||||
|
p.remix-link-container {
|
||||||
|
position: relative;
|
||||||
|
right: -100%; /* Positioned next to the the top-right corner of the code block following it. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.remix-link {
|
||||||
|
position: absolute; /* Remove it from normal flow not to affect the original position of the snippet. */
|
||||||
|
top: 0.5em;
|
||||||
|
width: 3.236em; /* Size of the margin (= right-side padding in .wy-nav-content in the current theme). */
|
||||||
|
}
|
||||||
|
|
||||||
|
a.remix-link .link-icon {
|
||||||
|
background: url("../img/share-solid.svg") no-repeat;
|
||||||
|
display: block;
|
||||||
|
width: 1.5em;
|
||||||
|
height: 1.5em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.remix-link .link-text {
|
||||||
|
display: none; /* Visible only on hover. */
|
||||||
|
width: 3.3em; /* Narrow enough to get two lines of text. */
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.8em;
|
||||||
|
line-height: normal;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.remix-link:hover {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.remix-link:hover .link-text {
|
||||||
|
display: block;
|
||||||
|
6
docs/_static/css/dark.css
vendored
6
docs/_static/css/dark.css
vendored
@ -627,3 +627,9 @@ code.docutils.literal.notranslate {
|
|||||||
|
|
||||||
|
|
||||||
/* Literal.Number.Integer.Long */
|
/* Literal.Number.Integer.Long */
|
||||||
|
|
||||||
|
|
||||||
|
/* Link to Remix IDE shown over code snippets */
|
||||||
|
a.remix-link {
|
||||||
|
filter: invert(1); /* The icon is black. In dark mode we want it white. */
|
||||||
|
}
|
||||||
|
1
docs/_static/img/share-solid.svg
vendored
Normal file
1
docs/_static/img/share-solid.svg
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="share" class="svg-inline--fa fa-share fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M503.691 189.836L327.687 37.851C312.281 24.546 288 35.347 288 56.015v80.053C127.371 137.907 0 170.1 0 322.326c0 61.441 39.581 122.309 83.333 154.132 13.653 9.931 33.111-2.533 28.077-18.631C66.066 312.814 132.917 274.316 288 272.085V360c0 20.7 24.3 31.453 39.687 18.164l176.004-152c11.071-9.562 11.086-26.753 0-36.328z"></path></svg>
|
After Width: | Height: | Size: 547 B |
6
docs/_templates/footer.html
vendored
Normal file
6
docs/_templates/footer.html
vendored
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{% extends "!footer.html" %}
|
||||||
|
|
||||||
|
{% block extrafooter %}
|
||||||
|
<br>
|
||||||
|
<a href="{{ pathto('credits-and-attribution') }}">Credits and attribution</a>.
|
||||||
|
{% endblock %}
|
@ -44,6 +44,7 @@ def setup(sphinx):
|
|||||||
extensions = [
|
extensions = [
|
||||||
'sphinx_a4doc',
|
'sphinx_a4doc',
|
||||||
'html_extra_template_renderer',
|
'html_extra_template_renderer',
|
||||||
|
'remix_code_links',
|
||||||
]
|
]
|
||||||
|
|
||||||
a4_base_path = os.path.dirname(__file__) + '/grammar'
|
a4_base_path = os.path.dirname(__file__) + '/grammar'
|
||||||
|
21
docs/credits-and-attribution.rst
Normal file
21
docs/credits-and-attribution.rst
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
.. This page is meant to be linked to from the footer.
|
||||||
|
|
||||||
|
:orphan:
|
||||||
|
|
||||||
|
#######################
|
||||||
|
Credits and Attribution
|
||||||
|
#######################
|
||||||
|
|
||||||
|
Website icons
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. |icon-share-solid| image:: _static/img/share-solid.svg
|
||||||
|
.. _share icon: https://fontawesome.com/v5.15/icons/share?style=solid
|
||||||
|
.. _Font Awesome Free License: https://fontawesome.com/license/free
|
||||||
|
|
||||||
|
+-------------------------+-----------------------------------------------------------------------+
|
||||||
|
| Icon | Attribution |
|
||||||
|
+=========================+=======================================================================+
|
||||||
|
| |icon-share-solid| | - Source: `share icon`_ from Font Awesome 5.15.0. |
|
||||||
|
| | - License: `Font Awesome Free License`_ (CC BY 4.0). |
|
||||||
|
+-------------------------+-----------------------------------------------------------------------+
|
83
docs/ext/remix_code_links.py
Normal file
83
docs/ext/remix_code_links.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import base64
|
||||||
|
import docutils # pragma pylint: disable=import-error
|
||||||
|
|
||||||
|
from sphinx.util import logging # pragma pylint: disable=import-error
|
||||||
|
|
||||||
|
# NOTE: 2000 should generally be safe for all browsers, while 8000 for most of them.
|
||||||
|
MAX_SAFE_URL_LENGTH = 10000
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def insert_node_before(child, new_sibling):
|
||||||
|
assert child in child.parent.children
|
||||||
|
|
||||||
|
for position, node in enumerate(child.parent.children):
|
||||||
|
if node == child:
|
||||||
|
child.parent.insert(position, new_sibling)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def remix_code_url(source_code, language, solidity_version):
|
||||||
|
# NOTE: base64 encoded data may contain +, = and / characters. Remix seems to handle them just
|
||||||
|
# fine without any escaping.
|
||||||
|
base64_encoded_source = base64.b64encode(source_code.encode('utf-8')).decode('ascii')
|
||||||
|
return f"https://remix.ethereum.org/?language={language}&version={solidity_version}&code={base64_encoded_source}"
|
||||||
|
|
||||||
|
|
||||||
|
def build_remix_link_node(url):
|
||||||
|
link_icon_node = docutils.nodes.inline()
|
||||||
|
link_icon_node.set_class('link-icon')
|
||||||
|
|
||||||
|
link_text_node = docutils.nodes.inline(text="open in Remix")
|
||||||
|
link_text_node.set_class('link-text')
|
||||||
|
|
||||||
|
reference_node = docutils.nodes.reference('', '', internal=False, refuri=url)
|
||||||
|
reference_node.set_class('remix-link')
|
||||||
|
reference_node += [link_icon_node, link_text_node]
|
||||||
|
|
||||||
|
paragraph_node = docutils.nodes.paragraph()
|
||||||
|
paragraph_node.set_class('remix-link-container')
|
||||||
|
paragraph_node += reference_node
|
||||||
|
return paragraph_node
|
||||||
|
|
||||||
|
|
||||||
|
def insert_remix_link(app, doctree, solidity_version):
|
||||||
|
if app.builder.format != 'html' or app.builder.name == 'epub':
|
||||||
|
return
|
||||||
|
|
||||||
|
for literal_block_node in doctree.traverse(docutils.nodes.literal_block):
|
||||||
|
assert 'language' in literal_block_node.attributes
|
||||||
|
language = literal_block_node.attributes['language'].lower()
|
||||||
|
if language in ['solidity', 'yul']:
|
||||||
|
text_nodes = list(literal_block_node.traverse(docutils.nodes.Text))
|
||||||
|
assert len(text_nodes) == 1
|
||||||
|
|
||||||
|
remix_url = remix_code_url(text_nodes[0], language, solidity_version)
|
||||||
|
url_length = len(remix_url.encode('utf-8'))
|
||||||
|
if url_length > MAX_SAFE_URL_LENGTH:
|
||||||
|
logger.warning(
|
||||||
|
"Remix URL generated from the code snippet exceeds the maximum safe URL length "
|
||||||
|
" (%d > %d bytes).",
|
||||||
|
url_length,
|
||||||
|
MAX_SAFE_URL_LENGTH,
|
||||||
|
location=(literal_block_node.source, literal_block_node.line),
|
||||||
|
)
|
||||||
|
|
||||||
|
insert_node_before(literal_block_node, build_remix_link_node(remix_url))
|
||||||
|
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
# NOTE: Need to access _raw_config here because setup() runs before app.config is ready.
|
||||||
|
solidity_version = app.config._raw_config['version'] # pylint: disable=protected-access
|
||||||
|
|
||||||
|
app.connect(
|
||||||
|
'doctree-resolved',
|
||||||
|
lambda app, doctree, docname: insert_remix_link(app, doctree, solidity_version)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'version': solidity_version,
|
||||||
|
'parallel_read_safe': True,
|
||||||
|
'parallel_write_safe': True,
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user