1<!DOCTYPE HTML>
2<html lang="{{ language }}" data-theme="{{ default_theme }}" data-color-scheme="{{ default_theme }}" dir="{{ text_direction }}">
3 <head>
4 <!-- Book generated using mdBook -->
5 <meta charset="UTF-8">
6 <title>{{ title }}</title>
7 {{#if is_print }}
8 <meta name="robots" content="noindex">
9 {{/if}}
10 {{#if base_url}}
11 <base href="{{ base_url }}">
12 {{/if}}
13
14
15 <!-- Custom HTML head -->
16 {{> head}}
17
18 <meta name="description" content="#description#">
19 <meta name="viewport" content="width=device-width, initial-scale=1">
20 <meta name="theme-color" content="#ffffff">
21
22 <link rel="shortcut icon" href="{{ path_to_root }}favicon.png">
23 <link rel="stylesheet" href="{{ path_to_root }}css/variables.css">
24 <link rel="stylesheet" href="{{ path_to_root }}css/general.css">
25 <link rel="stylesheet" href="{{ path_to_root }}css/chrome.css">
26 {{#if print_enable}}
27 <link rel="stylesheet" href="{{ path_to_root }}css/print.css" media="print">
28 {{/if}}
29
30 <!-- Fonts -->
31 <link rel="stylesheet" href="{{ path_to_root }}FontAwesome/css/font-awesome.css">
32 {{#if copy_fonts}}
33 <link rel="stylesheet" href="{{ path_to_root }}fonts/fonts.css">
34 {{/if}}
35
36 <!-- Highlight.js Stylesheets -->
37 <link rel="stylesheet" href="{{ path_to_root }}highlight.css">
38 <link rel="stylesheet" href="{{ path_to_root }}tomorrow-night.css">
39 <link rel="stylesheet" href="{{ path_to_root }}ayu-highlight.css">
40
41 <!-- Custom theme stylesheets -->
42 {{#each additional_css}}
43 <link rel="stylesheet" href="{{ ../path_to_root }}{{ this }}">
44 {{/each}}
45
46 {{#if mathjax_support}}
47 <!-- MathJax -->
48 <script async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
49 {{/if}}
50 </head>
51 <body class="no-js">
52 <div id="body-container">
53 <div class="noise-pattern" style="background-image: url('https://cdn.zed.dev/images/noise.png');"></div>
54
55 <!-- Provide site root to javascript -->
56 <script>
57 var path_to_root = "{{ path_to_root }}";
58 var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "{{ preferred_dark_theme }}" : "{{ default_theme }}";
59 </script>
60
61 <!-- Support dark mode -->
62 <script>
63 var theme;
64 try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
65 if (theme === null || theme === undefined) {
66 theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
67 }
68 var html = document.querySelector('html');
69 html.classList.remove('light', 'dark')
70 html.classList.add(theme);
71 var body = document.querySelector('body');
72 body.classList.remove('no-js')
73 body.classList.add('js');
74 </script>
75
76 <header class="header-bar">
77 <div class="left-container">
78 <a href="/" class="logo-nav">
79 <img src="https://zed.dev/logo_icon.webp" class="icon-logo-img" alt="Zed Industries" style="height: 26px;">
80 </a>
81 <button id="sidebar-toggle" class="icon-button ib-hidden-desktop" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar" aria-expanded="false">
82 <i class="fa fa-bars"></i>
83 </button>
84 </div>
85 {{#if search_enabled}}
86 <button id="search-toggle" class="search-button" type="button" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
87 <i class="icon fa fa-search"></i>
88 <span class="search-content-desktop">
89 <span class="placeholder">Search docs…</span>
90 <kbd>S</kbd>
91 </span>
92 <span class="search-content-mobile">
93 <span class="placeholder">Search…</span>
94 </span>
95 </button>
96 {{/if}}
97 <div class="right-container">
98 <button id="theme-toggle" class="icon-button" type="button" title="Change Theme" aria-label="Change Theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
99 <i class="fa fa-paint-brush"></i>
100 </button>
101
102 <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
103 <li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
104 <li role="none"><button role="menuitem" class="theme" id="dark">Dark</button></li>
105 </ul>
106
107 <button id="copy-markdown-toggle" class="icon-button ib-hidden-mobile" type="button" title="Copy Page as Markdown" aria-label="Copy page as markdown">
108 <i class="fa fa-copy"></i>
109 </button>
110
111 <a class="download-button" href="https://zed.dev/download" title="Download Zed" aria-label="Download Zed">
112 Download
113 </a>
114 {{#if git_repository_url}}
115 <a href="{{git_repository_url}}" title="Git repository" aria-label="Git repository">
116 <i id="git-repository-button" class="fa {{git_repository_icon}}"></i>
117 </a>
118 {{/if}}
119 {{#if git_repository_edit_url}}
120 <a href="{{git_repository_edit_url}}" title="Suggest an edit" aria-label="Suggest an edit">
121 <i id="git-edit-button" class="fa fa-edit"></i>
122 </a>
123 {{/if}}
124 </div>
125 </header>
126
127 <div id="page-wrapper" class="page-wrapper">
128
129 {{#if search_enabled}}
130 <div class="search-container">
131 <div id="search-wrapper" class="search-modal hidden">
132 <form id="searchbar-outer" class="searchbar-outer">
133 <input type="search" id="searchbar" name="searchbar" placeholder="Search…" aria-controls="searchresults-outer" aria-describedby="searchresults-header">
134 </form>
135 <div id="searchresults-outer" class="searchresults-outer">
136 <div id="searchresults-header" class="searchresults-header"></div>
137 <ul id="searchresults">
138 </ul>
139 </div>
140 </div>
141 </div>
142 {{/if}}
143
144 <nav id="sidebar" class="sidebar" aria-label="Table of contents">
145 <div class="sidebar-scrollbox">
146 {{#toc}}{{/toc}}
147 </div>
148 <div style="display: none;" id="sidebar-resize-handle" class="sidebar-resize-handle">
149 <div class="sidebar-resize-indicator"></div>
150 </div>
151 </nav>
152
153 <!-- Mobile sidebar toggle -->
154 <script>
155 (function() {
156 var sidebarToggle = document.getElementById('sidebar-toggle');
157 var sidebar = document.getElementById('sidebar');
158
159 sidebarToggle.addEventListener('click', function() {
160 var isOpen = document.body.classList.toggle('sidebar-open');
161 sidebarToggle.setAttribute('aria-expanded', isOpen);
162 sidebar.setAttribute('aria-hidden', !isOpen);
163 });
164
165 // Close sidebar when clicking a link inside it (on mobile)
166 sidebar.addEventListener('click', function(e) {
167 if (e.target.tagName === 'A' && window.innerWidth < 620) {
168 document.body.classList.remove('sidebar-open');
169 sidebarToggle.setAttribute('aria-expanded', 'false');
170 sidebar.setAttribute('aria-hidden', 'true');
171 }
172 });
173 })();
174 </script>
175
176 <!-- Search backdrop handlers -->
177 <script>
178 (function() {
179 var searchWrapper = document.getElementById('search-wrapper');
180 var searchContainer = document.querySelector('.search-container');
181 var searchResults = document.getElementById('searchresults');
182
183 if (!searchWrapper || !searchContainer) return;
184
185 searchContainer.addEventListener('click', function(e) {
186 if (e.target === searchContainer) {
187 searchWrapper.classList.add('hidden');
188 }
189 });
190
191 if (searchResults) {
192 searchResults.addEventListener('click', function(e) {
193 if (e.target.tagName === 'A' || e.target.closest('a')) {
194 searchWrapper.classList.add('hidden');
195 }
196 });
197 }
198 })();
199 </script>
200
201 <!-- Insert section spacers and apply collapsed state before scroll restoration to prevent layout shift/flicker -->
202 <script>
203 (function() {
204 var chapterList = document.querySelector('#sidebar ol.chapter');
205 if (!chapterList) return;
206
207 var collapsedSections = [];
208 try {
209 var stored = sessionStorage.getItem('sidebar-collapsed-sections');
210 if (stored) {
211 collapsedSections = JSON.parse(stored);
212 }
213 } catch (e) {}
214
215 var partTitles = chapterList.querySelectorAll('li.part-title');
216 var previousPartTitle = null;
217
218 partTitles.forEach(function(partTitle, index) {
219 partTitle._sectionName = partTitle.textContent.trim();
220
221 // Insert a spacer before this part-title (except for the first one)
222 if (index > 0) {
223 var spacer = document.createElement('li');
224 spacer.className = 'section-spacer';
225 partTitle.parentNode.insertBefore(spacer, partTitle);
226
227 if (previousPartTitle) {
228 previousPartTitle._spacerAfter = spacer;
229 }
230 }
231
232 var isCollapsed = collapsedSections.includes(partTitle._sectionName);
233 if (isCollapsed) {
234 // Hide all siblings until next part-title
235 var sibling = partTitle.nextElementSibling;
236 while (sibling && !sibling.classList.contains('part-title')) {
237 sibling.classList.add('section-hidden');
238 sibling = sibling.nextElementSibling;
239 }
240 // Hide the spacer after this section (will be set on next iteration)
241 partTitle._isCollapsed = true;
242 }
243
244 // If previous section was collapsed, hide its spacer
245 if (previousPartTitle && previousPartTitle._isCollapsed && previousPartTitle._spacerAfter) {
246 previousPartTitle._spacerAfter.classList.add('section-hidden');
247 }
248
249 previousPartTitle = partTitle;
250 });
251
252 // Handle the last section's spacer if it was collapsed
253 if (previousPartTitle && previousPartTitle._isCollapsed && previousPartTitle._spacerAfter) {
254 previousPartTitle._spacerAfter.classList.add('section-hidden');
255 }
256 })();
257 </script>
258
259 <!-- Track and set sidebar scroll position -->
260 <script>
261 var sidebarScrollbox = document.querySelector('#sidebar .sidebar-scrollbox');
262 sidebarScrollbox.addEventListener('click', function(e) {
263 if (e.target.tagName === 'A') {
264 sessionStorage.setItem('sidebar-scroll', sidebarScrollbox.scrollTop);
265 }
266 }, { passive: true });
267 var sidebarScrollTop = sessionStorage.getItem('sidebar-scroll');
268 sessionStorage.removeItem('sidebar-scroll');
269 if (sidebarScrollTop) {
270 // preserve sidebar scroll position when navigating via links within sidebar
271 sidebarScrollbox.scrollTop = sidebarScrollTop;
272 } else {
273 // scroll sidebar to current active section when navigating via "next/previous chapter" buttons
274 var activeSection = document.querySelector('#sidebar .active');
275 if (activeSection) {
276 activeSection.scrollIntoView({ block: 'center' });
277 }
278 }
279 </script>
280
281 <div class="page">
282 <div id="content" class="content">
283 <main>
284 {{{ content }}}
285 <div class="footer-buttons">
286 {{#previous}}
287 <a rel="prev" href="{{ path_to_root }}{{link}}" class="footer-button" title="{{title}}">
288 <i class="fa fa-angle-left"></i>
289 {{title}}
290 </a>
291 {{/previous}}
292 {{#next}}
293 <a rel="next" href="{{ path_to_root }}{{link}}" class="footer-button" title="{{title}}">
294 {{title}}
295 <i class="fa fa-angle-right"></i>
296 </a>
297 {{/next}}
298 </div>
299 </main>
300 <div class="toc-container">
301 <nav class="pagetoc">
302 <p class="toc-title">On this page</p>
303 </nav>
304 </div>
305 </div>
306 </div>
307 </div>
308
309 {{#if live_reload_endpoint}}
310 <!-- Livereload script (if served using the cli tool) -->
311 <script>
312 const wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
313 const wsAddress = wsProtocol + "//" + location.host + "/" + "{{{live_reload_endpoint}}}";
314 const socket = new WebSocket(wsAddress);
315 socket.onmessage = function (event) {
316 if (event.data === "reload") {
317 socket.close();
318 location.reload();
319 }
320 };
321
322 window.onbeforeunload = function() {
323 socket.close();
324 }
325 </script>
326 {{/if}}
327
328 {{#if playground_line_numbers}}
329 <script>
330 window.playground_line_numbers = true;
331 </script>
332 {{/if}}
333
334 {{#if playground_copyable}}
335 <script>
336 window.playground_copyable = true;
337 </script>
338 {{/if}}
339
340 {{#if playground_js}}
341 <script src="{{ path_to_root }}ace.js"></script>
342 <script src="{{ path_to_root }}editor.js"></script>
343 <script src="{{ path_to_root }}mode-rust.js"></script>
344 <script src="{{ path_to_root }}theme-dawn.js"></script>
345 <script src="{{ path_to_root }}theme-tomorrow_night.js"></script>
346 {{/if}}
347
348 {{#if search_js}}
349 <script src="{{ path_to_root }}elasticlunr.min.js"></script>
350 <script src="{{ path_to_root }}mark.min.js"></script>
351 <script src="{{ path_to_root }}searcher.js"></script>
352 {{/if}}
353
354 <script src="{{ path_to_root }}clipboard.min.js"></script>
355 <script src="{{ path_to_root }}highlight.js"></script>
356 <script src="{{ path_to_root }}book.js"></script>
357
358 <!-- Custom JS scripts -->
359 {{#each additional_js}}
360 <script src="{{ ../path_to_root }}{{this}}"></script>
361 {{/each}}
362
363 {{#if is_print}}
364 {{#if mathjax_support}}
365 <script>
366 window.addEventListener('load', function() {
367 MathJax.Hub.Register.StartupHook('End', function() {
368 window.setTimeout(window.print, 100);
369 });
370 });
371 </script>
372 {{else}}
373 <script>
374 window.addEventListener('load', function() {
375 window.setTimeout(window.print, 100);
376 });
377 </script>
378 {{/if}}
379 {{/if}}
380
381 <script>
382 (function() {
383 var theme = localStorage.getItem('mdbook-theme');
384 var html = document.querySelector('html');
385 if (theme) {
386 html.setAttribute('data-theme', theme);
387 html.setAttribute('data-color-scheme', theme);
388 html.className = theme;
389 } else {
390 var systemPreference = window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
391 html.setAttribute('data-theme', systemPreference);
392 html.setAttribute('data-color-scheme', systemPreference);
393 html.className = systemPreference;
394 }
395 })();
396 </script>
397
398 <!-- Amplitude Analytics -->
399 <script>
400 (function() {
401 var amplitudeKey = '#amplitude_key#';
402 if (amplitudeKey && amplitudeKey.indexOf('#') === -1) {
403 var script = document.createElement('script');
404 script.src = 'https://cdn.amplitude.com/script/' + amplitudeKey + '.js';
405 script.onload = function() {
406 window.amplitude.init(amplitudeKey, {
407 fetchRemoteConfig: true,
408 autocapture: true
409 });
410 };
411 document.head.appendChild(script);
412 }
413 })();
414 </script>
415 </div>
416 </body>
417</html>