We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Update Plans and pricing icon
We should update the rocket icon everywhere it shows up in the gear menu (Plans and pricing, Plan management) to:

<img width="128" alt="rocket" src="https://github.com/zulip/zulip/assets/2090066/a951bc3b-1d95-4ec5-b5a2-3cf9d1ba88f4">

![rocket](https://github.com/zulip/zulip/assets/2090066/883735c4-9a2f-49e2-a629-ba8b43d80974)


source: https://lucide.dev/icons/rocket

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `zerver/lib/markdown/help_relative_links.py`
Content:
```
1 import re
2 from typing import Any, List, Match
3 
4 from markdown import Markdown
5 from markdown.extensions import Extension
6 from markdown.preprocessors import Preprocessor
7 from typing_extensions import override
8 
9 from zerver.lib.markdown.priorities import PREPROCESSOR_PRIORITES
10 
11 # There is a lot of duplicated code between this file and
12 # help_settings_links.py. So if you're making a change here consider making
13 # it there as well.
14 
15 REGEXP = re.compile(r"\{relative\|(?P<link_type>.*?)\|(?P<key>.*?)\}")
16 
17 gear_info = {
18     # The pattern is key: [name, link]
19     # key is from REGEXP: `{relative|gear|key}`
20     # name is what the item is called in the gear menu: `Select **name**.`
21     # link is used for relative links: `Select [name](link).`
22     "stream-settings": [
23         '<i class="zulip-icon zulip-icon-hash"></i> Stream settings',
24         "/#streams/subscribed",
25     ],
26     "settings": [
27         '<i class="zulip-icon zulip-icon-tool"></i> Personal Settings',
28         "/#settings/profile",
29     ],
30     "organization-settings": [
31         '<i class="zulip-icon zulip-icon-building"></i> Organization settings',
32         "/#organization/organization-profile",
33     ],
34     "group-settings": [
35         '<i class="zulip-icon zulip-icon-user-cog"></i> Group settings',
36         "/#groups/your",
37     ],
38     "stats": ['<i class="zulip-icon zulip-icon-bar-chart"></i> Usage statistics', "/stats"],
39     "integrations": ['<i class="zulip-icon-git-pull-request"></i> Integrations', "/integrations/"],
40     "plans": ['<i class="fa fa-rocket"></i> Plans and pricing', "/plans/"],
41     "billing": ['<i class="zulip-icon zulip-icon-credit-card"></i> Billing', "/billing/"],
42     "about-zulip": ["About Zulip", "/#about-zulip"],
43 }
44 
45 gear_instructions = """
46 1. Click on the **gear** (<i class="zulip-icon zulip-icon-gear"></i>) icon in
47    the upper right corner of the web or desktop app.
48 
49 1. Select {item}.
50 """
51 
52 
53 def gear_handle_match(key: str) -> str:
54     if relative_help_links:
55         item = f"[{gear_info[key][0]}]({gear_info[key][1]})"
56     else:
57         item = f"**{gear_info[key][0]}**"
58     return gear_instructions.format(item=item)
59 
60 
61 help_info = {
62     # The pattern is key: [name, link]
63     # key is from REGEXP: `{relative|help|key}`
64     # name is what the item is called in the help menu: `Select **name**.`
65     # link is used for relative links: `Select [name](link).`
66     "keyboard-shortcuts": [
67         '<i class="zulip-icon zulip-icon-keyboard"></i> Keyboard shortcuts',
68         "/#keyboard-shortcuts",
69     ],
70     "message-formatting": [
71         '<i class="zulip-icon zulip-icon-edit"></i> Message formatting',
72         "/#message-formatting",
73     ],
74     "search-filters": [
75         '<i class="zulip-icon zulip-icon-manage-search"></i> Search filters',
76         "/#search-operators",
77     ],
78     "about-zulip": [
79         '<i class="zulip-icon zulip-icon-info"></i> About Zulip',
80         "/#about-zulip",
81     ],
82 }
83 
84 help_instructions = """
85 1. Click on the **Help menu** (<i class="zulip-icon zulip-icon-help"></i>) icon
86    in the upper right corner of the app.
87 
88 1. Select {item}.
89 """
90 
91 
92 def help_handle_match(key: str) -> str:
93     if relative_help_links:
94         item = f"[{help_info[key][0]}]({help_info[key][1]})"
95     else:
96         item = f"**{help_info[key][0]}**"
97     return help_instructions.format(item=item)
98 
99 
100 stream_info = {
101     "all": ["All streams", "/#streams/all"],
102 }
103 
104 stream_all_instructions = """
105 1. Click on the **gear** (<i class="zulip-icon zulip-icon-gear"></i>) icon in
106    the upper right corner of the web or desktop app.
107 
108 1. Select <i class="zulip-icon zulip-icon-hash"></i> **Stream settings**.
109 
110 1. Click {item} in the upper left.
111 """
112 
113 
114 def stream_handle_match(key: str) -> str:
115     if relative_help_links:
116         item = f"[{stream_info[key][0]}]({stream_info[key][1]})"
117     else:
118         item = f"**{stream_info[key][0]}**"
119     return stream_all_instructions.format(item=item)
120 
121 
122 group_info = {
123     "all": ["All groups", "/#groups/all"],
124 }
125 
126 group_all_instructions = """
127 1. Click on the **gear** (<i class="zulip-icon zulip-icon-gear"></i>) icon in
128    the upper right corner of the web or desktop app.
129 
130 1. Select <i class="zulip-icon zulip-icon-user-cog"></i> **Group settings**.
131 
132 1. Click {item} in the upper left.
133 """
134 
135 
136 def group_handle_match(key: str) -> str:
137     if relative_help_links:
138         item = f"[{group_info[key][0]}]({group_info[key][1]})"
139     else:
140         item = f"**{group_info[key][0]}**"
141     return group_all_instructions.format(item=item)
142 
143 
144 draft_instructions = """
145 1. Click on <i class="fa fa-pencil"></i> **Drafts** in the left sidebar.
146 """
147 
148 scheduled_instructions = """
149 1. Click on <i class="fa fa-calendar"></i> **Scheduled messages** in the left
150    sidebar. If you do not see this link, you have no scheduled messages.
151 """
152 
153 recent_instructions = """
154 1. Click on <i class="fa fa-clock-o"></i> **Recent conversations** in the left
155    sidebar, or use the <kbd>T</kbd> keyboard shortcut..
156 """
157 
158 all_instructions = """
159 1. Click on <i class="fa fa-align-left"></i> **All messages** in the left
160    sidebar, or use the <kbd>A</kbd> keyboard shortcut.
161 """
162 
163 starred_instructions = """
164 1. Click on <i class="fa fa-star"></i> **Starred messages** in the left
165    sidebar, or by [searching](/help/search-for-messages) for `is:starred`.
166 """
167 
168 direct_instructions = """
169 1. In the left sidebar, click the **All direct messages**
170    (<i class="fa fa-align-right"></i>) icon to the right of the
171    **Direct messages** label, or use the <kbd>Shift</kbd> + <kbd>P</kbd>
172    keyboard shortcut.
173 """
174 
175 inbox_instructions = """
176 1. Click on <i class="zulip-icon zulip-icon-inbox"></i> **Inbox** in the left
177    sidebar, or use the <kbd>Shift</kbd> + <kbd>I</kbd> keyboard shortcut.
178 """
179 
180 message_info = {
181     "drafts": ["Drafts", "/#drafts", draft_instructions],
182     "scheduled": ["Scheduled messages", "/#scheduled", scheduled_instructions],
183     "recent": ["Recent conversations", "/#recent", recent_instructions],
184     "all": ["All messages", "/#all_messages", all_instructions],
185     "starred": ["Starred messages", "/#narrow/is/starred", starred_instructions],
186     "direct": ["All direct messages", "/#narrow/is/dm", direct_instructions],
187     "inbox": ["Inbox", "/#inbox", inbox_instructions],
188 }
189 
190 
191 def message_handle_match(key: str) -> str:
192     if relative_help_links:
193         return f"1. Go to [{message_info[key][0]}]({message_info[key][1]})."
194     else:
195         return message_info[key][2]
196 
197 
198 LINK_TYPE_HANDLERS = {
199     "gear": gear_handle_match,
200     "stream": stream_handle_match,
201     "message": message_handle_match,
202     "help": help_handle_match,
203     "group": group_handle_match,
204 }
205 
206 
207 class RelativeLinksHelpExtension(Extension):
208     @override
209     def extendMarkdown(self, md: Markdown) -> None:
210         """Add RelativeLinksHelpExtension to the Markdown instance."""
211         md.registerExtension(self)
212         md.preprocessors.register(
213             RelativeLinks(), "help_relative_links", PREPROCESSOR_PRIORITES["help_relative_links"]
214         )
215 
216 
217 relative_help_links: bool = False
218 
219 
220 def set_relative_help_links(value: bool) -> None:
221     global relative_help_links
222     relative_help_links = value
223 
224 
225 class RelativeLinks(Preprocessor):
226     @override
227     def run(self, lines: List[str]) -> List[str]:
228         done = False
229         while not done:
230             for line in lines:
231                 loc = lines.index(line)
232                 match = REGEXP.search(line)
233 
234                 if match:
235                     text = [self.handleMatch(match)]
236                     # The line that contains the directive to include the macro
237                     # may be preceded or followed by text or tags, in that case
238                     # we need to make sure that any preceding or following text
239                     # stays the same.
240                     line_split = REGEXP.split(line, maxsplit=0)
241                     preceding = line_split[0]
242                     following = line_split[-1]
243                     text = [preceding, *text, following]
244                     lines = lines[:loc] + text + lines[loc + 1 :]
245                     break
246             else:
247                 done = True
248         return lines
249 
250     def handleMatch(self, match: Match[str]) -> str:
251         return LINK_TYPE_HANDLERS[match.group("link_type")](match.group("key"))
252 
253 
254 def makeExtension(*args: Any, **kwargs: Any) -> RelativeLinksHelpExtension:
255     return RelativeLinksHelpExtension(*args, **kwargs)
256
```
--- 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/zerver/lib/markdown/help_relative_links.py b/zerver/lib/markdown/help_relative_links.py
--- a/zerver/lib/markdown/help_relative_links.py
+++ b/zerver/lib/markdown/help_relative_links.py
@@ -37,7 +37,7 @@
     ],
     "stats": ['<i class="zulip-icon zulip-icon-bar-chart"></i> Usage statistics', "/stats"],
     "integrations": ['<i class="zulip-icon-git-pull-request"></i> Integrations', "/integrations/"],
-    "plans": ['<i class="fa fa-rocket"></i> Plans and pricing', "/plans/"],
+    "plans": ['<i class="zulip-icon zulip-icon-rocket"></i> Plans and pricing', "/plans/"],
     "billing": ['<i class="zulip-icon zulip-icon-credit-card"></i> Billing', "/billing/"],
     "about-zulip": ["About Zulip", "/#about-zulip"],
 }

{"golden_diff": "diff --git a/zerver/lib/markdown/help_relative_links.py b/zerver/lib/markdown/help_relative_links.py\n--- a/zerver/lib/markdown/help_relative_links.py\n+++ b/zerver/lib/markdown/help_relative_links.py\n@@ -37,7 +37,7 @@\n     ],\n     \"stats\": ['<i class=\"zulip-icon zulip-icon-bar-chart\"></i> Usage statistics', \"/stats\"],\n     \"integrations\": ['<i class=\"zulip-icon-git-pull-request\"></i> Integrations', \"/integrations/\"],\n-    \"plans\": ['<i class=\"fa fa-rocket\"></i> Plans and pricing', \"/plans/\"],\n+    \"plans\": ['<i class=\"zulip-icon zulip-icon-rocket\"></i> Plans and pricing', \"/plans/\"],\n     \"billing\": ['<i class=\"zulip-icon zulip-icon-credit-card\"></i> Billing', \"/billing/\"],\n     \"about-zulip\": [\"About Zulip\", \"/#about-zulip\"],\n }\n", "issue": "Update Plans and pricing icon\nWe should update the rocket icon everywhere it shows up in the gear menu (Plans and pricing, Plan management) to:\r\n\r\n<img width=\"128\" alt=\"rocket\" src=\"https://github.com/zulip/zulip/assets/2090066/a951bc3b-1d95-4ec5-b5a2-3cf9d1ba88f4\">\r\n\r\n![rocket](https://github.com/zulip/zulip/assets/2090066/883735c4-9a2f-49e2-a629-ba8b43d80974)\r\n\r\n\r\nsource: https://lucide.dev/icons/rocket\n", "before_files": [{"content": "import re\nfrom typing import Any, List, Match\n\nfrom markdown import Markdown\nfrom markdown.extensions import Extension\nfrom markdown.preprocessors import Preprocessor\nfrom typing_extensions import override\n\nfrom zerver.lib.markdown.priorities import PREPROCESSOR_PRIORITES\n\n# There is a lot of duplicated code between this file and\n# help_settings_links.py. So if you're making a change here consider making\n# it there as well.\n\nREGEXP = re.compile(r\"\\{relative\\|(?P<link_type>.*?)\\|(?P<key>.*?)\\}\")\n\ngear_info = {\n    # The pattern is key: [name, link]\n    # key is from REGEXP: `{relative|gear|key}`\n    # name is what the item is called in the gear menu: `Select **name**.`\n    # link is used for relative links: `Select [name](link).`\n    \"stream-settings\": [\n        '<i class=\"zulip-icon zulip-icon-hash\"></i> Stream settings',\n        \"/#streams/subscribed\",\n    ],\n    \"settings\": [\n        '<i class=\"zulip-icon zulip-icon-tool\"></i> Personal Settings',\n        \"/#settings/profile\",\n    ],\n    \"organization-settings\": [\n        '<i class=\"zulip-icon zulip-icon-building\"></i> Organization settings',\n        \"/#organization/organization-profile\",\n    ],\n    \"group-settings\": [\n        '<i class=\"zulip-icon zulip-icon-user-cog\"></i> Group settings',\n        \"/#groups/your\",\n    ],\n    \"stats\": ['<i class=\"zulip-icon zulip-icon-bar-chart\"></i> Usage statistics', \"/stats\"],\n    \"integrations\": ['<i class=\"zulip-icon-git-pull-request\"></i> Integrations', \"/integrations/\"],\n    \"plans\": ['<i class=\"fa fa-rocket\"></i> Plans and pricing', \"/plans/\"],\n    \"billing\": ['<i class=\"zulip-icon zulip-icon-credit-card\"></i> Billing', \"/billing/\"],\n    \"about-zulip\": [\"About Zulip\", \"/#about-zulip\"],\n}\n\ngear_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select {item}.\n\"\"\"\n\n\ndef gear_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{gear_info[key][0]}]({gear_info[key][1]})\"\n    else:\n        item = f\"**{gear_info[key][0]}**\"\n    return gear_instructions.format(item=item)\n\n\nhelp_info = {\n    # The pattern is key: [name, link]\n    # key is from REGEXP: `{relative|help|key}`\n    # name is what the item is called in the help menu: `Select **name**.`\n    # link is used for relative links: `Select [name](link).`\n    \"keyboard-shortcuts\": [\n        '<i class=\"zulip-icon zulip-icon-keyboard\"></i> Keyboard shortcuts',\n        \"/#keyboard-shortcuts\",\n    ],\n    \"message-formatting\": [\n        '<i class=\"zulip-icon zulip-icon-edit\"></i> Message formatting',\n        \"/#message-formatting\",\n    ],\n    \"search-filters\": [\n        '<i class=\"zulip-icon zulip-icon-manage-search\"></i> Search filters',\n        \"/#search-operators\",\n    ],\n    \"about-zulip\": [\n        '<i class=\"zulip-icon zulip-icon-info\"></i> About Zulip',\n        \"/#about-zulip\",\n    ],\n}\n\nhelp_instructions = \"\"\"\n1. Click on the **Help menu** (<i class=\"zulip-icon zulip-icon-help\"></i>) icon\n   in the upper right corner of the app.\n\n1. Select {item}.\n\"\"\"\n\n\ndef help_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{help_info[key][0]}]({help_info[key][1]})\"\n    else:\n        item = f\"**{help_info[key][0]}**\"\n    return help_instructions.format(item=item)\n\n\nstream_info = {\n    \"all\": [\"All streams\", \"/#streams/all\"],\n}\n\nstream_all_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select <i class=\"zulip-icon zulip-icon-hash\"></i> **Stream settings**.\n\n1. Click {item} in the upper left.\n\"\"\"\n\n\ndef stream_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{stream_info[key][0]}]({stream_info[key][1]})\"\n    else:\n        item = f\"**{stream_info[key][0]}**\"\n    return stream_all_instructions.format(item=item)\n\n\ngroup_info = {\n    \"all\": [\"All groups\", \"/#groups/all\"],\n}\n\ngroup_all_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select <i class=\"zulip-icon zulip-icon-user-cog\"></i> **Group settings**.\n\n1. Click {item} in the upper left.\n\"\"\"\n\n\ndef group_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{group_info[key][0]}]({group_info[key][1]})\"\n    else:\n        item = f\"**{group_info[key][0]}**\"\n    return group_all_instructions.format(item=item)\n\n\ndraft_instructions = \"\"\"\n1. Click on <i class=\"fa fa-pencil\"></i> **Drafts** in the left sidebar.\n\"\"\"\n\nscheduled_instructions = \"\"\"\n1. Click on <i class=\"fa fa-calendar\"></i> **Scheduled messages** in the left\n   sidebar. If you do not see this link, you have no scheduled messages.\n\"\"\"\n\nrecent_instructions = \"\"\"\n1. Click on <i class=\"fa fa-clock-o\"></i> **Recent conversations** in the left\n   sidebar, or use the <kbd>T</kbd> keyboard shortcut..\n\"\"\"\n\nall_instructions = \"\"\"\n1. Click on <i class=\"fa fa-align-left\"></i> **All messages** in the left\n   sidebar, or use the <kbd>A</kbd> keyboard shortcut.\n\"\"\"\n\nstarred_instructions = \"\"\"\n1. Click on <i class=\"fa fa-star\"></i> **Starred messages** in the left\n   sidebar, or by [searching](/help/search-for-messages) for `is:starred`.\n\"\"\"\n\ndirect_instructions = \"\"\"\n1. In the left sidebar, click the **All direct messages**\n   (<i class=\"fa fa-align-right\"></i>) icon to the right of the\n   **Direct messages** label, or use the <kbd>Shift</kbd> + <kbd>P</kbd>\n   keyboard shortcut.\n\"\"\"\n\ninbox_instructions = \"\"\"\n1. Click on <i class=\"zulip-icon zulip-icon-inbox\"></i> **Inbox** in the left\n   sidebar, or use the <kbd>Shift</kbd> + <kbd>I</kbd> keyboard shortcut.\n\"\"\"\n\nmessage_info = {\n    \"drafts\": [\"Drafts\", \"/#drafts\", draft_instructions],\n    \"scheduled\": [\"Scheduled messages\", \"/#scheduled\", scheduled_instructions],\n    \"recent\": [\"Recent conversations\", \"/#recent\", recent_instructions],\n    \"all\": [\"All messages\", \"/#all_messages\", all_instructions],\n    \"starred\": [\"Starred messages\", \"/#narrow/is/starred\", starred_instructions],\n    \"direct\": [\"All direct messages\", \"/#narrow/is/dm\", direct_instructions],\n    \"inbox\": [\"Inbox\", \"/#inbox\", inbox_instructions],\n}\n\n\ndef message_handle_match(key: str) -> str:\n    if relative_help_links:\n        return f\"1. Go to [{message_info[key][0]}]({message_info[key][1]}).\"\n    else:\n        return message_info[key][2]\n\n\nLINK_TYPE_HANDLERS = {\n    \"gear\": gear_handle_match,\n    \"stream\": stream_handle_match,\n    \"message\": message_handle_match,\n    \"help\": help_handle_match,\n    \"group\": group_handle_match,\n}\n\n\nclass RelativeLinksHelpExtension(Extension):\n    @override\n    def extendMarkdown(self, md: Markdown) -> None:\n        \"\"\"Add RelativeLinksHelpExtension to the Markdown instance.\"\"\"\n        md.registerExtension(self)\n        md.preprocessors.register(\n            RelativeLinks(), \"help_relative_links\", PREPROCESSOR_PRIORITES[\"help_relative_links\"]\n        )\n\n\nrelative_help_links: bool = False\n\n\ndef set_relative_help_links(value: bool) -> None:\n    global relative_help_links\n    relative_help_links = value\n\n\nclass RelativeLinks(Preprocessor):\n    @override\n    def run(self, lines: List[str]) -> List[str]:\n        done = False\n        while not done:\n            for line in lines:\n                loc = lines.index(line)\n                match = REGEXP.search(line)\n\n                if match:\n                    text = [self.handleMatch(match)]\n                    # The line that contains the directive to include the macro\n                    # may be preceded or followed by text or tags, in that case\n                    # we need to make sure that any preceding or following text\n                    # stays the same.\n                    line_split = REGEXP.split(line, maxsplit=0)\n                    preceding = line_split[0]\n                    following = line_split[-1]\n                    text = [preceding, *text, following]\n                    lines = lines[:loc] + text + lines[loc + 1 :]\n                    break\n            else:\n                done = True\n        return lines\n\n    def handleMatch(self, match: Match[str]) -> str:\n        return LINK_TYPE_HANDLERS[match.group(\"link_type\")](match.group(\"key\"))\n\n\ndef makeExtension(*args: Any, **kwargs: Any) -> RelativeLinksHelpExtension:\n    return RelativeLinksHelpExtension(*args, **kwargs)\n", "path": "zerver/lib/markdown/help_relative_links.py"}], "after_files": [{"content": "import re\nfrom typing import Any, List, Match\n\nfrom markdown import Markdown\nfrom markdown.extensions import Extension\nfrom markdown.preprocessors import Preprocessor\nfrom typing_extensions import override\n\nfrom zerver.lib.markdown.priorities import PREPROCESSOR_PRIORITES\n\n# There is a lot of duplicated code between this file and\n# help_settings_links.py. So if you're making a change here consider making\n# it there as well.\n\nREGEXP = re.compile(r\"\\{relative\\|(?P<link_type>.*?)\\|(?P<key>.*?)\\}\")\n\ngear_info = {\n    # The pattern is key: [name, link]\n    # key is from REGEXP: `{relative|gear|key}`\n    # name is what the item is called in the gear menu: `Select **name**.`\n    # link is used for relative links: `Select [name](link).`\n    \"stream-settings\": [\n        '<i class=\"zulip-icon zulip-icon-hash\"></i> Stream settings',\n        \"/#streams/subscribed\",\n    ],\n    \"settings\": [\n        '<i class=\"zulip-icon zulip-icon-tool\"></i> Personal Settings',\n        \"/#settings/profile\",\n    ],\n    \"organization-settings\": [\n        '<i class=\"zulip-icon zulip-icon-building\"></i> Organization settings',\n        \"/#organization/organization-profile\",\n    ],\n    \"group-settings\": [\n        '<i class=\"zulip-icon zulip-icon-user-cog\"></i> Group settings',\n        \"/#groups/your\",\n    ],\n    \"stats\": ['<i class=\"zulip-icon zulip-icon-bar-chart\"></i> Usage statistics', \"/stats\"],\n    \"integrations\": ['<i class=\"zulip-icon-git-pull-request\"></i> Integrations', \"/integrations/\"],\n    \"plans\": ['<i class=\"zulip-icon zulip-icon-rocket\"></i> Plans and pricing', \"/plans/\"],\n    \"billing\": ['<i class=\"zulip-icon zulip-icon-credit-card\"></i> Billing', \"/billing/\"],\n    \"about-zulip\": [\"About Zulip\", \"/#about-zulip\"],\n}\n\ngear_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select {item}.\n\"\"\"\n\n\ndef gear_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{gear_info[key][0]}]({gear_info[key][1]})\"\n    else:\n        item = f\"**{gear_info[key][0]}**\"\n    return gear_instructions.format(item=item)\n\n\nhelp_info = {\n    # The pattern is key: [name, link]\n    # key is from REGEXP: `{relative|help|key}`\n    # name is what the item is called in the help menu: `Select **name**.`\n    # link is used for relative links: `Select [name](link).`\n    \"keyboard-shortcuts\": [\n        '<i class=\"zulip-icon zulip-icon-keyboard\"></i> Keyboard shortcuts',\n        \"/#keyboard-shortcuts\",\n    ],\n    \"message-formatting\": [\n        '<i class=\"zulip-icon zulip-icon-edit\"></i> Message formatting',\n        \"/#message-formatting\",\n    ],\n    \"search-filters\": [\n        '<i class=\"zulip-icon zulip-icon-manage-search\"></i> Search filters',\n        \"/#search-operators\",\n    ],\n    \"about-zulip\": [\n        '<i class=\"zulip-icon zulip-icon-info\"></i> About Zulip',\n        \"/#about-zulip\",\n    ],\n}\n\nhelp_instructions = \"\"\"\n1. Click on the **Help menu** (<i class=\"zulip-icon zulip-icon-help\"></i>) icon\n   in the upper right corner of the app.\n\n1. Select {item}.\n\"\"\"\n\n\ndef help_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{help_info[key][0]}]({help_info[key][1]})\"\n    else:\n        item = f\"**{help_info[key][0]}**\"\n    return help_instructions.format(item=item)\n\n\nstream_info = {\n    \"all\": [\"All streams\", \"/#streams/all\"],\n}\n\nstream_all_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select <i class=\"zulip-icon zulip-icon-hash\"></i> **Stream settings**.\n\n1. Click {item} in the upper left.\n\"\"\"\n\n\ndef stream_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{stream_info[key][0]}]({stream_info[key][1]})\"\n    else:\n        item = f\"**{stream_info[key][0]}**\"\n    return stream_all_instructions.format(item=item)\n\n\ngroup_info = {\n    \"all\": [\"All groups\", \"/#groups/all\"],\n}\n\ngroup_all_instructions = \"\"\"\n1. Click on the **gear** (<i class=\"zulip-icon zulip-icon-gear\"></i>) icon in\n   the upper right corner of the web or desktop app.\n\n1. Select <i class=\"zulip-icon zulip-icon-user-cog\"></i> **Group settings**.\n\n1. Click {item} in the upper left.\n\"\"\"\n\n\ndef group_handle_match(key: str) -> str:\n    if relative_help_links:\n        item = f\"[{group_info[key][0]}]({group_info[key][1]})\"\n    else:\n        item = f\"**{group_info[key][0]}**\"\n    return group_all_instructions.format(item=item)\n\n\ndraft_instructions = \"\"\"\n1. Click on <i class=\"fa fa-pencil\"></i> **Drafts** in the left sidebar.\n\"\"\"\n\nscheduled_instructions = \"\"\"\n1. Click on <i class=\"fa fa-calendar\"></i> **Scheduled messages** in the left\n   sidebar. If you do not see this link, you have no scheduled messages.\n\"\"\"\n\nrecent_instructions = \"\"\"\n1. Click on <i class=\"fa fa-clock-o\"></i> **Recent conversations** in the left\n   sidebar, or use the <kbd>T</kbd> keyboard shortcut..\n\"\"\"\n\nall_instructions = \"\"\"\n1. Click on <i class=\"fa fa-align-left\"></i> **All messages** in the left\n   sidebar, or use the <kbd>A</kbd> keyboard shortcut.\n\"\"\"\n\nstarred_instructions = \"\"\"\n1. Click on <i class=\"fa fa-star\"></i> **Starred messages** in the left\n   sidebar, or by [searching](/help/search-for-messages) for `is:starred`.\n\"\"\"\n\ndirect_instructions = \"\"\"\n1. In the left sidebar, click the **All direct messages**\n   (<i class=\"fa fa-align-right\"></i>) icon to the right of the\n   **Direct messages** label, or use the <kbd>Shift</kbd> + <kbd>P</kbd>\n   keyboard shortcut.\n\"\"\"\n\ninbox_instructions = \"\"\"\n1. Click on <i class=\"zulip-icon zulip-icon-inbox\"></i> **Inbox** in the left\n   sidebar, or use the <kbd>Shift</kbd> + <kbd>I</kbd> keyboard shortcut.\n\"\"\"\n\nmessage_info = {\n    \"drafts\": [\"Drafts\", \"/#drafts\", draft_instructions],\n    \"scheduled\": [\"Scheduled messages\", \"/#scheduled\", scheduled_instructions],\n    \"recent\": [\"Recent conversations\", \"/#recent\", recent_instructions],\n    \"all\": [\"All messages\", \"/#all_messages\", all_instructions],\n    \"starred\": [\"Starred messages\", \"/#narrow/is/starred\", starred_instructions],\n    \"direct\": [\"All direct messages\", \"/#narrow/is/dm\", direct_instructions],\n    \"inbox\": [\"Inbox\", \"/#inbox\", inbox_instructions],\n}\n\n\ndef message_handle_match(key: str) -> str:\n    if relative_help_links:\n        return f\"1. Go to [{message_info[key][0]}]({message_info[key][1]}).\"\n    else:\n        return message_info[key][2]\n\n\nLINK_TYPE_HANDLERS = {\n    \"gear\": gear_handle_match,\n    \"stream\": stream_handle_match,\n    \"message\": message_handle_match,\n    \"help\": help_handle_match,\n    \"group\": group_handle_match,\n}\n\n\nclass RelativeLinksHelpExtension(Extension):\n    @override\n    def extendMarkdown(self, md: Markdown) -> None:\n        \"\"\"Add RelativeLinksHelpExtension to the Markdown instance.\"\"\"\n        md.registerExtension(self)\n        md.preprocessors.register(\n            RelativeLinks(), \"help_relative_links\", PREPROCESSOR_PRIORITES[\"help_relative_links\"]\n        )\n\n\nrelative_help_links: bool = False\n\n\ndef set_relative_help_links(value: bool) -> None:\n    global relative_help_links\n    relative_help_links = value\n\n\nclass RelativeLinks(Preprocessor):\n    @override\n    def run(self, lines: List[str]) -> List[str]:\n        done = False\n        while not done:\n            for line in lines:\n                loc = lines.index(line)\n                match = REGEXP.search(line)\n\n                if match:\n                    text = [self.handleMatch(match)]\n                    # The line that contains the directive to include the macro\n                    # may be preceded or followed by text or tags, in that case\n                    # we need to make sure that any preceding or following text\n                    # stays the same.\n                    line_split = REGEXP.split(line, maxsplit=0)\n                    preceding = line_split[0]\n                    following = line_split[-1]\n                    text = [preceding, *text, following]\n                    lines = lines[:loc] + text + lines[loc + 1 :]\n                    break\n            else:\n                done = True\n        return lines\n\n    def handleMatch(self, match: Match[str]) -> str:\n        return LINK_TYPE_HANDLERS[match.group(\"link_type\")](match.group(\"key\"))\n\n\ndef makeExtension(*args: Any, **kwargs: Any) -> RelativeLinksHelpExtension:\n    return RelativeLinksHelpExtension(*args, **kwargs)\n", "path": "zerver/lib/markdown/help_relative_links.py"}]}