Skip to content

Commit 2275c97

Browse files
committed
Add go domain to sphinx docs build with function, type and method directives
1 parent 03d019d commit 2275c97

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed

edb/tools/docs/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from . import js
3131
from . import sdl
3232
from . import graphql
33+
from . import go
3334
from . import shared
3435

3536

@@ -119,6 +120,7 @@ def setup(app):
119120
js.setup_domain(app)
120121
sdl.setup_domain(app)
121122
graphql.setup_domain(app)
123+
go.setup_domain(app)
122124

123125
app.add_directive('versionadded', VersionAdded, True)
124126
app.add_directive('versionchanged', VersionChanged, True)

edb/tools/docs/go.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#
2+
# This source file is part of the EdgeDB open source project.
3+
#
4+
# Copyright 2018-present MagicStack Inc. and the EdgeDB authors.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
20+
from __future__ import annotations
21+
22+
import re
23+
24+
from typing import Any, Dict
25+
26+
from docutils import nodes as d_nodes
27+
28+
from sphinx import addnodes as s_nodes
29+
from sphinx import directives as s_directives
30+
from sphinx import domains as s_domains
31+
32+
33+
class BaseGoDirective(s_directives.ObjectDescription):
34+
35+
def get_signatures(self):
36+
return [re.compile(r'\\\s*\n').sub('\n', self.arguments[0])]
37+
38+
def add_target_and_index(self, name, sig, signode):
39+
target = name.replace(' ', '-')
40+
41+
if target in self.state.document.ids:
42+
raise self.error(
43+
f'duplicate {self.objtype} {name} description')
44+
45+
signode['names'].append(target)
46+
signode['ids'].append(target)
47+
self.state.document.note_explicit_target(signode)
48+
49+
objects = self.env.domaindata['go']['objects']
50+
51+
if target in objects:
52+
raise self.error(
53+
f'duplicate {self.objtype} {name} description')
54+
objects[target] = (self.env.docname, self.objtype)
55+
56+
57+
class GoTypeDirective(BaseGoDirective):
58+
59+
def handle_signature(self, sig, signode):
60+
name = re.split(r'\s+', sig)[1].strip()
61+
62+
signode['name'] = name
63+
signode['fullname'] = name
64+
65+
signode['is_multiline'] = True
66+
signode += [
67+
s_nodes.desc_signature_line(sig, line)
68+
for line in sig.split('\n')
69+
]
70+
71+
return name
72+
73+
def add_target_and_index(self, name, sig, signode):
74+
return super().add_target_and_index(name, sig, signode)
75+
76+
77+
goFuncRegex = re.compile(
78+
r"func\s+(?:\(.+?\s+\*?(?P<receiver>.+?)\)\s+)?(?P<name>.+?)\s*\(")
79+
80+
81+
class GoFunctionDirective(BaseGoDirective):
82+
83+
def handle_signature(self, sig, signode):
84+
match = goFuncRegex.match(sig)
85+
if match is None:
86+
raise self.error(f'could not parse go func signature: {sig!r}')
87+
88+
signode['fullname'] = fullname = (
89+
f"{match.group('receiver')}.{match.group('name')}"
90+
if match.group('receiver')
91+
else match.group('name')
92+
)
93+
signode['name'] = match.group('name')
94+
95+
signode['is_multiline'] = True
96+
signode += [
97+
s_nodes.desc_signature_line(sig, line)
98+
for line in sig.split('\n')
99+
]
100+
101+
return fullname
102+
103+
def add_target_and_index(self, name, sig, signode):
104+
return super().add_target_and_index(name, sig, signode)
105+
106+
107+
class GoMethodDirective(GoFunctionDirective):
108+
pass
109+
110+
111+
class GolangDomain(s_domains.Domain):
112+
113+
name = "go"
114+
label = "Golang"
115+
116+
object_types = {
117+
'function': s_domains.ObjType('function'),
118+
'type': s_domains.ObjType('type'),
119+
}
120+
121+
directives = {
122+
'function': GoFunctionDirective,
123+
'type': GoTypeDirective,
124+
'method': GoMethodDirective,
125+
}
126+
127+
initial_data: Dict[str, Dict[str, Any]] = {
128+
'objects': {} # fullname -> docname, objtype
129+
}
130+
131+
def clear_doc(self, docname):
132+
for fullname, (fn, _l) in list(self.data['objects'].items()):
133+
if fn == docname:
134+
del self.data['objects'][fullname]
135+
136+
def merge_domaindata(self, docnames, otherdata):
137+
for fullname, (fn, objtype) in otherdata['objects'].items():
138+
if fn in docnames:
139+
self.data['objects'][fullname] = (fn, objtype)
140+
141+
def get_objects(self):
142+
for refname, (docname, type) in self.data['objects'].items():
143+
yield (refname, refname, type, docname, refname, 1)
144+
145+
def get_full_qualified_name(self, node):
146+
fn = node.get('fullname')
147+
if not fn:
148+
raise self.error('no fullname attribute')
149+
return fn
150+
151+
def setup_domain(app):
152+
app.add_domain(GolangDomain)
153+
154+
def setup(app):
155+
setup_domain(app)

0 commit comments

Comments
 (0)