feat(gazelle): Support "$python_root$" placeholder in the "gazelle:python_visibility" directive (#1936)

Add support for the `$python_root$` placeholder in the `#
gazelle:python_visibility` directive.

Fixes #1932.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e331a86..7a9e4e6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -83,6 +83,8 @@
   invalid usage previously but we were not failing the build. From now on this
   is explicitly disallowed.
 * (toolchains) Added riscv64 platform definition for python toolchains.
+* (gazelle) The `python_visibility` directive now supports the `$python_root$`
+  placeholder, just like the `python_default_visibility` directive does.
 * (rules) A new bootstrap implementation that doesn't require a system Python
   is available. It can be enabled by setting
   {obj}`--@rules_python//python:config_settings:bootstrap_impl=two_phase`. It
diff --git a/gazelle/README.md b/gazelle/README.md
index e7b1766..bb688b9 100644
--- a/gazelle/README.md
+++ b/gazelle/README.md
@@ -360,6 +360,19 @@
 
 ```
 
+This directive also supports the `$python_root$` placeholder that
+`# gazelle:python_default_visibility` supports.
+
+```starlark
+# gazlle:python_visibility //$python_root$/foo:bar
+
+py_library(
+    ...
+    visibility = ["//this_is_my_python_root/foo:bar"],
+    ...
+)
+```
+
 
 #### Directive: `python_test_file_pattern`:
 
diff --git a/gazelle/python/configure.go b/gazelle/python/configure.go
index ed6e2e1..c35a261 100644
--- a/gazelle/python/configure.go
+++ b/gazelle/python/configure.go
@@ -182,7 +182,8 @@
 				config.SetDefaultVisibility(strings.Split(labels, ","))
 			}
 		case pythonconfig.Visibility:
-			config.AppendVisibility(strings.TrimSpace(d.Value))
+			labels := strings.ReplaceAll(strings.TrimSpace(d.Value), "$python_root$", config.PythonProjectRoot())
+			config.AppendVisibility(labels)
 		case pythonconfig.TestFilePattern:
 			value := strings.TrimSpace(d.Value)
 			if value == "" {
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.in b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.in
new file mode 100644
index 0000000..6948b47
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.in
@@ -0,0 +1 @@
+# gazelle:python_root
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.out b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.out
new file mode 100644
index 0000000..6948b47
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/BUILD.out
@@ -0,0 +1 @@
+# gazelle:python_root
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.in b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.in
new file mode 100644
index 0000000..41ff631
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.in
@@ -0,0 +1,6 @@
+# The default visibility is "//$python_root$:__subpackages" so the generated
+# target will also have "//subdir_python_root:__subpackages__" in the visibility
+# attribute.
+#
+# gazelle:python_visibility //$python_root$/anywhere:__pkg__
+# gazelle:python_visibility //$python_root$/and/also:here
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.out b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.out
new file mode 100644
index 0000000..25ec8de
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/BUILD.out
@@ -0,0 +1,24 @@
+load("@rules_python//python:defs.bzl", "py_library")
+
+# The default visibility is "//$python_root$:__subpackages" so the generated
+# target will also have "//subdir_python_root:__subpackages__" in the visibility
+# attribute.
+#
+# gazelle:python_visibility //$python_root$/anywhere:__pkg__
+# gazelle:python_visibility //$python_root$/and/also:here
+
+py_library(
+    name = "subdir",
+    srcs = [
+        "__init__.py",
+        "baz.py",
+    ],
+    imports = [".."],
+    visibility = [
+        "//bar:baz",
+        "//subdir_python_root:__subpackages__",
+        "//subdir_python_root/and/also:here",
+        "//subdir_python_root/anywhere:__pkg__",
+        "//tests:__pkg__",
+    ],
+)
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/__init__.py b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/__init__.py
diff --git a/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/baz.py b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/baz.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gazelle/python/testdata/directive_python_visibility/subdir_python_root/subdir/baz.py