Last active
November 11, 2016 15:53
-
-
Save shimizukawa/069818f5633d7e51ca0ff93541ed958b to your computer and use it in GitHub Desktop.
sphinx拡張: shuwa builder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
文頭は、一文字下げ | |
○章扉リード文(タグ不要) | |
○第1レベル見出し(節見出し) ■■■■ | |
○第2レベル見出し ■■■ | |
○第3レベル見出し ■■ | |
○第4レベル見出し ■ | |
▽●コラム | |
△● | |
▽●●Tips | |
△●● | |
▽●●● | |
表 表(Tabアキ) | |
表 表(Tabアキ) | |
表 表(Tabアキ) | |
△●●● | |
★[リスト番号○-○]――ソースファイル名★ | |
▽●●●● | |
(ソースコードやコマンドラインの全部・一部) | |
△●●●● | |
▽●●●●● | |
構文・書式 | |
△●●●●● | |
▲引き出し線キャプション▲ | |
(画面キャプチャの一部分を説明する場合などに利用) | |
☆一語・一行・短文強調☆ | |
(例) | |
ここで☆ラムダ式☆が定義されています。 | |
☆http://www.example.com/☆ | |
▽◎ | |
① 操作手順 | |
② 操作手順 | |
③ 操作手順 | |
△◎ | |
▽◆ | |
箇条書き | |
箇条書き | |
△◆ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf8 -*- | |
""" | |
docutils shuwa-system writer. | |
:copyright: Copyright 2014 by Takayuki SHIMIZUKAWA. | |
:license: MIT. | |
""" | |
__docformat__ = 'reStructuredText' | |
import posixpath | |
import os | |
import re | |
import textwrap | |
import unicodedata | |
import codecs | |
from itertools import izip_longest | |
from six import iteritems, text_type | |
from docutils import nodes | |
from docutils.io import StringOutput | |
from sphinx import addnodes | |
from sphinx.builders.text import TextBuilder | |
from sphinx.writers.text import TextWriter, TextTranslator | |
from sphinx.util.osutil import relative_uri, ensuredir, copyfile, os_path | |
from sphinx.util.console import bold, darkgreen, brown | |
from sphinx.util.nodes import inline_all_toctrees | |
admonition_labels = { | |
'note': (u'▽●●', u'△●●'), | |
'column': (u'▽●', u'△●'), | |
} | |
def node_prev(node): | |
if node.parent is not None: | |
idx = node.parent.children.index(node) | |
if idx: | |
return node.parent[idx-1] | |
return None | |
def node_next(node): | |
if node.parent is not None: | |
idx = node.parent.children.index(node) | |
if idx + 1 < len(node.parent): | |
return node.parent[idx+1] | |
return None | |
def get_width(text): | |
return sum((unicodedata.east_asian_width(x)=='W' and 2 or 1) for x in text) | |
def normalize_to_wide_parenthesis(text): | |
""" | |
If text include half parenthesis within wide text, emit warning. | |
""" | |
orig = text | |
text = text.replace(u'(', u'(').replace(u')', u')') | |
#if orig != text: | |
# print orig, ' -> ', text | |
return text | |
def convert_double_parenthesis(text): | |
""" | |
replace ((1)) -> ① | |
""" | |
circle_nums = re.findall(ur'([((]{2}(\d{1,2})[))]{2})', text) | |
for t, n in (x for x in circle_nums if 0<int(x[1])<=20): | |
text = text.replace(t, unichr(ord(u'①') - 1 + int(n))) | |
return text | |
def convert_for_rst(text, builder=None): | |
"""don't apply this to literal block""" | |
text = convert_double_parenthesis(text) | |
text = normalize_to_wide_parenthesis(text) | |
return text | |
def format_section_number(numbers): | |
""" | |
convert numbers from ['2', '3', '1'] to '02-03-01' | |
""" | |
numbers = map(text_type, numbers) | |
_ = (('%02d' % int(x) if x.isdigit() else x) for x in numbers) | |
secnum = '-'.join(_) | |
return secnum | |
def setup(app): | |
app.add_builder(ShuwaBuilder) | |
class ShuwaBuilder(TextBuilder): | |
name = 'shuwa' | |
format = 'text' | |
out_suffix = '.txt' | |
def init(self): | |
TextBuilder.init(self) | |
self.assembled_fignumbers = {} | |
self.assembled_secnumbers = {} | |
def get_docname(self, node): | |
docname = self.current_docname | |
p = node | |
while p: | |
if p.get('docname'): | |
docname = p.get('docname') | |
break | |
p = p.parent | |
return docname | |
def assemble_doctree(self, docname): | |
tree = self.env.get_doctree(docname) | |
docnameset = set() | |
tree = inline_all_toctrees(self, docnameset, docname, tree, darkgreen) | |
tree['docname'] = docname | |
self.env.resolve_references(tree, docname, self) | |
return tree, docnameset | |
def assemble_toc_secnumbers(self, root_docname, child_docnames): | |
# Assemble toc_secnumbers to resolve section numbers on Merged File. | |
# Merge all secnumbers to single secnumber. | |
new_secnumbers = self.assembled_secnumbers[root_docname] = {} | |
for docname in set([root_docname]) | child_docnames: | |
secnums = self.env.toc_secnumbers.get(docname, {}) | |
for id, secnum in iteritems(secnums): | |
new_secnumbers[(docname, id)] = secnum | |
def assemble_toc_fignumbers(self, root_docname, child_docnames): | |
# Assemble toc_fignumbers to resolve section numbers on Merged File. | |
# Merge all fignumbers to single fignumber. | |
new_fignumbers = self.assembled_fignumbers[root_docname] = {} | |
for docname in set([root_docname]) | child_docnames: | |
fignums = self.env.toc_fignumbers.get(docname, {}) | |
for figtype, figids in iteritems(fignums): | |
for id, fignum in iteritems(figids): | |
new_fignumbers.setdefault(figtype, {})[(docname, id)] = fignum | |
def get_docnames_in_doc(self, docname): | |
doctree = self.env.get_doctree(docname) | |
docnameset = set() | |
for toctreenode in doctree.traverse(addnodes.toctree): | |
includefiles = map(text_type, toctreenode['includefiles']) | |
for includefile in includefiles: | |
try: | |
docnameset.add(includefile) | |
except Exception: | |
self.warn('toctree contains ref to nonexisting ' | |
'file %r' % includefile, | |
self.env.doc2path(docname)) | |
return docnameset | |
def get_outfilename(self, docname): | |
secnumbers = self.assembled_secnumbers.get(docname) | |
if secnumbers: | |
secnum = secnumbers[(docname, '')][0] | |
outfilename = '%02d%s' % (secnum, self.out_suffix) | |
elif '/' in docname: | |
outfilename = docname.split('/')[0] + self.out_suffix | |
else: | |
outfilename = os_path(docname) + self.out_suffix | |
outfilename = os.path.join(self.outdir, outfilename) | |
return outfilename | |
def get_target_uri(self, docname, typ=None): | |
return docname | |
def get_relative_uri(self, from_, to, typ=None): | |
# ignore source | |
return self.get_target_uri(to, typ) | |
def write(self, *ignored): | |
self.info(bold('preparing documents... '), nonl=True) | |
self.prepare_writing(self.env.all_docs) | |
self.info('done') | |
master_doc = self.config.master_doc | |
master_doctree = self.env.get_and_resolve_doctree(master_doc, self) | |
self.write_doc_serialized(master_doc, master_doctree) | |
self.write_doc(master_doc, master_doctree) | |
docnames = self.get_docnames_in_doc(master_doc) | |
for docname in self.app.status_iterator( | |
docnames, 'writing output... ', darkgreen, len(docnames)): | |
doctree, child_docnames = self.assemble_doctree(docname) | |
self.assemble_toc_secnumbers(docname, child_docnames) | |
self.assemble_toc_fignumbers(docname, child_docnames) | |
self.write_doc_serialized(docname, doctree) | |
self.write_doc(docname, doctree) | |
self.info('done') | |
def prepare_writing(self, docnames): | |
self.writer = ShuwaWriter(self) | |
def write_doc(self, docname, doctree): | |
self.current_docname = docname | |
self.secnumbers = self.assembled_secnumbers.get(docname, {}) | |
self.fignumbers = self.assembled_fignumbers.get(docname, {}) | |
self.imgpath = relative_uri(self.get_target_uri(docname), '_images') | |
self.post_process_images(doctree) | |
destination = StringOutput(encoding='utf-8') | |
self.writer.write(doctree, destination) | |
outfilename = self.get_outfilename(docname) | |
ensuredir(os.path.dirname(outfilename)) | |
try: | |
with codecs.open(outfilename, 'w', 'utf-8') as f: | |
f.write(self.writer.output) | |
except (IOError, OSError) as err: | |
self.warn("error writing file %s: %s" % (outfilename, err)) | |
def post_process_images(self, doctree): | |
for node in doctree.traverse(nodes.image): | |
candidate = node['uri'] | |
if candidate not in self.env.images: | |
# non-existing URI; let it alone | |
continue | |
numbers = [] | |
if isinstance(node.parent, nodes.figure): | |
docname = self.get_docname(node) | |
anchor = node.parent['ids'][0] | |
key = (docname, anchor) | |
if key in self.fignumbers.get('figure', {}): | |
numbers = self.fignumbers['figure'][key] | |
numbers = ['%02d' % d for d in numbers] | |
if len(numbers) < 2: | |
numbers.insert(0, re.sub('[/.]', '_', docname)) | |
dest = self.env.images[candidate][1] | |
if numbers: | |
fignum = '-'.join(numbers) | |
dest = fignum + '_' + dest | |
self.images[candidate] = dest | |
def finish(self): | |
self.copy_image_files() | |
return TextBuilder.finish(self) | |
def copy_image_files(self): | |
# copy image files | |
if self.images: | |
ensuredir(os.path.join(self.outdir, '_images')) | |
for src in self.status_iterator(self.images, 'copying images... ', | |
brown, len(self.images)): | |
dest = self.images[src] | |
try: | |
copyfile(os.path.join(self.srcdir, src), | |
os.path.join(self.outdir, '_images', dest)) | |
except Exception, err: | |
self.warn('cannot copy image file %r: %s' % | |
(os.path.join(self.srcdir, src), err)) | |
class TextWrapper(textwrap.TextWrapper): | |
"""Custom subclass that uses a different word separator regex.""" | |
wordsep_re = re.compile( | |
r'(\s+|' # any whitespace | |
r'(?<=\s)(?::[a-z-]+:)?`\S+|' # interpreted text start | |
r'[^\s\w]*\w+[a-zA-Z]-(?=\w+[a-zA-Z])|' # hyphenated words | |
r'(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') # em-dash | |
MAXWIDTH = 70 | |
STDINDENT = 3 | |
def my_wrap(text, width=MAXWIDTH, **kwargs): | |
w = TextWrapper(width=width, **kwargs) | |
return w.wrap(text) | |
class ShuwaWriter(TextWriter): | |
supported = ('text',) | |
settings_spec = ('No options here.', '', ()) | |
settings_defaults = {} | |
output = None | |
def translate(self): | |
visitor = ShuwaTranslator(self.document, self.builder) | |
self.document.walkabout(visitor) | |
self.output = visitor.body | |
class ShuwaTranslator(TextTranslator): | |
def add_line(self, text): | |
if isinstance(text, basestring): | |
text = [text] | |
self.states[-1].append((0, text)) | |
def end_state(self, wrap=True, end=[''], first=None): | |
content = self.states.pop() | |
maxindent = sum(self.stateindent) | |
indent = self.stateindent.pop() | |
result = [] | |
toformat = [] | |
def do_format(): | |
if not toformat: | |
return | |
if wrap: | |
pass | |
#res = my_wrap(''.join(toformat), width=MAXWIDTH-maxindent) | |
#res = convert_for_rst(''.join(toformat), self.builder).splitlines() #NOTE: no-wrap and convert non-literals for shuwa | |
res = ''.join(toformat).splitlines() | |
else: | |
res = ''.join(toformat).splitlines() | |
if end: | |
res += end | |
result.append((indent, res)) | |
for itemindent, item in content: | |
if itemindent == -1: | |
toformat.append(item) | |
else: | |
do_format() | |
result.append((indent + itemindent, item)) | |
toformat = [] | |
do_format() | |
if first is not None and result: | |
itemindent, item = result[0] | |
if item: | |
result.insert(0, (itemindent - indent, [first + item[0]])) | |
result[1] = (itemindent, item[1:]) | |
self.states[-1].extend(result) | |
def get_target_secnumber(self, docname, anchorname): | |
secnumbers = self.builder.env.toc_secnumbers.get(docname, {}) | |
if anchorname not in secnumbers: | |
anchorname = '' # try first heading which has no anchor | |
if secnumbers.get(anchorname): | |
return secnumbers[anchorname] | |
return None | |
def get_secnumber(self, node): | |
if node.get('secnumber'): | |
return '.'.join(map(text_type, node['secnumber'])) | |
docname = self.builder.get_docname(node) | |
anchorname = '#' + node.parent['ids'][0] | |
id = (docname, anchorname) | |
if id not in self.builder.secnumbers: | |
id = (docname, '') # try first heading which has no anchor | |
if self.builder.secnumbers.get(id): | |
numbers = self.builder.secnumbers[id] | |
return '.'.join(map(text_type, numbers)) | |
return '' | |
def get_fignumber(self, node): | |
def append_fignumber(figtype, figure_id): | |
docname = self.builder.get_docname(node) | |
key = (docname, figure_id) | |
if key in self.builder.fignumbers.get(figtype, {}): | |
prefix = self.builder.config.numfig_format.get(figtype, '') | |
numbers = self.builder.fignumbers[figtype][key] | |
return prefix % '.'.join(map(text_type, numbers)) + ' ' | |
return '' | |
if isinstance(node.parent, nodes.figure): | |
return append_fignumber('figure', node.parent['ids'][0]) | |
elif isinstance(node.parent, nodes.table): | |
return append_fignumber('table', node.parent['ids'][0]) | |
elif isinstance(node.parent, nodes.container): | |
return append_fignumber('code-block', node.parent['ids'][0]) | |
return '' | |
def visit_start_of_file(self, node): | |
pass | |
def depart_start_of_file(self, node): | |
pass | |
def depart_document(self, node): | |
self.end_state() | |
self.body = '\n'.join(line and (' '*indent + line) | |
for indent, lines in self.states[0] | |
for line in lines) | |
self.body = re.sub('\n{3,10}', '\n\n', self.body) | |
# XXX header/footer? | |
def visit_topic(self, node): | |
if 'contents' in node['classes']: | |
raise nodes.SkipChildren | |
self.new_state(0) | |
def depart_topic(self, node): | |
if 'contents' not in node['classes']: | |
self.end_state() | |
def visit_title(self, node): | |
if isinstance(node.parent, (nodes.Admonition, nodes.table)): | |
text = node.astext() | |
text = convert_for_rst(text, self.builder) | |
self.add_text(text) | |
raise nodes.SkipNode | |
self.new_state(0) | |
def depart_title(self, node): | |
headings = {1:u'■■■■■', 2:u'■■■■', 3:u'■■■', 4:u'■■', 5:u'■'} | |
heading = headings.get(self.sectionlevel, '') | |
text = ''.join(x[1] for x in self.states.pop() if x[0] == -1) | |
# split "2.3.1 hogehoge" into ("2.3.1", "hogehoge") | |
secnum = self.get_secnumber(node) | |
if secnum: | |
# 1-15章 | |
title = text | |
numbers = secnum.strip() | |
chapter = 'Chapter' | |
match = 1 #dummy flag | |
else: | |
match = re.match(ur'(Appendix\s+)?([A-Z\d\.][\d\.]*)[:\s]+(.*)$', text) | |
if match: | |
# Appendix章 | |
_, numbers, title = match.groups() | |
chapter = 'Appendix' | |
if match: | |
# convert numbers from '2.3.1' to ['2', '3', '1'] | |
numbers = [x for x in re.split(r'\.', numbers)] | |
# convert chapter title | |
if self.sectionlevel == 1: | |
title = title.lstrip(u'章').lstrip(':').strip() | |
title = '%(chapter)s %(secnum)s\t' + title | |
secnum = numbers[0] | |
else: | |
title = '%(secnum)s\t' + title.strip() | |
secnum = format_section_number(numbers) | |
#re concatinate | |
text = title % locals() | |
# 前の行が空行でないなら | |
if self.states[-1] and self.states[-1][-1] != (0, ['']): | |
self.add_line('') | |
self.stateindent.pop() | |
self.add_line(heading + text) | |
def visit_figure(self, node): | |
self.new_state(0) | |
def depart_figure(self, node): | |
self.end_state() | |
def visit_caption(self, node): | |
if isinstance(node.parent, nodes.figure): | |
self.add_text(u'▲' + self.get_fignumber(node)) | |
elif isinstance(node.parent, nodes.container): | |
try: | |
next_node = node.parent[node.parent.index(node)+1] | |
except IndexError: | |
next_node = None | |
if isinstance(next_node, nodes.literal_block): | |
next_node['caption'] = self.get_fignumber(node) + node.next_node().astext() | |
raise nodes.SkipChildren | |
def depart_caption(self, node): | |
if isinstance(node.parent, nodes.figure): | |
self.add_text(u'▲') | |
def visit_seealso(self, node): | |
if isinstance(node[0], nodes.title): | |
del node[0] | |
self.new_state(0) | |
self.add_line(u'▽●●●●●') | |
def depart_seealso(self, node): | |
self.add_line([u'△●●●●●', '']) | |
self.end_state(first=u'\n', end=[]) | |
def visit_option_list(self, node): | |
self.add_line(['']) | |
self.new_state(0) | |
self.add_line(u'▽●●●●●●') | |
def depart_option_list(self, node): | |
self.add_line([u'△●●●●●●']) | |
self.end_state(end=[]) | |
self.add_line(['']) | |
def visit_option_list_item(self, node): | |
self.new_state(0) | |
def depart_option_list_item(self, node): | |
self.end_state(end=[], first=u'□') | |
def visit_option_group(self, node): | |
self._firstoption = True | |
def depart_option_group(self, node): | |
pass | |
def visit_option(self, node): | |
if self._firstoption: | |
self._firstoption = False | |
else: | |
self.add_text(', ') | |
def depart_option(self, node): | |
pass | |
def visit_option_string(self, node): | |
self.add_text(u'☆') | |
def depart_option_string(self, node): | |
self.add_text(u'☆') | |
def visit_table(self, node): | |
if self.table: | |
raise NotImplementedError('Nested tables are not supported.') | |
self.add_line(['']) | |
self.new_state(0) | |
self.add_text(u'▽●●●') | |
self.table = [[]] | |
def depart_table(self, node): | |
lines = self.table[1:] | |
prev_line = None | |
for line in lines: | |
if line == 'sep': | |
if prev_line and prev_line != line: | |
self.add_line('') | |
else: | |
# line = ['col1', 'col2-line1\ncol2-line2', 'col3'] | |
# add line as: | |
# 'col1\tcol2-line1\tcol3\n' | |
# '\tcol2-line1\t\n' | |
for cols in izip_longest(*[l.split('\n') for l in line], fillvalue=''): | |
value = '\t'.join(c.strip() for c in cols) | |
if value.strip(): # skip empty/tab-onlye line | |
self.add_line(value) | |
prev_line = line | |
self.table = None | |
self.add_line(u'△●●●') | |
self.end_state(wrap=False, end=None) | |
self.add_line(['']) | |
def visit_image(self, node): | |
olduri = node['uri'] | |
# rewrite the URI if the environment knows about it | |
if olduri in self.builder.images: | |
node['uri'] = posixpath.join(self.builder.imgpath, | |
self.builder.images[olduri]) | |
newuri = node['uri'] | |
if newuri.startswith(self.builder.outdir): | |
newuri = newuri[len(self.builder.outdir):] | |
else: | |
newuri = posixpath.join('_images', os.path.basename(olduri)) | |
self.add_line(['', ('[image: %s]' % newuri)]) | |
raise nodes.SkipNode | |
def visit_bullet_list(self, node): | |
self.list_counter.append(-1) | |
# 前の行が空行でないなら | |
if self.states[-1] and self.states[-1][-1] != (0, ['']): | |
self.add_line('') | |
self.add_line(u'▽◆') | |
def depart_bullet_list(self, node): | |
self.add_line([u'△◆', '']) | |
self.list_counter.pop() | |
def visit_enumerated_list(self, node): | |
self.list_counter.append(0) | |
self.add_line(u'▽◆') | |
def depart_enumerated_list(self, node): | |
self.add_text(u'△◆') | |
self.list_counter.pop() | |
def visit_definition_list(self, node): | |
self.add_line(['']) | |
self.new_state(0) | |
self.add_line(u'▽●●●●●●') | |
def depart_definition_list(self, node): | |
self.add_line([u'△●●●●●●']) | |
self.end_state(end=[]) | |
self.add_line(['']) | |
def visit_list_item(self, node): | |
if self.list_counter[-1] == -1: | |
# bullet list | |
self.new_state(0) | |
elif self.list_counter[-1] == -2: | |
# definition list | |
pass | |
else: | |
# enumerated list | |
self.list_counter[-1] += 1 | |
#self.new_state(len(text_type(self.list_counter[-1])) + 2) | |
self.new_state(0) | |
def depart_list_item(self, node): | |
if self.list_counter[-1] == -1: | |
self.end_state(first=u'・', end=None) | |
elif self.list_counter[-1] == -2: | |
pass | |
else: | |
level = len(self.list_counter) - 1 | |
if level == 0: | |
n = unichr(ord(u'①') - 1 + self.list_counter[-1]) | |
elif level > 0: | |
n = u'(%d)' % self.list_counter[-1] | |
padding = '\t' * level | |
self.end_state(first=u'%s%s ' % (padding, n), end=None) | |
def visit_term(self, node): | |
self.new_state(0) | |
def depart_term(self, node): | |
if not self._li_has_classifier: | |
self.end_state(end=[], first=u'□') | |
def visit_classifier(self, node): | |
self.add_text(u'(') | |
def depart_classifier(self, node): | |
self.add_text(u')') | |
self.end_state(end=None, first=u'□') | |
def visit_definition(self, node): | |
self.new_state(0) | |
def depart_definition(self, node): | |
self.end_state() | |
def visit_admonition(self, node): | |
self.add_line(['']) | |
self.new_state(0) | |
if node.tagname == 'todo_node': | |
node.children[:] = [] #NOTE: remove todo block | |
elif 'name' in node.attributes: | |
# column, note | |
name = node.attributes['name'] | |
labels = admonition_labels.get(name, ('', '')) | |
self.add_text(labels[0]) | |
def depart_admonition(self, node): | |
if 'name' in node.attributes: | |
name = node.attributes['name'] | |
labels = admonition_labels.get(name, ('', '')) | |
self.add_text(labels[1]) | |
self.end_state(end=[]) | |
self.add_line(['']) | |
def _make_admonition(name): | |
#name = admonitionlabels.get(name, name) | |
def visit_admonition(self, node): | |
self.new_state(0) | |
self.add_line(['', u'▽●●' + name]) | |
def depart_admonition(self, node): | |
self.add_text(u'△●●') | |
self.end_state() | |
return visit_admonition, depart_admonition | |
visit_hint, depart_hint = _make_admonition(u'note') | |
visit_tip, depart_tip = _make_admonition(u'note') | |
visit_note, depart_note = _make_admonition(u'note') | |
def visit_literal_block(self, node): | |
if 'caption' in node: | |
line = node['caption'] | |
else: | |
line = '' | |
# 前の行が空行でないなら | |
if self.states[-1] and self.states[-1][-1] != (0, ['']): | |
self.add_line('') | |
self.new_state(0) | |
self.add_line(u'▽●●●●' + line) | |
def depart_literal_block(self, node): | |
self.add_line([u'△●●●●', '']) | |
self.end_state(wrap=False, end=[]) | |
def visit_block_quote(self, node): | |
raise NotImplementedError('blockquote') | |
def depart_block_quote(self, node): | |
raise NotImplementedError('blockquote') | |
def visit_paragraph(self, node): | |
self.new_state(0) | |
def depart_paragraph(self, node): | |
if isinstance(node.parent, nodes.list_item): | |
if node.parent.next_node() == node: | |
self.end_state(end=[], first=u'') | |
else: | |
self.end_state(end=[], first=u' ') | |
elif isinstance(node.parent, nodes.Admonition): | |
self.end_state(end=[], first=u' ') | |
elif isinstance(node.parent, nodes.entry): | |
self.end_state(end=[], first=u'') | |
else: | |
self.end_state(end=[], first=u' ') | |
def visit_reference(self, node): | |
if node.get('secnumber'): | |
#self.add_text('.'.join(map(text_type, node['secnumber'])) + ' ') | |
pass | |
elif node.get('internal') and node.get('refuri'): | |
# pass # 他のページに繋がってるノードはここに来ない | |
refuri = node['refuri'] | |
if '#' in refuri: | |
docname, anchorname = refuri.split('#', 1) | |
anchorname = '#' + anchorname | |
else: | |
docname = refuri | |
anchorname = '' | |
if docname: | |
node['secnumber'] = self.get_target_secnumber(docname, anchorname) | |
def depart_reference(self, node): | |
pass | |
def visit_number_reference(self, node): | |
self.visit_reference(node) | |
def depart_number_reference(self, node): | |
self.depart_reference(node) | |
def visit_emphasis(self, node): | |
self.add_text(u'☆') # :ref:`lets-start-python` -> ☆第1章...☆ | |
if isinstance(node.parent, nodes.reference): | |
secnum = None | |
if node.parent.get('secnumber'): | |
secnum = node.parent['secnumber'] | |
elif node.parent.get('refid'): | |
secnum = self.get_target_secnumber(self.document['docname'], | |
'#'+node.parent['refid']) | |
if secnum and not isinstance(node.parent, addnodes.number_reference): | |
if len(secnum) == 1: | |
self.add_text(u'第%s章 ' % secnum) | |
else: # len(secnum) > 1 | |
self.add_text(format_section_number(secnum) + u' ') | |
def depart_emphasis(self, node): | |
self.add_text(u'☆') | |
def visit_literal_emphasis(self, node): | |
self.add_text(u'※') | |
def depart_literal_emphasis(self, node): | |
self.add_text(u'※') | |
def visit_strong(self, node): | |
self.add_text(u'★') # **foo** -> ★foo★ | |
def depart_strong(self, node): | |
self.add_text(u'★') | |
def visit_literal_strong(self, node): | |
self.add_text(u'※') | |
def depart_literal_strong(self, node): | |
self.add_text(u'※') | |
def visit_abbreviation(self, node): | |
#self.add_text('') | |
pass | |
def depart_abbreviation(self, node): | |
if node.hasattr('explanation'): | |
self.add_text(u'(%s)' % node['explanation']) | |
def visit_title_reference(self, node): | |
self.add_text(u'☆') # `foo` -> ☆foo☆ | |
def depart_title_reference(self, node): | |
self.add_text(u'☆') | |
def visit_literal(self, node): | |
self.add_text(u'※') # ``foo`` -> ※foo※ | |
def depart_literal(self, node): | |
self.add_text(u'※') | |
def visit_Text(self, node): | |
text = node.astext().strip() | |
if (isinstance(node.parent, nodes.reference) # 親ノードがref | |
and not node.parent.get('internal') # refはページ内リンクではない | |
and re.match('^https?://', node.parent.get('refuri', '')) # refはURL | |
): | |
if node.parent['refuri'] != text: # textはURL以外の文字列 | |
# URLを脚注にする | |
text = u'%s◆◆%s◆◆' % (text, node.parent['refuri']) | |
else: | |
# URLを埋め込みリンクにする | |
text = u'◆%s◆' % text | |
if not isinstance(node.parent, (nodes.literal, nodes.literal_block)): | |
#NOTE: no-wrap and convert non-literals for shuwa | |
text = convert_for_rst(text, self.builder) | |
self.add_text(text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment