summaryrefslogtreecommitdiff
path: root/elpa/evil-1.15.0/doc/source/_ext/elisp.py
diff options
context:
space:
mode:
authorthing1 <thing1@seacrossedlovers.xyz>2025-04-01 18:10:15 +0000
committerthing1 <thing1@seacrossedlovers.xyz>2025-04-01 18:10:15 +0000
commitdabaff03992c102c395314629f63ce93a2c1bd3a (patch)
tree990472507186637085165b7cbbf7abf15c10889a /elpa/evil-1.15.0/doc/source/_ext/elisp.py
init commit
Diffstat (limited to 'elpa/evil-1.15.0/doc/source/_ext/elisp.py')
-rw-r--r--elpa/evil-1.15.0/doc/source/_ext/elisp.py309
1 files changed, 309 insertions, 0 deletions
diff --git a/elpa/evil-1.15.0/doc/source/_ext/elisp.py b/elpa/evil-1.15.0/doc/source/_ext/elisp.py
new file mode 100644
index 0000000..924d026
--- /dev/null
+++ b/elpa/evil-1.15.0/doc/source/_ext/elisp.py
@@ -0,0 +1,309 @@
+import re
+from os import path
+import json
+
+from docutils import nodes
+from docutils.parsers.rst import Directive
+
+from sphinx import addnodes
+from sphinx.domains import Domain, ObjType, Index
+from sphinx.domains.std import StandardDomain
+from sphinx.directives import ObjectDescription
+from sphinx.roles import XRefRole
+from sphinx.util.docfields import Field
+from sphinx.util.nodes import make_refnode
+
+
+with open(path.join(path.dirname(__file__), '..', '..', 'docstringdb.json')) as f:
+ DATA = json.load(f)
+
+
+re_evilcode = re.compile(r"`(evil-[^']*)'")
+re_code = re.compile(r"`([^:][^ ']*)'")
+re_kwd = re.compile(r"`(:[^']*)'")
+re_item = re.compile(r"([^\n])\n- ")
+re_sexp = re.compile(r"\([A-Z \-\.'`\[\]]+\)|[A-Z\-]+")
+re_capitals = re.compile(r"[A-Z\-]+")
+re_nonspace = re.compile(r"[^ ]")
+re_signature = re.compile(r'\(fn (.*)\)')
+re_keymap_or_kbd = re.compile(r"\\[\[<]([^\]>]*)[\]>]")
+
+emphasis = [
+ 'thing-at-point',
+]
+
+def emacs_is_local(var):
+ return DATA[var]['local']
+
+def emacs_default_value(var):
+ default = DATA[var]['default']
+ tp = DATA[var]['default-type']
+ if tp == 'string':
+ rep = repr(default)[1:-1]
+ return f'"{rep}"'
+ return str(default)
+
+def process_docstring(docstring, capitals=None):
+ # Remove explicit signature
+ docstring = re_signature.sub('', docstring)
+
+ # Add code blocks to indented sections
+ def blockified_lines(lines):
+ in_block = False
+ for line in lines:
+ try:
+ indented = next(re_nonspace.finditer(line)).start(0) > 3
+ except StopIteration:
+ indented = None
+ if indented is True and not in_block:
+ yield '.. code-block:: elisp'
+ yield ''
+ in_block = True
+ elif indented is False:
+ in_block = False
+ yield line
+ docstring = '\n'.join(blockified_lines(docstring.split('\n')))
+
+ # Substitute `evil-alpha' with :elisp:ref:`evil-alpha`
+ docstring = re_evilcode.sub(r':elisp:ref:`\1`', docstring)
+
+ # Substitute `alpha' with ``alpha``
+ docstring = re_code.sub(r'``\1``', docstring)
+
+ # Substitute `:alpha' with ``alpha``
+ docstring = re_kwd.sub(r'``\1``', docstring)
+
+ # Translate key bindings
+ keymap = None
+ def substitute_binding(match):
+ nonlocal keymap
+ if match.group(0)[1] == '<':
+ keymap = match.group(1)
+ return ''
+ if keymap is None:
+ print(docstring)
+ assert False
+ return '???'
+ key = DATA[keymap]['keymap-inv'][match.group(1)]
+ return f':kbd:`{key}`'
+ docstring = re_keymap_or_kbd.sub(substitute_binding, docstring)
+
+ # Add empty line between list items
+ docstring = re_item.sub(r'\1\n\n- ', docstring)
+
+ if capitals is None:
+ capitals = []
+ else:
+ capitals = list(capitals)
+
+ # Find things that look like sexps
+ def substitute_sexp(match):
+ s = match.group(0)
+ if re_capitals.match(s):
+ if s in capitals:
+ return f'*{s}*'
+ return s
+ else:
+ capitals.extend(re_capitals.findall(s))
+ return f'``{s}``'
+ docstring = re_sexp.sub(substitute_sexp, docstring)
+
+ # Italicize some words
+ for s in emphasis:
+ docstring = docstring.replace(s, f'*{s}*')
+
+ return docstring
+
+def emacs_variable_docstring(var):
+ docstring = DATA[var]['var-docstring']
+ return process_docstring(docstring)
+
+def emacs_function_docstring(var):
+ docstring = DATA[var]['fn-docstring']
+ return process_docstring(docstring, capitals=emacs_argnames(var))
+
+def emacs_argnames(var):
+ arglist = emacs_arglist(var)
+ return re_capitals.findall(arglist)
+
+def emacs_arglist(var):
+ docstring = DATA[var]['fn-docstring']
+ match = re_signature.search(docstring)
+ if match:
+ return match.group(1)
+
+ arglist = [arg.upper() for arg in DATA[var]['arglist']]
+ state = None
+ ret = ''
+ for arg in arglist:
+ if arg in ('&REST', '&OPTIONAL'):
+ if state == '&OPTIONAL':
+ ret += ']'
+ state = arg
+ ret += ' ['
+ continue
+ ret += ('' if state in ('&REST', '&OPTIONAL') else ' ') + arg
+ if state == '&OPTIONAL':
+ state += '-CONT'
+ if state is not None and state.startswith('&OPTIONAL'):
+ ret += ']'
+ if state == '&REST':
+ ret += '...]'
+ return ret
+
+
+class AbstractElisp(ObjectDescription):
+
+ def add_target_and_index(self, name, sig, signode):
+ anchor = f'elispobj-{sig}'
+ signode['ids'].append(anchor)
+
+ objs = self.env.domaindata['elisp']['objects']
+ objs[sig] = {
+ 'docname': self.env.docname,
+ 'anchor': f'elispobj-{sig}',
+ 'type': self.object_type,
+ }
+
+
+class AbstractVariable(AbstractElisp):
+ object_type = 'variable'
+
+ def handle_signature(self, sig, signode):
+ signode += addnodes.desc_annotation(sig, sig)
+ return sig
+
+ def run(self):
+ extra = []
+
+ default = self.default_value()
+ if default:
+ extra.append(f'Default: ``{default}``')
+ if self.is_buffer_local():
+ extra.append('buffer-local')
+
+ self.content.data.extend(['', ', '.join(extra)])
+ retval = super().run()
+ return retval
+
+
+class Variable(AbstractVariable):
+ required_arguments = 1
+ optional_arguments = 2
+
+ def default_value(self):
+ try:
+ return self.arguments[1]
+ except IndexError:
+ return None
+
+ def is_buffer_local(self):
+ return 'bufloc' in self.arguments[1:]
+
+
+class AutoVariable(AbstractVariable):
+ required_arguments = 1
+
+ def is_buffer_local(self):
+ return emacs_is_local(self.arguments[0])
+
+ def default_value(self):
+ return emacs_default_value(self.arguments[0])
+
+ def run(self):
+ docstring = emacs_variable_docstring(self.arguments[0])
+ self.content.data.extend(docstring.split('\n'))
+ return super().run()
+
+
+class AutoFunction(AbstractElisp):
+ required_arguments = 1
+
+ @property
+ def object_type(self):
+ return 'macro' if DATA[self.arguments[0]]['macrop'] else 'function'
+
+ def handle_signature(self, sig, signode):
+ args = emacs_arglist(sig)
+ signode += addnodes.desc_annotation(sig, f'({sig} {args})')
+ return sig
+
+ def run(self):
+ docstring = emacs_function_docstring(self.arguments[0])
+ self.content.data.extend(docstring.split('\n'))
+ return super().run()
+
+
+class ElispIndex(Index):
+ name = 'index'
+ localname = 'Emacs lisp functions and variables'
+ shortname = 'Elisp'
+
+ def generate(self, docnames=None):
+ index = {}
+ for name, item in self.domain.data['objects'].items():
+ if name.startswith('evil-'):
+ letter = name[5].upper()
+ else:
+ letter = name[0].upper()
+ index.setdefault(letter, []).append((
+ name,
+ 0,
+ item['docname'],
+ item['anchor'],
+ item['type'],
+ '',
+ '',
+ ))
+
+ index = {k: sorted(v, key=lambda k: k[0].lower()) for k, v in index.items()}
+ index = list(index.items())
+ index = sorted(index, key=lambda k: k[0])
+ return index, True
+
+
+class Elisp(Domain):
+ name = 'elisp'
+ label = 'Emacs lisp'
+
+ object_types = {
+ 'variable': ObjType('variable', 'variable', 'obj'),
+ 'autovariable': ObjType('autovariable', 'autovariable', 'obj'),
+ 'autofunction': ObjType('autofunction', 'autofunction', 'obj'),
+ }
+
+ directives = {
+ 'variable': Variable,
+ 'autovariable': AutoVariable,
+ 'autofunction': AutoFunction,
+ }
+
+ roles = {
+ 'ref': XRefRole(),
+ }
+
+ initial_data = {
+ 'objects': {},
+ }
+
+ indices = {
+ ElispIndex,
+ }
+
+ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
+ obj = self.data['objects'].get(target, None)
+ if obj is None:
+ return None
+ return make_refnode(builder, fromdocname, obj['docname'], obj['anchor'], contnode, obj['anchor'])
+
+
+def setup(app):
+ app.add_domain(Elisp)
+ StandardDomain.initial_data['labels']['elispindex'] = ('elisp-index', '', 'Emacs lisp functions and variables')
+ StandardDomain.initial_data['anonlabels']['elispindex'] = ('elisp-index', '')
+
+ return {
+ 'version': '0.1',
+ 'parallel_read_safe': True,
+ 'parallel_write_safe': True,
+ }