Add rst.heading()

This commit is contained in:
Takeshi KOMIYA 2019-05-02 13:46:10 +09:00
parent de0c44196e
commit 662389b8b0
2 changed files with 69 additions and 2 deletions

View File

@ -9,11 +9,14 @@
"""
import re
from collections import defaultdict
from contextlib import contextmanager
from unicodedata import east_asian_width
from docutils.parsers.rst import roles
from docutils.parsers.rst.languages import en as english
from docutils.utils import Reporter
from jinja2 import environmentfilter
from sphinx.locale import __
from sphinx.util import docutils
@ -21,13 +24,20 @@ from sphinx.util import logging
if False:
# For type annotation
from typing import Generator # NOQA
from typing import Callable, Dict, Generator # NOQA
from docutils.statemachine import StringList # NOQA
from jinja2 import Environment # NOQA
logger = logging.getLogger(__name__)
docinfo_re = re.compile(':\\w+:.*?')
symbols_re = re.compile(r'([!-\-/:-@\[-`{-~])') # symbols without dot(0x2e)
SECTIONING_CHARS = ['=', '-', '~']
# width of characters
WIDECHARS = defaultdict(lambda: "WF") # type: Dict[str, str]
# WF: Wide + Full-width
WIDECHARS["ja"] = "WFA" # In Japanese, Ambiguous characters also have double width
def escape(text):
@ -37,6 +47,29 @@ def escape(text):
return text
def textwidth(text, widechars='WF'):
# type: (str, str) -> int
"""Get width of text."""
def charwidth(char, widechars):
# type: (str, str) -> int
if east_asian_width(char) in widechars:
return 2
else:
return 1
return sum(charwidth(c, widechars) for c in text)
@environmentfilter
def heading(env, text, level=1):
# type: (Environment, str, int) -> str
"""Create a heading for *level*."""
assert level <= 3
width = textwidth(text, WIDECHARS[env.language]) # type: ignore
sectioning_char = SECTIONING_CHARS[level - 1]
return '%s\n%s' % (text, sectioning_char * width)
@contextmanager
def default_role(docname, name):
# type: (str, str) -> Generator

View File

@ -9,8 +9,11 @@
"""
from docutils.statemachine import StringList
from jinja2 import Environment
from sphinx.util.rst import append_epilog, escape, prepend_prolog
from sphinx.util.rst import (
append_epilog, escape, heading, prepend_prolog, textwidth
)
def test_escape():
@ -83,3 +86,34 @@ def test_prepend_prolog_without_CR(app):
('<generated>', 0, ''),
('dummy.rst', 0, 'hello Sphinx world'),
('dummy.rst', 1, 'Sphinx is a document generator')]
def test_textwidth():
assert textwidth('Hello') == 5
assert textwidth('русский язык') == 12
assert textwidth('русский язык', 'WFA') == 23 # Cyrillic are ambiguous chars
def test_heading():
env = Environment()
env.extend(language=None)
assert heading(env, 'Hello') == ('Hello\n'
'=====')
assert heading(env, 'Hello', 1) == ('Hello\n'
'=====')
assert heading(env, 'Hello', 2) == ('Hello\n'
'-----')
assert heading(env, 'Hello', 3) == ('Hello\n'
'~~~~~')
assert heading(env, 'русский язык', 1) == (
'русский язык\n'
'============'
)
# language=ja: ambiguous
env.language = 'ja'
assert heading(env, 'русский язык', 1) == (
'русский язык\n'
'======================='
)