Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use native php naming #61

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ PHP Domain supports following objects:

.. note::

This domain expresses methods and attribute names like this::
This domain expresses methods and properties like this::

Class::method_name
Class::$attribute_name
Class::$prop_name

You address classes/functions in namespaces using \\ syntax as you would in PHP::

Expand Down
42 changes: 13 additions & 29 deletions doc/reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,6 @@ Each directive populates the index, and or the namespace index.

This directive declares a new PHP constant, you can also used it nested
inside a class directive to create class constants.

.. rst:directive:: .. php:exception:: name

This directive declares a new Exception in the current namespace. The
signature can include constructor arguments.

.. rst:directive:: .. php:interface:: name

Expand Down Expand Up @@ -108,7 +103,7 @@ Each directive populates the index, and or the namespace index.

.. rst:directive:: .. php:class:: name

Describes a class. Methods, attributes, and constants belonging to the class
Describes a class. Methods, properties, and constants belonging to the class
should be inside this directive's body::

.. php:class:: MyClass
Expand All @@ -120,7 +115,7 @@ Each directive populates the index, and or the namespace index.
Method description


Attributes, methods and constants don't need to be nested. They can also just
Properties, methods and constants don't need to be nested. They can also just
follow the class declaration::

.. php:class:: MyClass
Expand All @@ -133,7 +128,7 @@ Each directive populates the index, and or the namespace index.


.. seealso:: :rst:dir:`php:method`
:rst:dir:`php:attr`
:rst:dir:`php:property`
:rst:dir:`php:const`

.. rst:directive:: .. php:method:: name(signature)
Expand All @@ -150,29 +145,24 @@ Each directive populates the index, and or the namespace index.

This is an instance method.

.. rst:directive:: .. php:staticmethod:: ClassName::methodName(signature)

Describe a static method, its arguments, return value and exceptions,
see :rst:dir:`php:method` for options.
.. rst:directive:: .. php:property:: name

.. rst:directive:: .. php:attr:: name

Describe an property/attribute on a class.
Describe a property on a class.

Cross Referencing
=================

The following roles refer to php objects and are links are generated if a
matching directive is found:

.. rst:role:: php:ns
.. rst:role:: php:namespace

Reference a namespace. Nested namespaces need to be separated by two \\ due
to the syntax of ReST::

.. php:ns:`LibraryName\\SubPackage` will work correctly.
.. php:namespace:`LibraryName\\SubPackage` will work correctly.

.. rst:role:: php:func
.. rst:role:: php:function

Reference a PHP function either in a namespace or out. If the function is in
a namespace, be sure to include the namespace, unless you are currently
Expand All @@ -196,23 +186,17 @@ matching directive is found:

:php:class:`LibraryName\\ClassName`

.. rst:role:: php:meth
.. rst:role:: php:method

Reference a method of a class/interface/trait. This role supports
both kinds of methods::
Reference a method of a class/interface/trait::

:php:meth:`DateTime::setDate`
:php:meth:`Classname::staticMethod`
:php:method:`DateTime::setDate`

.. rst:role:: php:attr
.. rst:role:: php:property

Reference a property on an object::

:php:attr:`ClassName::$propertyName`

.. rst:role:: php:exc

Reference an exception. A namespaced name may be used.
:php:property:`ClassName::$propertyName`

.. rst:role:: php:interface

Expand Down
4 changes: 2 additions & 2 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,10 @@ From other place, you can create cross reference like that:

.. code:: rst

You can modify a DateTime's date using :php:meth:`DateTime::setDate`.
You can modify a DateTime's date using :php:method:`DateTime::setDate`.

Result
-----------

You can modify a DateTime's date using :php:meth:`DateTime::setDate`.
You can modify a DateTime's date using :php:method:`DateTime::setDate`.

149 changes: 100 additions & 49 deletions sphinxcontrib/phpdomain.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def throw_if_false(fromdocnode, value, message: str):
"exception": None,
"method": "::",
"const": "::",
"property": "::$",
"attr": "::$",
"staticmethod": "::",
"case": "::",
Expand Down Expand Up @@ -218,48 +219,81 @@ def handle_signature(self, sig, signode):
if m is None:
throw_if_false(signode, False, "Invalid signature")

visibility, modifiers, name_prefix, name, arglist, retann, enumtype = m.groups()
visibility, modifiers, classname, name, arglist, retann, enumtype = m.groups()

if not name_prefix:
name_prefix = ""

# determine namespace and class name (if applicable), as well as full name
namespace = self.options.get(
# parse & resolve classname and name
env_namespace = self.options.get(
"namespace", self.env.temp_data.get("php:namespace")
)
env_class = self.env.temp_data.get("php:class")
separator = separators[self.objtype]

if "::" in name_prefix:
classname = name_prefix.rstrip("::")
if (
self.objtype == "const"
and not classname
and (not env_class or name.startswith(NS))
):
separator = None
type_in_class = separator != None

if not classname:
# throw_if_false(signode, not name.startswith('$'))
if name.startswith("$"):
name = name[1:]
if type_in_class:
throw_if_false(signode, env_class, "In-class type requires class")
classname = NS + env_class
else:
classname = name
name = None
else:
classname = self.env.temp_data.get("php:class")
throw_if_false(
signode, type_in_class, "Unexpected name in non in-class type"
)
throw_if_false(
signode,
classname.endswith("::"),
"Separator between class and name is required",
)
classname = classname[:-2]
# throw_if_false(signode, name.startswith('$') == (separator and separator.endswith('$'))) # not strictly needed
if name.startswith("$"):
name = name[1:]

if self.objtype == "global":
namespace = None
name = "$" + classname
classname = None
elif classname.startswith(NS):
classname = classname[1:]
elif env_namespace:
classname = env_namespace + NS + classname

if not type_in_class and self.objtype != "global":
name = classname.split(NS)[-1]
classname = ""
elif classname and env_namespace and classname.startswith(env_namespace + NS):
classname = classname[len(env_namespace + NS) :]

if not classname:
fullname = name
elif not name:
fullname = classname
else:
if name_prefix:
fullname = name_prefix + name

# Currently in a class, but not creating another class,
elif classname and not self.objtype in [
"class",
"exception",
"interface",
"trait",
"enum",
"function",
]:
if not self.env.temp_data["php:in_class"]:
name_prefix = classname + separator

fullname = classname + separator + name
fullname = classname + separator + name

name_prefix = classname
if not name_prefix:
name_prefix = None
# elif type_in_class and not self.env.temp_data['php:in_class']:
elif type_in_class:
if not self.env.temp_data.get("php:in_class", False):
name_prefix = name_prefix + separator
else:
classname = ""
fullname = name
name_prefix = None

print([env_namespace, classname, name, fullname, name_prefix])
print()

signode["namespace"] = namespace
signode["namespace"] = env_namespace
signode["class"] = self.class_name = classname
signode["fullname"] = fullname

Expand All @@ -275,16 +309,16 @@ def handle_signature(self, sig, signode):
signode += addnodes.desc_annotation(sig_prefix, sig_prefix)

if name_prefix:
if namespace and not self.env.temp_data["php:in_class"]:
name_prefix = namespace + NS + name_prefix
if env_namespace and not self.env.temp_data["php:in_class"]:
name_prefix = env_namespace + NS + name_prefix
signode += addnodes.desc_addname(name_prefix, name_prefix)

elif (
namespace
env_namespace
and not self.env.temp_data.get("php:in_class", False)
and self.env.config.add_module_names
):
nodetext = namespace + NS
nodetext = env_namespace + NS
signode += addnodes.desc_addname(nodetext, nodetext)

signode += addnodes.desc_name(name, name)
Expand Down Expand Up @@ -334,7 +368,8 @@ def _toc_entry_name(self, sig_node: addnodes.desc_signature) -> str:
return name + parens
if config.toc_object_entries_show_parents == "all":
if (
objtype in {"method", "const", "attr", "staticmethod", "case"}
objtype
in {"method", "const", "property", "attr", "staticmethod", "case"}
and len(parents) > 0
):
name = parents.pop() + "::" + name
Expand All @@ -348,7 +383,11 @@ def get_index_text(self, namespace, name):
raise NotImplementedError("must be implemented in subclasses")

def _is_class_member(self):
return self.objtype.startswith("method") or self.objtype.startswith("attr")
return (
self.objtype.startswith("method")
or self.objtype.startswith("property")
or self.objtype.startswith("attr")
)

def add_target_and_index(self, name_cls, sig, signode):
if self.objtype == "global":
Expand Down Expand Up @@ -480,7 +519,7 @@ class PhpClassmember(PhpObject):
"""

def get_signature_prefix(self, sig):
if self.objtype == "attr":
if self.objtype == "property" or self.objtype == "attr":
return _("property ")
if self.objtype == "staticmethod":
return _("static ")
Expand All @@ -496,6 +535,7 @@ def get_index_text(self, namespace, name_cls):

if (
self.objtype.endswith("method")
or self.objtype == "property"
or self.objtype == "attr"
or self.objtype == "case"
):
Expand All @@ -512,7 +552,7 @@ def get_index_text(self, namespace, name_cls):
return _("%s() (%s\\%s method)") % (propname, namespace, clsname)
else:
return _("%s() (%s method)") % (propname, clsname)
elif self.objtype == "attr":
elif self.objtype == "property" or self.objtype == "attr":
if namespace and clsname is None:
return _("%s (in namespace %s)") % (name, namespace)
elif namespace and self.env.config.add_module_names:
Expand Down Expand Up @@ -713,14 +753,15 @@ class PhpDomain(Domain):
name = "php"
label = "PHP"
object_types = {
"function": ObjType(_("function"), "func", "obj"),
"function": ObjType(_("function"), "function", "obj"),
"global": ObjType(_("global variable"), "global", "obj"),
"const": ObjType(_("const"), "const", "obj"),
"method": ObjType(_("method"), "meth", "obj"),
"method": ObjType(_("method"), "method", "obj"),
"class": ObjType(_("class"), "class", "obj"),
"property": ObjType(_("attribute"), "property", "obj"),
"attr": ObjType(_("attribute"), "attr", "obj"),
"exception": ObjType(_("exception"), "exc", "obj"),
"namespace": ObjType(_("namespace"), "ns", "obj"),
"namespace": ObjType(_("namespace"), "namespace", "obj"),
"interface": ObjType(_("interface"), "interface", "obj"),
"trait": ObjType(_("trait"), "trait", "obj"),
"enum": ObjType(_("enum"), "enum", "obj"),
Expand All @@ -733,27 +774,32 @@ class PhpDomain(Domain):
"const": PhpNamespacelevel,
"class": PhpClasslike,
"method": PhpClassmember,
"staticmethod": PhpClassmember,
"attr": PhpClassmember,
"staticmethod": PhpClassmember, # deprecated, use "method" with "static" modifier, methods in PHP are exclusively static or non-static
"property": PhpClassmember,
"attr": PhpClassmember, # deprecated, use "property"
"case": PhpClassmember,
"exception": PhpClasslike,
"exception": PhpClasslike, # deprecated, use "class", exceptions in PHP are regular classes
"interface": PhpClasslike,
"trait": PhpClasslike,
"enum": PhpClasslike,
"namespace": PhpNamespace,
"currentmodule": PhpCurrentNamespace,
"currentmodule": PhpCurrentNamespace, # deprecated, use "currentnamespace"
"currentnamespace": PhpCurrentNamespace,
}

roles = {
"func": PhpXRefRole(fix_parens=False),
"function": PhpXRefRole(fix_parens=False),
"func": PhpXRefRole(fix_parens=False), # deprecated, use "function"
"global": PhpXRefRole(),
"class": PhpXRefRole(),
"exc": PhpXRefRole(),
"meth": PhpXRefRole(fix_parens=False),
"method": PhpXRefRole(fix_parens=False),
"meth": PhpXRefRole(fix_parens=False), # deprecated, use "method"
"property": PhpXRefRole(),
"attr": PhpXRefRole(),
"const": PhpXRefRole(),
"ns": PhpXRefRole(),
"namespace": PhpXRefRole(),
"ns": PhpXRefRole(), # deprecated, use "namespace"
"obj": PhpXRefRole(),
"interface": PhpXRefRole(),
"trait": PhpXRefRole(),
Expand Down Expand Up @@ -795,7 +841,12 @@ def resolve_any_xref(self, env, fromdocname, builder, target, node, contnode):
return []

def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
if typ == "ns" or typ == "obj" and target in self.data["namespaces"]:
if (
typ == "namespace"
or typ == "ns"
or typ == "obj"
and target in self.data["namespaces"]
):
docname, synopsis, deprecated = self.data["namespaces"].get(
target, ("", "", "")
)
Expand Down
Loading