Skip to content

Commit

Permalink
ENH: Automatically shorten links for GitHub/GitLab (#957)
Browse files Browse the repository at this point in the history
* shorten links

* typo

* add icons scss

* add example

* check uri existence

* fix: docutil deprecation warning

* manage smaller links (user, repository, github itself)

* fix: workaround for reference without body

* set up the example as a link

* update the tests

* typo

* typo

* fix: test uses 1 space indentation

* test: add the gitlab link

* add a normal link

* use > instead of >= for tests

* parse_path cannot be called if platform is None

* Update docs/user_guide/theme-elements.md

Co-authored-by: Chris Holdgraf <choldgraf@gmail.com>

* Update docs/user_guide/theme-elements.md

Co-authored-by: Chris Holdgraf <choldgraf@gmail.com>

* Update src/pydata_sphinx_theme/__init__.py

Co-authored-by: Chris Holdgraf <choldgraf@gmail.com>

* Update src/pydata_sphinx_theme/__init__.py

Co-authored-by: Chris Holdgraf <choldgraf@gmail.com>

* refactor: new function names

* maint: use fontawesome 6

Co-authored-by: Chris Holdgraf <choldgraf@gmail.com>
  • Loading branch information
12rambau and choldgraf committed Sep 30, 2022
1 parent 494e5e9 commit 959042d
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 1 deletion.
6 changes: 6 additions & 0 deletions docs/user_guide/theme-elements.md
Expand Up @@ -143,3 +143,9 @@ For example, the admonition sidebar was created with the following markdown:
Some sidebar content.
```
````

## Link shortening for git repository services

Many projects have links back to their issues / PRs hosted on platforms like **GitHub** or **GitLab**. Instead of displaying these as raw links, this theme does some lightweight formatting for these platforms specifically. Here is an example from the issue requesting this feature: [https://github.com/pydata/pydata-sphinx-theme/issues/841](https://github.com/pydata/pydata-sphinx-theme/issues/841).

Links provided with a text body won't be changed.
78 changes: 78 additions & 0 deletions src/pydata_sphinx_theme/__init__.py
Expand Up @@ -5,12 +5,16 @@
import warnings
from pathlib import Path
from functools import lru_cache
from urllib.parse import urlparse

import jinja2
from bs4 import BeautifulSoup as bs
from docutils import nodes
from sphinx import addnodes
from sphinx.environment.adapters.toctree import TocTree
from sphinx.addnodes import toctree as toctree_node
from sphinx.transforms.post_transforms import SphinxPostTransform
from sphinx.util.nodes import NodeMatcher
from sphinx.errors import ExtensionError
from sphinx.util import logging
from pygments.formatters import HtmlFormatter
Expand Down Expand Up @@ -816,6 +820,78 @@ def _overwrite_pygments_css(app, exception=None):
f.write(get_pygments_stylesheet(light_theme, dark_theme))


# ------------------------------------------------------------------------------
# customize rendering of the links
# ------------------------------------------------------------------------------


class ShortenLinkTransform(SphinxPostTransform):
"""
Shorten link when they are coming from github or gitlab and add an extra class to the tag
for further styling.
Before::
<a class="reference external" href="https://github.com/2i2c-org/infrastructure/issues/1329">
https://github.com/2i2c-org/infrastructure/issues/1329
</a>
After::
<a class="reference external github" href="https://github.com/2i2c-org/infrastructure/issues/1329">
2i2c-org/infrastructure#1329
</a>
""" # noqa

default_priority = 400
formats = ("html",)
supported_platform = {"github.com": "github", "gitlab.com": "gitlab"}
platform = None

def run(self, **kwargs):
matcher = NodeMatcher(nodes.reference)
for node in self.document.findall(matcher):
uri = node.attributes.get("refuri")
text = next(iter(node.children), None)
# only act if the uri and text are the same
# if not the user has already customized the display of the link
if uri is not None and text is not None and text == uri:
uri = urlparse(uri)
# only do something if the platform is identified
self.platform = self.supported_platform.get(uri.netloc)
if self.platform is not None:
node.attributes["classes"].append(self.platform)
node.children[0] = nodes.Text(self.parse_url(uri.path))

def parse_url(self, path):
"""
parse the content of the url with respect to the selected platform
"""

# split the url content
# be careful the first one is a "/"
s = path.split("/")

# check the platform name and read the information accordingly
if self.platform == "github":
text = "github"
if len(s) > 1:
text = s[1]
if len(s) > 2:
text += f"/{s[2]}"
if len(s) > 3:
if s[3] in ["issues", "pull", "discussions"]:
text += f"#{s[-1]}"

elif self.platform == "gitlab":
text = "gitlab"
if len(s) > 1:
text = s[1]
if len(s) > 2:
text += f"/{s[2]}"
if len(s) > 3:
if s[4] in ["issues", "merge_requests"]:
text += f"#{s[-1]}"

return text


# -----------------------------------------------------------------------------


Expand All @@ -825,6 +901,8 @@ def setup(app):

app.add_html_theme("pydata_sphinx_theme", str(theme_path))

app.add_post_transform(ShortenLinkTransform)

app.set_translator("html", BootstrapHTML5Translator)
# Read the Docs uses ``readthedocs`` as the name of the build, and also
# uses a special "dirhtml" builder so we need to replace these both with
Expand Down
15 changes: 15 additions & 0 deletions src/pydata_sphinx_theme/assets/styles/base/_base.scss
Expand Up @@ -59,6 +59,21 @@ a {
opacity: 1;
}
}

// set up a icon next to the shorten links from github and gitlab
&::before {
color: var(--pst-color-text-muted);
font-family: "Font Awesome 6 Brands";
margin-right: 0.25rem;
}

&.github::before {
content: var(--pst-icon-github);
}

&.gitlab::before {
content: var(--pst-icon-gitlab);
}
}

.heading-style {
Expand Down
Expand Up @@ -242,7 +242,7 @@ div.topic,
div.topic.contents,
// Docutils >= 0.18
nav.contents,
aside.topic, {
aside.topic {
display: flex;
flex-direction: column;
background-color: var(--pst-color-surface);
Expand Down
2 changes: 2 additions & 0 deletions src/pydata_sphinx_theme/assets/styles/variables/_icons.scss
Expand Up @@ -18,4 +18,6 @@
--pst-icon-angle-right: "\f105"; // fa-solid fa-angle-right
--pst-icon-external-link: "\f35d"; // fa-solid fa-up-right-from-square
--pst-icon-search-minus: "\f010"; // fa-solid fa-magnifying-glass-minus
--pst-icon-github: "\f09b"; // fa-brands fa-github
--pst-icon-gitlab: "\f296"; // fa-brands fa-gitlab
}
4 changes: 4 additions & 0 deletions tests/sites/base/page1.rst
@@ -1,2 +1,6 @@
Page 1
======

- here's a normal link: https://pydata-sphinx-theme.readthedocs.io/en/latest/
- Here's a github link: https://github.com/2i2c-org/infrastructure/issues/1329
- Here's a gitlab link: https://gitlab.com/gitlab-org/gitlab/-/issues/375583
12 changes: 12 additions & 0 deletions tests/test_build.py
Expand Up @@ -664,3 +664,15 @@ def test_theme_switcher(sphinx_build_factory, file_regression):
file_regression.check(
switcher.prettify(), basename="navbar_theme", extension=".html"
)


def test_shorten_link(sphinx_build_factory, file_regression):
"""regression test the shorten links html"""

sphinx_build = sphinx_build_factory("base").build()

github = sphinx_build.html_tree("page1.html").select(".github")[0]
file_regression.check(github.prettify(), basename="github_link", extension=".html")

gitlab = sphinx_build.html_tree("page1.html").select(".gitlab")[0]
file_regression.check(gitlab.prettify(), basename="gitlab_link", extension=".html")
3 changes: 3 additions & 0 deletions tests/test_build/github_link.html
@@ -0,0 +1,3 @@
<a class="github reference external" href="https://github.com/2i2c-org/infrastructure/issues/1329">
2i2c-org/infrastructure#1329
</a>
3 changes: 3 additions & 0 deletions tests/test_build/gitlab_link.html
@@ -0,0 +1,3 @@
<a class="gitlab reference external" href="https://gitlab.com/gitlab-org/gitlab/-/issues/375583">
gitlab-org/gitlab#375583
</a>

0 comments on commit 959042d

Please sign in to comment.