We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
`ListView` initial index is off by one
Setting the `initial_index` of a `ListView` seems to be off by one, introduced somewhere in v0.48.2:

```python
from textual.app import App, ComposeResult
from textual.widgets import Label, ListItem, ListView


class ExampleApp(App):
    def compose(self) -> ComposeResult:
        list_items = [ListItem(Label(str(i))) for i in range(10)]
        yield ListView(
            *list_items,
            initial_index=9,
        )


if __name__ == "__main__":
    app = ExampleApp()
    app.run()
```

![image](https://github.com/Textualize/textual/assets/101601846/90471154-e20b-4da4-b776-f436a29dfac2)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/textual/widgets/_list_view.py`
Content:
```
1 from __future__ import annotations
2 
3 from typing import ClassVar, Iterable, Optional
4 
5 from typing_extensions import TypeGuard
6 
7 from .. import _widget_navigation
8 from ..await_remove import AwaitRemove
9 from ..binding import Binding, BindingType
10 from ..containers import VerticalScroll
11 from ..events import Mount
12 from ..message import Message
13 from ..reactive import reactive
14 from ..widget import AwaitMount
15 from ..widgets._list_item import ListItem
16 
17 
18 class ListView(VerticalScroll, can_focus=True, can_focus_children=False):
19     """A vertical list view widget.
20 
21     Displays a vertical list of `ListItem`s which can be highlighted and
22     selected using the mouse or keyboard.
23 
24     Attributes:
25         index: The index in the list that's currently highlighted.
26     """
27 
28     BINDINGS: ClassVar[list[BindingType]] = [
29         Binding("enter", "select_cursor", "Select", show=False),
30         Binding("up", "cursor_up", "Cursor Up", show=False),
31         Binding("down", "cursor_down", "Cursor Down", show=False),
32     ]
33     """
34     | Key(s) | Description |
35     | :- | :- |
36     | enter | Select the current item. |
37     | up | Move the cursor up. |
38     | down | Move the cursor down. |
39     """
40 
41     index = reactive[Optional[int]](0, always_update=True, init=False)
42     """The index of the currently highlighted item."""
43 
44     class Highlighted(Message):
45         """Posted when the highlighted item changes.
46 
47         Highlighted item is controlled using up/down keys.
48         Can be handled using `on_list_view_highlighted` in a subclass of `ListView`
49         or in a parent widget in the DOM.
50         """
51 
52         ALLOW_SELECTOR_MATCH = {"item"}
53         """Additional message attributes that can be used with the [`on` decorator][textual.on]."""
54 
55         def __init__(self, list_view: ListView, item: ListItem | None) -> None:
56             super().__init__()
57             self.list_view: ListView = list_view
58             """The view that contains the item highlighted."""
59             self.item: ListItem | None = item
60             """The highlighted item, if there is one highlighted."""
61 
62         @property
63         def control(self) -> ListView:
64             """The view that contains the item highlighted.
65 
66             This is an alias for [`Highlighted.list_view`][textual.widgets.ListView.Highlighted.list_view]
67             and is used by the [`on`][textual.on] decorator.
68             """
69             return self.list_view
70 
71     class Selected(Message):
72         """Posted when a list item is selected, e.g. when you press the enter key on it.
73 
74         Can be handled using `on_list_view_selected` in a subclass of `ListView` or in
75         a parent widget in the DOM.
76         """
77 
78         ALLOW_SELECTOR_MATCH = {"item"}
79         """Additional message attributes that can be used with the [`on` decorator][textual.on]."""
80 
81         def __init__(self, list_view: ListView, item: ListItem) -> None:
82             super().__init__()
83             self.list_view: ListView = list_view
84             """The view that contains the item selected."""
85             self.item: ListItem = item
86             """The selected item."""
87 
88         @property
89         def control(self) -> ListView:
90             """The view that contains the item selected.
91 
92             This is an alias for [`Selected.list_view`][textual.widgets.ListView.Selected.list_view]
93             and is used by the [`on`][textual.on] decorator.
94             """
95             return self.list_view
96 
97     def __init__(
98         self,
99         *children: ListItem,
100         initial_index: int | None = 0,
101         name: str | None = None,
102         id: str | None = None,
103         classes: str | None = None,
104         disabled: bool = False,
105     ) -> None:
106         """
107         Initialize a ListView.
108 
109         Args:
110             *children: The ListItems to display in the list.
111             initial_index: The index that should be highlighted when the list is first mounted.
112             name: The name of the widget.
113             id: The unique ID of the widget used in CSS/query selection.
114             classes: The CSS classes of the widget.
115             disabled: Whether the ListView is disabled or not.
116         """
117         super().__init__(
118             *children, name=name, id=id, classes=classes, disabled=disabled
119         )
120         # Set the index to the given initial index, or the first available index after.
121         self._index = _widget_navigation.find_next_enabled(
122             self._nodes,
123             anchor=initial_index - 1 if initial_index is not None else None,
124             direction=1,
125         )
126 
127     def _on_mount(self, _: Mount) -> None:
128         """Ensure the ListView is fully-settled after mounting."""
129         self.index = self._index
130 
131     @property
132     def highlighted_child(self) -> ListItem | None:
133         """The currently highlighted ListItem, or None if nothing is highlighted."""
134         if self.index is not None and 0 <= self.index < len(self._nodes):
135             list_item = self._nodes[self.index]
136             assert isinstance(list_item, ListItem)
137             return list_item
138         else:
139             return None
140 
141     def validate_index(self, index: int | None) -> int | None:
142         """Clamp the index to the valid range, or set to None if there's nothing to highlight.
143 
144         Args:
145             index: The index to clamp.
146 
147         Returns:
148             The clamped index.
149         """
150         if index is None or not self._nodes:
151             return None
152         elif index < 0:
153             return 0
154         elif index >= len(self._nodes):
155             return len(self._nodes) - 1
156 
157         return index
158 
159     def _is_valid_index(self, index: int | None) -> TypeGuard[int]:
160         """Determine whether the current index is valid into the list of children."""
161         if index is None:
162             return False
163         return 0 <= index < len(self._nodes)
164 
165     def watch_index(self, old_index: int | None, new_index: int | None) -> None:
166         """Updates the highlighting when the index changes."""
167         if self._is_valid_index(old_index):
168             old_child = self._nodes[old_index]
169             assert isinstance(old_child, ListItem)
170             old_child.highlighted = False
171 
172         if self._is_valid_index(new_index) and not self._nodes[new_index].disabled:
173             new_child = self._nodes[new_index]
174             assert isinstance(new_child, ListItem)
175             new_child.highlighted = True
176             self._scroll_highlighted_region()
177             self.post_message(self.Highlighted(self, new_child))
178         else:
179             self.post_message(self.Highlighted(self, None))
180 
181     def extend(self, items: Iterable[ListItem]) -> AwaitMount:
182         """Append multiple new ListItems to the end of the ListView.
183 
184         Args:
185             items: The ListItems to append.
186 
187         Returns:
188             An awaitable that yields control to the event loop
189                 until the DOM has been updated with the new child items.
190         """
191         await_mount = self.mount(*items)
192         if len(self) == 1:
193             self.index = 0
194         return await_mount
195 
196     def append(self, item: ListItem) -> AwaitMount:
197         """Append a new ListItem to the end of the ListView.
198 
199         Args:
200             item: The ListItem to append.
201 
202         Returns:
203             An awaitable that yields control to the event loop
204                 until the DOM has been updated with the new child item.
205         """
206         return self.extend([item])
207 
208     def clear(self) -> AwaitRemove:
209         """Clear all items from the ListView.
210 
211         Returns:
212             An awaitable that yields control to the event loop until
213                 the DOM has been updated to reflect all children being removed.
214         """
215         await_remove = self.query("ListView > ListItem").remove()
216         self.index = None
217         return await_remove
218 
219     def insert(self, index: int, items: Iterable[ListItem]) -> AwaitMount:
220         """Insert new ListItem(s) to specified index.
221 
222         Args:
223             index: index to insert new ListItem.
224             items: The ListItems to insert.
225 
226         Returns:
227             An awaitable that yields control to the event loop
228                 until the DOM has been updated with the new child item.
229         """
230         await_mount = self.mount(*items, before=index)
231         return await_mount
232 
233     def pop(self, index: Optional[int] = None) -> AwaitRemove:
234         """Remove last ListItem from ListView or
235            Remove ListItem from ListView by index
236 
237         Args:
238             index: index of ListItem to remove from ListView
239 
240         Returns:
241             An awaitable that yields control to the event loop until
242                 the DOM has been updated to reflect item being removed.
243         """
244         if index is None:
245             await_remove = self.query("ListItem").last().remove()
246         else:
247             await_remove = self.query("ListItem")[index].remove()
248         return await_remove
249 
250     def remove_items(self, indices: Iterable[int]) -> AwaitRemove:
251         """Remove ListItems from ListView by indices
252 
253         Args:
254             indices: index(s) of ListItems to remove from ListView
255 
256         Returns:
257             An awaitable object that waits for the direct children to be removed.
258         """
259         items = self.query("ListItem")
260         items_to_remove = []
261         for index in indices:
262             items_to_remove.append(items[index])
263 
264         await_remove = self.app._remove_nodes(items_to_remove, self)
265         return await_remove
266 
267     def action_select_cursor(self) -> None:
268         """Select the current item in the list."""
269         selected_child = self.highlighted_child
270         if selected_child is None:
271             return
272         self.post_message(self.Selected(self, selected_child))
273 
274     def action_cursor_down(self) -> None:
275         """Highlight the next item in the list."""
276         candidate = _widget_navigation.find_next_enabled(
277             self._nodes,
278             anchor=self.index,
279             direction=1,
280         )
281         if self.index is not None and candidate is not None and candidate < self.index:
282             return  # Avoid wrapping around.
283 
284         self.index = candidate
285 
286     def action_cursor_up(self) -> None:
287         """Highlight the previous item in the list."""
288         candidate = _widget_navigation.find_next_enabled(
289             self._nodes,
290             anchor=self.index,
291             direction=-1,
292         )
293         if self.index is not None and candidate is not None and candidate > self.index:
294             return  # Avoid wrapping around.
295 
296         self.index = candidate
297 
298     def _on_list_item__child_clicked(self, event: ListItem._ChildClicked) -> None:
299         event.stop()
300         self.focus()
301         self.index = self._nodes.index(event.item)
302         self.post_message(self.Selected(self, event.item))
303 
304     def _scroll_highlighted_region(self) -> None:
305         """Used to keep the highlighted index within vision"""
306         if self.highlighted_child is not None:
307             self.call_after_refresh(
308                 self.scroll_to_widget, self.highlighted_child, animate=False
309             )
310 
311     def __len__(self) -> int:
312         """Compute the length (in number of items) of the list view."""
313         return len(self._nodes)
314
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/textual/widgets/_list_view.py b/src/textual/widgets/_list_view.py
--- a/src/textual/widgets/_list_view.py
+++ b/src/textual/widgets/_list_view.py
@@ -119,9 +119,10 @@
         )
         # Set the index to the given initial index, or the first available index after.
         self._index = _widget_navigation.find_next_enabled(
-            self._nodes,
-            anchor=initial_index - 1 if initial_index is not None else None,
+            children,
+            anchor=initial_index if initial_index is not None else None,
             direction=1,
+            with_anchor=True,
         )
 
     def _on_mount(self, _: Mount) -> None:

{"golden_diff": "diff --git a/src/textual/widgets/_list_view.py b/src/textual/widgets/_list_view.py\n--- a/src/textual/widgets/_list_view.py\n+++ b/src/textual/widgets/_list_view.py\n@@ -119,9 +119,10 @@\n         )\n         # Set the index to the given initial index, or the first available index after.\n         self._index = _widget_navigation.find_next_enabled(\n-            self._nodes,\n-            anchor=initial_index - 1 if initial_index is not None else None,\n+            children,\n+            anchor=initial_index if initial_index is not None else None,\n             direction=1,\n+            with_anchor=True,\n         )\n \n     def _on_mount(self, _: Mount) -> None:\n", "issue": "`ListView` initial index is off by one\nSetting the `initial_index` of a `ListView` seems to be off by one, introduced somewhere in v0.48.2:\r\n\r\n```python\r\nfrom textual.app import App, ComposeResult\r\nfrom textual.widgets import Label, ListItem, ListView\r\n\r\n\r\nclass ExampleApp(App):\r\n    def compose(self) -> ComposeResult:\r\n        list_items = [ListItem(Label(str(i))) for i in range(10)]\r\n        yield ListView(\r\n            *list_items,\r\n            initial_index=9,\r\n        )\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    app = ExampleApp()\r\n    app.run()\r\n```\r\n\r\n![image](https://github.com/Textualize/textual/assets/101601846/90471154-e20b-4da4-b776-f436a29dfac2)\n", "before_files": [{"content": "from __future__ import annotations\n\nfrom typing import ClassVar, Iterable, Optional\n\nfrom typing_extensions import TypeGuard\n\nfrom .. import _widget_navigation\nfrom ..await_remove import AwaitRemove\nfrom ..binding import Binding, BindingType\nfrom ..containers import VerticalScroll\nfrom ..events import Mount\nfrom ..message import Message\nfrom ..reactive import reactive\nfrom ..widget import AwaitMount\nfrom ..widgets._list_item import ListItem\n\n\nclass ListView(VerticalScroll, can_focus=True, can_focus_children=False):\n    \"\"\"A vertical list view widget.\n\n    Displays a vertical list of `ListItem`s which can be highlighted and\n    selected using the mouse or keyboard.\n\n    Attributes:\n        index: The index in the list that's currently highlighted.\n    \"\"\"\n\n    BINDINGS: ClassVar[list[BindingType]] = [\n        Binding(\"enter\", \"select_cursor\", \"Select\", show=False),\n        Binding(\"up\", \"cursor_up\", \"Cursor Up\", show=False),\n        Binding(\"down\", \"cursor_down\", \"Cursor Down\", show=False),\n    ]\n    \"\"\"\n    | Key(s) | Description |\n    | :- | :- |\n    | enter | Select the current item. |\n    | up | Move the cursor up. |\n    | down | Move the cursor down. |\n    \"\"\"\n\n    index = reactive[Optional[int]](0, always_update=True, init=False)\n    \"\"\"The index of the currently highlighted item.\"\"\"\n\n    class Highlighted(Message):\n        \"\"\"Posted when the highlighted item changes.\n\n        Highlighted item is controlled using up/down keys.\n        Can be handled using `on_list_view_highlighted` in a subclass of `ListView`\n        or in a parent widget in the DOM.\n        \"\"\"\n\n        ALLOW_SELECTOR_MATCH = {\"item\"}\n        \"\"\"Additional message attributes that can be used with the [`on` decorator][textual.on].\"\"\"\n\n        def __init__(self, list_view: ListView, item: ListItem | None) -> None:\n            super().__init__()\n            self.list_view: ListView = list_view\n            \"\"\"The view that contains the item highlighted.\"\"\"\n            self.item: ListItem | None = item\n            \"\"\"The highlighted item, if there is one highlighted.\"\"\"\n\n        @property\n        def control(self) -> ListView:\n            \"\"\"The view that contains the item highlighted.\n\n            This is an alias for [`Highlighted.list_view`][textual.widgets.ListView.Highlighted.list_view]\n            and is used by the [`on`][textual.on] decorator.\n            \"\"\"\n            return self.list_view\n\n    class Selected(Message):\n        \"\"\"Posted when a list item is selected, e.g. when you press the enter key on it.\n\n        Can be handled using `on_list_view_selected` in a subclass of `ListView` or in\n        a parent widget in the DOM.\n        \"\"\"\n\n        ALLOW_SELECTOR_MATCH = {\"item\"}\n        \"\"\"Additional message attributes that can be used with the [`on` decorator][textual.on].\"\"\"\n\n        def __init__(self, list_view: ListView, item: ListItem) -> None:\n            super().__init__()\n            self.list_view: ListView = list_view\n            \"\"\"The view that contains the item selected.\"\"\"\n            self.item: ListItem = item\n            \"\"\"The selected item.\"\"\"\n\n        @property\n        def control(self) -> ListView:\n            \"\"\"The view that contains the item selected.\n\n            This is an alias for [`Selected.list_view`][textual.widgets.ListView.Selected.list_view]\n            and is used by the [`on`][textual.on] decorator.\n            \"\"\"\n            return self.list_view\n\n    def __init__(\n        self,\n        *children: ListItem,\n        initial_index: int | None = 0,\n        name: str | None = None,\n        id: str | None = None,\n        classes: str | None = None,\n        disabled: bool = False,\n    ) -> None:\n        \"\"\"\n        Initialize a ListView.\n\n        Args:\n            *children: The ListItems to display in the list.\n            initial_index: The index that should be highlighted when the list is first mounted.\n            name: The name of the widget.\n            id: The unique ID of the widget used in CSS/query selection.\n            classes: The CSS classes of the widget.\n            disabled: Whether the ListView is disabled or not.\n        \"\"\"\n        super().__init__(\n            *children, name=name, id=id, classes=classes, disabled=disabled\n        )\n        # Set the index to the given initial index, or the first available index after.\n        self._index = _widget_navigation.find_next_enabled(\n            self._nodes,\n            anchor=initial_index - 1 if initial_index is not None else None,\n            direction=1,\n        )\n\n    def _on_mount(self, _: Mount) -> None:\n        \"\"\"Ensure the ListView is fully-settled after mounting.\"\"\"\n        self.index = self._index\n\n    @property\n    def highlighted_child(self) -> ListItem | None:\n        \"\"\"The currently highlighted ListItem, or None if nothing is highlighted.\"\"\"\n        if self.index is not None and 0 <= self.index < len(self._nodes):\n            list_item = self._nodes[self.index]\n            assert isinstance(list_item, ListItem)\n            return list_item\n        else:\n            return None\n\n    def validate_index(self, index: int | None) -> int | None:\n        \"\"\"Clamp the index to the valid range, or set to None if there's nothing to highlight.\n\n        Args:\n            index: The index to clamp.\n\n        Returns:\n            The clamped index.\n        \"\"\"\n        if index is None or not self._nodes:\n            return None\n        elif index < 0:\n            return 0\n        elif index >= len(self._nodes):\n            return len(self._nodes) - 1\n\n        return index\n\n    def _is_valid_index(self, index: int | None) -> TypeGuard[int]:\n        \"\"\"Determine whether the current index is valid into the list of children.\"\"\"\n        if index is None:\n            return False\n        return 0 <= index < len(self._nodes)\n\n    def watch_index(self, old_index: int | None, new_index: int | None) -> None:\n        \"\"\"Updates the highlighting when the index changes.\"\"\"\n        if self._is_valid_index(old_index):\n            old_child = self._nodes[old_index]\n            assert isinstance(old_child, ListItem)\n            old_child.highlighted = False\n\n        if self._is_valid_index(new_index) and not self._nodes[new_index].disabled:\n            new_child = self._nodes[new_index]\n            assert isinstance(new_child, ListItem)\n            new_child.highlighted = True\n            self._scroll_highlighted_region()\n            self.post_message(self.Highlighted(self, new_child))\n        else:\n            self.post_message(self.Highlighted(self, None))\n\n    def extend(self, items: Iterable[ListItem]) -> AwaitMount:\n        \"\"\"Append multiple new ListItems to the end of the ListView.\n\n        Args:\n            items: The ListItems to append.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child items.\n        \"\"\"\n        await_mount = self.mount(*items)\n        if len(self) == 1:\n            self.index = 0\n        return await_mount\n\n    def append(self, item: ListItem) -> AwaitMount:\n        \"\"\"Append a new ListItem to the end of the ListView.\n\n        Args:\n            item: The ListItem to append.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child item.\n        \"\"\"\n        return self.extend([item])\n\n    def clear(self) -> AwaitRemove:\n        \"\"\"Clear all items from the ListView.\n\n        Returns:\n            An awaitable that yields control to the event loop until\n                the DOM has been updated to reflect all children being removed.\n        \"\"\"\n        await_remove = self.query(\"ListView > ListItem\").remove()\n        self.index = None\n        return await_remove\n\n    def insert(self, index: int, items: Iterable[ListItem]) -> AwaitMount:\n        \"\"\"Insert new ListItem(s) to specified index.\n\n        Args:\n            index: index to insert new ListItem.\n            items: The ListItems to insert.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child item.\n        \"\"\"\n        await_mount = self.mount(*items, before=index)\n        return await_mount\n\n    def pop(self, index: Optional[int] = None) -> AwaitRemove:\n        \"\"\"Remove last ListItem from ListView or\n           Remove ListItem from ListView by index\n\n        Args:\n            index: index of ListItem to remove from ListView\n\n        Returns:\n            An awaitable that yields control to the event loop until\n                the DOM has been updated to reflect item being removed.\n        \"\"\"\n        if index is None:\n            await_remove = self.query(\"ListItem\").last().remove()\n        else:\n            await_remove = self.query(\"ListItem\")[index].remove()\n        return await_remove\n\n    def remove_items(self, indices: Iterable[int]) -> AwaitRemove:\n        \"\"\"Remove ListItems from ListView by indices\n\n        Args:\n            indices: index(s) of ListItems to remove from ListView\n\n        Returns:\n            An awaitable object that waits for the direct children to be removed.\n        \"\"\"\n        items = self.query(\"ListItem\")\n        items_to_remove = []\n        for index in indices:\n            items_to_remove.append(items[index])\n\n        await_remove = self.app._remove_nodes(items_to_remove, self)\n        return await_remove\n\n    def action_select_cursor(self) -> None:\n        \"\"\"Select the current item in the list.\"\"\"\n        selected_child = self.highlighted_child\n        if selected_child is None:\n            return\n        self.post_message(self.Selected(self, selected_child))\n\n    def action_cursor_down(self) -> None:\n        \"\"\"Highlight the next item in the list.\"\"\"\n        candidate = _widget_navigation.find_next_enabled(\n            self._nodes,\n            anchor=self.index,\n            direction=1,\n        )\n        if self.index is not None and candidate is not None and candidate < self.index:\n            return  # Avoid wrapping around.\n\n        self.index = candidate\n\n    def action_cursor_up(self) -> None:\n        \"\"\"Highlight the previous item in the list.\"\"\"\n        candidate = _widget_navigation.find_next_enabled(\n            self._nodes,\n            anchor=self.index,\n            direction=-1,\n        )\n        if self.index is not None and candidate is not None and candidate > self.index:\n            return  # Avoid wrapping around.\n\n        self.index = candidate\n\n    def _on_list_item__child_clicked(self, event: ListItem._ChildClicked) -> None:\n        event.stop()\n        self.focus()\n        self.index = self._nodes.index(event.item)\n        self.post_message(self.Selected(self, event.item))\n\n    def _scroll_highlighted_region(self) -> None:\n        \"\"\"Used to keep the highlighted index within vision\"\"\"\n        if self.highlighted_child is not None:\n            self.call_after_refresh(\n                self.scroll_to_widget, self.highlighted_child, animate=False\n            )\n\n    def __len__(self) -> int:\n        \"\"\"Compute the length (in number of items) of the list view.\"\"\"\n        return len(self._nodes)\n", "path": "src/textual/widgets/_list_view.py"}], "after_files": [{"content": "from __future__ import annotations\n\nfrom typing import ClassVar, Iterable, Optional\n\nfrom typing_extensions import TypeGuard\n\nfrom .. import _widget_navigation\nfrom ..await_remove import AwaitRemove\nfrom ..binding import Binding, BindingType\nfrom ..containers import VerticalScroll\nfrom ..events import Mount\nfrom ..message import Message\nfrom ..reactive import reactive\nfrom ..widget import AwaitMount\nfrom ..widgets._list_item import ListItem\n\n\nclass ListView(VerticalScroll, can_focus=True, can_focus_children=False):\n    \"\"\"A vertical list view widget.\n\n    Displays a vertical list of `ListItem`s which can be highlighted and\n    selected using the mouse or keyboard.\n\n    Attributes:\n        index: The index in the list that's currently highlighted.\n    \"\"\"\n\n    BINDINGS: ClassVar[list[BindingType]] = [\n        Binding(\"enter\", \"select_cursor\", \"Select\", show=False),\n        Binding(\"up\", \"cursor_up\", \"Cursor Up\", show=False),\n        Binding(\"down\", \"cursor_down\", \"Cursor Down\", show=False),\n    ]\n    \"\"\"\n    | Key(s) | Description |\n    | :- | :- |\n    | enter | Select the current item. |\n    | up | Move the cursor up. |\n    | down | Move the cursor down. |\n    \"\"\"\n\n    index = reactive[Optional[int]](0, always_update=True, init=False)\n    \"\"\"The index of the currently highlighted item.\"\"\"\n\n    class Highlighted(Message):\n        \"\"\"Posted when the highlighted item changes.\n\n        Highlighted item is controlled using up/down keys.\n        Can be handled using `on_list_view_highlighted` in a subclass of `ListView`\n        or in a parent widget in the DOM.\n        \"\"\"\n\n        ALLOW_SELECTOR_MATCH = {\"item\"}\n        \"\"\"Additional message attributes that can be used with the [`on` decorator][textual.on].\"\"\"\n\n        def __init__(self, list_view: ListView, item: ListItem | None) -> None:\n            super().__init__()\n            self.list_view: ListView = list_view\n            \"\"\"The view that contains the item highlighted.\"\"\"\n            self.item: ListItem | None = item\n            \"\"\"The highlighted item, if there is one highlighted.\"\"\"\n\n        @property\n        def control(self) -> ListView:\n            \"\"\"The view that contains the item highlighted.\n\n            This is an alias for [`Highlighted.list_view`][textual.widgets.ListView.Highlighted.list_view]\n            and is used by the [`on`][textual.on] decorator.\n            \"\"\"\n            return self.list_view\n\n    class Selected(Message):\n        \"\"\"Posted when a list item is selected, e.g. when you press the enter key on it.\n\n        Can be handled using `on_list_view_selected` in a subclass of `ListView` or in\n        a parent widget in the DOM.\n        \"\"\"\n\n        ALLOW_SELECTOR_MATCH = {\"item\"}\n        \"\"\"Additional message attributes that can be used with the [`on` decorator][textual.on].\"\"\"\n\n        def __init__(self, list_view: ListView, item: ListItem) -> None:\n            super().__init__()\n            self.list_view: ListView = list_view\n            \"\"\"The view that contains the item selected.\"\"\"\n            self.item: ListItem = item\n            \"\"\"The selected item.\"\"\"\n\n        @property\n        def control(self) -> ListView:\n            \"\"\"The view that contains the item selected.\n\n            This is an alias for [`Selected.list_view`][textual.widgets.ListView.Selected.list_view]\n            and is used by the [`on`][textual.on] decorator.\n            \"\"\"\n            return self.list_view\n\n    def __init__(\n        self,\n        *children: ListItem,\n        initial_index: int | None = 0,\n        name: str | None = None,\n        id: str | None = None,\n        classes: str | None = None,\n        disabled: bool = False,\n    ) -> None:\n        \"\"\"\n        Initialize a ListView.\n\n        Args:\n            *children: The ListItems to display in the list.\n            initial_index: The index that should be highlighted when the list is first mounted.\n            name: The name of the widget.\n            id: The unique ID of the widget used in CSS/query selection.\n            classes: The CSS classes of the widget.\n            disabled: Whether the ListView is disabled or not.\n        \"\"\"\n        super().__init__(\n            *children, name=name, id=id, classes=classes, disabled=disabled\n        )\n        # Set the index to the given initial index, or the first available index after.\n        self._index = _widget_navigation.find_next_enabled(\n            children,\n            anchor=initial_index if initial_index is not None else None,\n            direction=1,\n            with_anchor=True,\n        )\n\n    def _on_mount(self, _: Mount) -> None:\n        \"\"\"Ensure the ListView is fully-settled after mounting.\"\"\"\n        self.index = self._index\n\n    @property\n    def highlighted_child(self) -> ListItem | None:\n        \"\"\"The currently highlighted ListItem, or None if nothing is highlighted.\"\"\"\n        if self.index is not None and 0 <= self.index < len(self._nodes):\n            list_item = self._nodes[self.index]\n            assert isinstance(list_item, ListItem)\n            return list_item\n        else:\n            return None\n\n    def validate_index(self, index: int | None) -> int | None:\n        \"\"\"Clamp the index to the valid range, or set to None if there's nothing to highlight.\n\n        Args:\n            index: The index to clamp.\n\n        Returns:\n            The clamped index.\n        \"\"\"\n        if index is None or not self._nodes:\n            return None\n        elif index < 0:\n            return 0\n        elif index >= len(self._nodes):\n            return len(self._nodes) - 1\n\n        return index\n\n    def _is_valid_index(self, index: int | None) -> TypeGuard[int]:\n        \"\"\"Determine whether the current index is valid into the list of children.\"\"\"\n        if index is None:\n            return False\n        return 0 <= index < len(self._nodes)\n\n    def watch_index(self, old_index: int | None, new_index: int | None) -> None:\n        \"\"\"Updates the highlighting when the index changes.\"\"\"\n        if self._is_valid_index(old_index):\n            old_child = self._nodes[old_index]\n            assert isinstance(old_child, ListItem)\n            old_child.highlighted = False\n\n        if self._is_valid_index(new_index) and not self._nodes[new_index].disabled:\n            new_child = self._nodes[new_index]\n            assert isinstance(new_child, ListItem)\n            new_child.highlighted = True\n            self._scroll_highlighted_region()\n            self.post_message(self.Highlighted(self, new_child))\n        else:\n            self.post_message(self.Highlighted(self, None))\n\n    def extend(self, items: Iterable[ListItem]) -> AwaitMount:\n        \"\"\"Append multiple new ListItems to the end of the ListView.\n\n        Args:\n            items: The ListItems to append.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child items.\n        \"\"\"\n        await_mount = self.mount(*items)\n        if len(self) == 1:\n            self.index = 0\n        return await_mount\n\n    def append(self, item: ListItem) -> AwaitMount:\n        \"\"\"Append a new ListItem to the end of the ListView.\n\n        Args:\n            item: The ListItem to append.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child item.\n        \"\"\"\n        return self.extend([item])\n\n    def clear(self) -> AwaitRemove:\n        \"\"\"Clear all items from the ListView.\n\n        Returns:\n            An awaitable that yields control to the event loop until\n                the DOM has been updated to reflect all children being removed.\n        \"\"\"\n        await_remove = self.query(\"ListView > ListItem\").remove()\n        self.index = None\n        return await_remove\n\n    def insert(self, index: int, items: Iterable[ListItem]) -> AwaitMount:\n        \"\"\"Insert new ListItem(s) to specified index.\n\n        Args:\n            index: index to insert new ListItem.\n            items: The ListItems to insert.\n\n        Returns:\n            An awaitable that yields control to the event loop\n                until the DOM has been updated with the new child item.\n        \"\"\"\n        await_mount = self.mount(*items, before=index)\n        return await_mount\n\n    def pop(self, index: Optional[int] = None) -> AwaitRemove:\n        \"\"\"Remove last ListItem from ListView or\n           Remove ListItem from ListView by index\n\n        Args:\n            index: index of ListItem to remove from ListView\n\n        Returns:\n            An awaitable that yields control to the event loop until\n                the DOM has been updated to reflect item being removed.\n        \"\"\"\n        if index is None:\n            await_remove = self.query(\"ListItem\").last().remove()\n        else:\n            await_remove = self.query(\"ListItem\")[index].remove()\n        return await_remove\n\n    def remove_items(self, indices: Iterable[int]) -> AwaitRemove:\n        \"\"\"Remove ListItems from ListView by indices\n\n        Args:\n            indices: index(s) of ListItems to remove from ListView\n\n        Returns:\n            An awaitable object that waits for the direct children to be removed.\n        \"\"\"\n        items = self.query(\"ListItem\")\n        items_to_remove = []\n        for index in indices:\n            items_to_remove.append(items[index])\n\n        await_remove = self.app._remove_nodes(items_to_remove, self)\n        return await_remove\n\n    def action_select_cursor(self) -> None:\n        \"\"\"Select the current item in the list.\"\"\"\n        selected_child = self.highlighted_child\n        if selected_child is None:\n            return\n        self.post_message(self.Selected(self, selected_child))\n\n    def action_cursor_down(self) -> None:\n        \"\"\"Highlight the next item in the list.\"\"\"\n        candidate = _widget_navigation.find_next_enabled(\n            self._nodes,\n            anchor=self.index,\n            direction=1,\n        )\n        if self.index is not None and candidate is not None and candidate < self.index:\n            return  # Avoid wrapping around.\n\n        self.index = candidate\n\n    def action_cursor_up(self) -> None:\n        \"\"\"Highlight the previous item in the list.\"\"\"\n        candidate = _widget_navigation.find_next_enabled(\n            self._nodes,\n            anchor=self.index,\n            direction=-1,\n        )\n        if self.index is not None and candidate is not None and candidate > self.index:\n            return  # Avoid wrapping around.\n\n        self.index = candidate\n\n    def _on_list_item__child_clicked(self, event: ListItem._ChildClicked) -> None:\n        event.stop()\n        self.focus()\n        self.index = self._nodes.index(event.item)\n        self.post_message(self.Selected(self, event.item))\n\n    def _scroll_highlighted_region(self) -> None:\n        \"\"\"Used to keep the highlighted index within vision\"\"\"\n        if self.highlighted_child is not None:\n            self.call_after_refresh(\n                self.scroll_to_widget, self.highlighted_child, animate=False\n            )\n\n    def __len__(self) -> int:\n        \"\"\"Compute the length (in number of items) of the list view.\"\"\"\n        return len(self._nodes)\n", "path": "src/textual/widgets/_list_view.py"}]}