]> git.proxmox.com Git - rustc.git/blob - src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_ext.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / rust-analyzer / src / lsp_ext.rs
1 //! rust-analyzer extensions to the LSP.
2
3 use std::{collections::HashMap, path::PathBuf};
4
5 use ide_db::line_index::WideEncoding;
6 use lsp_types::request::Request;
7 use lsp_types::{
8 notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
9 PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
10 };
11 use lsp_types::{PositionEncodingKind, Url};
12 use serde::{Deserialize, Serialize};
13
14 use crate::line_index::PositionEncoding;
15
16 pub enum AnalyzerStatus {}
17
18 impl Request for AnalyzerStatus {
19 type Params = AnalyzerStatusParams;
20 type Result = String;
21 const METHOD: &'static str = "rust-analyzer/analyzerStatus";
22 }
23
24 #[derive(Deserialize, Serialize, Debug)]
25 #[serde(rename_all = "camelCase")]
26 pub struct AnalyzerStatusParams {
27 pub text_document: Option<TextDocumentIdentifier>,
28 }
29
30 #[derive(Deserialize, Serialize, Debug)]
31 #[serde(rename_all = "camelCase")]
32 pub struct CrateInfoResult {
33 pub name: Option<String>,
34 pub version: Option<String>,
35 pub path: Url,
36 }
37 pub enum FetchDependencyList {}
38
39 impl Request for FetchDependencyList {
40 type Params = FetchDependencyListParams;
41 type Result = FetchDependencyListResult;
42 const METHOD: &'static str = "rust-analyzer/fetchDependencyList";
43 }
44
45 #[derive(Deserialize, Serialize, Debug)]
46 #[serde(rename_all = "camelCase")]
47 pub struct FetchDependencyListParams {}
48
49 #[derive(Deserialize, Serialize, Debug)]
50 #[serde(rename_all = "camelCase")]
51 pub struct FetchDependencyListResult {
52 pub crates: Vec<CrateInfoResult>,
53 }
54
55 pub enum MemoryUsage {}
56
57 impl Request for MemoryUsage {
58 type Params = ();
59 type Result = String;
60 const METHOD: &'static str = "rust-analyzer/memoryUsage";
61 }
62
63 pub enum ShuffleCrateGraph {}
64
65 impl Request for ShuffleCrateGraph {
66 type Params = ();
67 type Result = ();
68 const METHOD: &'static str = "rust-analyzer/shuffleCrateGraph";
69 }
70
71 pub enum ReloadWorkspace {}
72
73 impl Request for ReloadWorkspace {
74 type Params = ();
75 type Result = ();
76 const METHOD: &'static str = "rust-analyzer/reloadWorkspace";
77 }
78
79 pub enum RebuildProcMacros {}
80
81 impl Request for RebuildProcMacros {
82 type Params = ();
83 type Result = ();
84 const METHOD: &'static str = "rust-analyzer/rebuildProcMacros";
85 }
86
87 pub enum SyntaxTree {}
88
89 impl Request for SyntaxTree {
90 type Params = SyntaxTreeParams;
91 type Result = String;
92 const METHOD: &'static str = "rust-analyzer/syntaxTree";
93 }
94
95 #[derive(Deserialize, Serialize, Debug)]
96 #[serde(rename_all = "camelCase")]
97 pub struct SyntaxTreeParams {
98 pub text_document: TextDocumentIdentifier,
99 pub range: Option<Range>,
100 }
101
102 pub enum ViewHir {}
103
104 impl Request for ViewHir {
105 type Params = lsp_types::TextDocumentPositionParams;
106 type Result = String;
107 const METHOD: &'static str = "rust-analyzer/viewHir";
108 }
109
110 pub enum ViewMir {}
111
112 impl Request for ViewMir {
113 type Params = lsp_types::TextDocumentPositionParams;
114 type Result = String;
115 const METHOD: &'static str = "rust-analyzer/viewMir";
116 }
117
118 pub enum InterpretFunction {}
119
120 impl Request for InterpretFunction {
121 type Params = lsp_types::TextDocumentPositionParams;
122 type Result = String;
123 const METHOD: &'static str = "rust-analyzer/interpretFunction";
124 }
125
126 pub enum ViewFileText {}
127
128 impl Request for ViewFileText {
129 type Params = lsp_types::TextDocumentIdentifier;
130 type Result = String;
131 const METHOD: &'static str = "rust-analyzer/viewFileText";
132 }
133
134 #[derive(Deserialize, Serialize, Debug)]
135 #[serde(rename_all = "camelCase")]
136 pub struct ViewCrateGraphParams {
137 /// Include *all* crates, not just crates in the workspace.
138 pub full: bool,
139 }
140
141 pub enum ViewCrateGraph {}
142
143 impl Request for ViewCrateGraph {
144 type Params = ViewCrateGraphParams;
145 type Result = String;
146 const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
147 }
148
149 #[derive(Deserialize, Serialize, Debug)]
150 #[serde(rename_all = "camelCase")]
151 pub struct ViewItemTreeParams {
152 pub text_document: TextDocumentIdentifier,
153 }
154
155 pub enum ViewItemTree {}
156
157 impl Request for ViewItemTree {
158 type Params = ViewItemTreeParams;
159 type Result = String;
160 const METHOD: &'static str = "rust-analyzer/viewItemTree";
161 }
162
163 pub enum ExpandMacro {}
164
165 impl Request for ExpandMacro {
166 type Params = ExpandMacroParams;
167 type Result = Option<ExpandedMacro>;
168 const METHOD: &'static str = "rust-analyzer/expandMacro";
169 }
170
171 #[derive(Deserialize, Serialize, Debug)]
172 #[serde(rename_all = "camelCase")]
173 pub struct ExpandMacroParams {
174 pub text_document: TextDocumentIdentifier,
175 pub position: Position,
176 }
177
178 #[derive(Deserialize, Serialize, Debug)]
179 #[serde(rename_all = "camelCase")]
180 pub struct ExpandedMacro {
181 pub name: String,
182 pub expansion: String,
183 }
184
185 pub enum ViewRecursiveMemoryLayout {}
186
187 impl Request for ViewRecursiveMemoryLayout {
188 type Params = lsp_types::TextDocumentPositionParams;
189 type Result = Option<RecursiveMemoryLayout>;
190 const METHOD: &'static str = "rust-analyzer/viewRecursiveMemoryLayout";
191 }
192
193 #[derive(Deserialize, Serialize, Debug)]
194 #[serde(rename_all = "camelCase")]
195 pub struct RecursiveMemoryLayout {
196 pub nodes: Vec<MemoryLayoutNode>,
197 }
198
199 #[derive(Deserialize, Serialize, Debug)]
200 #[serde(rename_all = "camelCase")]
201 pub struct MemoryLayoutNode {
202 pub item_name: String,
203 pub typename: String,
204 pub size: u64,
205 pub offset: u64,
206 pub alignment: u64,
207 pub parent_idx: i64,
208 pub children_start: i64,
209 pub children_len: u64,
210 }
211
212 pub enum CancelFlycheck {}
213
214 impl Notification for CancelFlycheck {
215 type Params = ();
216 const METHOD: &'static str = "rust-analyzer/cancelFlycheck";
217 }
218
219 pub enum RunFlycheck {}
220
221 impl Notification for RunFlycheck {
222 type Params = RunFlycheckParams;
223 const METHOD: &'static str = "rust-analyzer/runFlycheck";
224 }
225
226 pub enum ClearFlycheck {}
227
228 impl Notification for ClearFlycheck {
229 type Params = ();
230 const METHOD: &'static str = "rust-analyzer/clearFlycheck";
231 }
232
233 pub enum OpenServerLogs {}
234
235 impl Notification for OpenServerLogs {
236 type Params = ();
237 const METHOD: &'static str = "rust-analyzer/openServerLogs";
238 }
239
240 #[derive(Deserialize, Serialize, Debug)]
241 #[serde(rename_all = "camelCase")]
242 pub struct RunFlycheckParams {
243 pub text_document: Option<TextDocumentIdentifier>,
244 }
245
246 pub enum MatchingBrace {}
247
248 impl Request for MatchingBrace {
249 type Params = MatchingBraceParams;
250 type Result = Vec<Position>;
251 const METHOD: &'static str = "experimental/matchingBrace";
252 }
253
254 #[derive(Deserialize, Serialize, Debug)]
255 #[serde(rename_all = "camelCase")]
256 pub struct MatchingBraceParams {
257 pub text_document: TextDocumentIdentifier,
258 pub positions: Vec<Position>,
259 }
260
261 pub enum ParentModule {}
262
263 impl Request for ParentModule {
264 type Params = lsp_types::TextDocumentPositionParams;
265 type Result = Option<lsp_types::GotoDefinitionResponse>;
266 const METHOD: &'static str = "experimental/parentModule";
267 }
268
269 pub enum JoinLines {}
270
271 impl Request for JoinLines {
272 type Params = JoinLinesParams;
273 type Result = Vec<lsp_types::TextEdit>;
274 const METHOD: &'static str = "experimental/joinLines";
275 }
276
277 #[derive(Deserialize, Serialize, Debug)]
278 #[serde(rename_all = "camelCase")]
279 pub struct JoinLinesParams {
280 pub text_document: TextDocumentIdentifier,
281 pub ranges: Vec<Range>,
282 }
283
284 pub enum OnEnter {}
285
286 impl Request for OnEnter {
287 type Params = lsp_types::TextDocumentPositionParams;
288 type Result = Option<Vec<SnippetTextEdit>>;
289 const METHOD: &'static str = "experimental/onEnter";
290 }
291
292 pub enum Runnables {}
293
294 impl Request for Runnables {
295 type Params = RunnablesParams;
296 type Result = Vec<Runnable>;
297 const METHOD: &'static str = "experimental/runnables";
298 }
299
300 #[derive(Serialize, Deserialize, Debug)]
301 #[serde(rename_all = "camelCase")]
302 pub struct RunnablesParams {
303 pub text_document: TextDocumentIdentifier,
304 pub position: Option<Position>,
305 }
306
307 #[derive(Deserialize, Serialize, Debug)]
308 #[serde(rename_all = "camelCase")]
309 pub struct Runnable {
310 pub label: String,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub location: Option<lsp_types::LocationLink>,
313 pub kind: RunnableKind,
314 pub args: CargoRunnable,
315 }
316
317 #[derive(Serialize, Deserialize, Debug)]
318 #[serde(rename_all = "lowercase")]
319 pub enum RunnableKind {
320 Cargo,
321 }
322
323 #[derive(Deserialize, Serialize, Debug)]
324 #[serde(rename_all = "camelCase")]
325 pub struct CargoRunnable {
326 // command to be executed instead of cargo
327 pub override_cargo: Option<String>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub workspace_root: Option<PathBuf>,
330 // command, --package and --lib stuff
331 pub cargo_args: Vec<String>,
332 // user-specified additional cargo args, like `--release`.
333 pub cargo_extra_args: Vec<String>,
334 // stuff after --
335 pub executable_args: Vec<String>,
336 #[serde(skip_serializing_if = "Option::is_none")]
337 pub expect_test: Option<bool>,
338 }
339
340 pub enum RelatedTests {}
341
342 impl Request for RelatedTests {
343 type Params = lsp_types::TextDocumentPositionParams;
344 type Result = Vec<TestInfo>;
345 const METHOD: &'static str = "rust-analyzer/relatedTests";
346 }
347
348 #[derive(Debug, Deserialize, Serialize)]
349 pub struct TestInfo {
350 pub runnable: Runnable,
351 }
352
353 #[derive(Serialize, Deserialize, Debug)]
354 #[serde(rename_all = "camelCase")]
355 pub struct InlayHintsParams {
356 pub text_document: TextDocumentIdentifier,
357 pub range: Option<lsp_types::Range>,
358 }
359
360 pub enum Ssr {}
361
362 impl Request for Ssr {
363 type Params = SsrParams;
364 type Result = lsp_types::WorkspaceEdit;
365 const METHOD: &'static str = "experimental/ssr";
366 }
367
368 #[derive(Debug, Deserialize, Serialize)]
369 #[serde(rename_all = "camelCase")]
370 pub struct SsrParams {
371 pub query: String,
372 pub parse_only: bool,
373
374 /// File position where SSR was invoked. Paths in `query` will be resolved relative to this
375 /// position.
376 #[serde(flatten)]
377 pub position: lsp_types::TextDocumentPositionParams,
378
379 /// Current selections. Search/replace will be restricted to these if non-empty.
380 pub selections: Vec<lsp_types::Range>,
381 }
382
383 pub enum ServerStatusNotification {}
384
385 impl Notification for ServerStatusNotification {
386 type Params = ServerStatusParams;
387 const METHOD: &'static str = "experimental/serverStatus";
388 }
389
390 #[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
391 pub struct ServerStatusParams {
392 pub health: Health,
393 pub quiescent: bool,
394 pub message: Option<String>,
395 }
396
397 #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
398 #[serde(rename_all = "camelCase")]
399 pub enum Health {
400 Ok,
401 Warning,
402 Error,
403 }
404
405 pub enum CodeActionRequest {}
406
407 impl Request for CodeActionRequest {
408 type Params = lsp_types::CodeActionParams;
409 type Result = Option<Vec<CodeAction>>;
410 const METHOD: &'static str = "textDocument/codeAction";
411 }
412
413 pub enum CodeActionResolveRequest {}
414
415 impl Request for CodeActionResolveRequest {
416 type Params = CodeAction;
417 type Result = CodeAction;
418 const METHOD: &'static str = "codeAction/resolve";
419 }
420
421 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
422 #[serde(rename_all = "camelCase")]
423 pub struct CodeAction {
424 pub title: String,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub group: Option<String>,
427 #[serde(skip_serializing_if = "Option::is_none")]
428 pub kind: Option<CodeActionKind>,
429 #[serde(skip_serializing_if = "Option::is_none")]
430 pub command: Option<lsp_types::Command>,
431 #[serde(skip_serializing_if = "Option::is_none")]
432 pub edit: Option<SnippetWorkspaceEdit>,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub is_preferred: Option<bool>,
435
436 #[serde(skip_serializing_if = "Option::is_none")]
437 pub data: Option<CodeActionData>,
438 }
439
440 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
441 #[serde(rename_all = "camelCase")]
442 pub struct CodeActionData {
443 pub code_action_params: lsp_types::CodeActionParams,
444 pub id: String,
445 }
446
447 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
448 #[serde(rename_all = "camelCase")]
449 pub struct SnippetWorkspaceEdit {
450 #[serde(skip_serializing_if = "Option::is_none")]
451 pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
452 #[serde(skip_serializing_if = "Option::is_none")]
453 pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
454 #[serde(skip_serializing_if = "Option::is_none")]
455 pub change_annotations:
456 Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
457 }
458
459 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
460 #[serde(untagged, rename_all = "lowercase")]
461 pub enum SnippetDocumentChangeOperation {
462 Op(lsp_types::ResourceOp),
463 Edit(SnippetTextDocumentEdit),
464 }
465
466 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
467 #[serde(rename_all = "camelCase")]
468 pub struct SnippetTextDocumentEdit {
469 pub text_document: lsp_types::OptionalVersionedTextDocumentIdentifier,
470 pub edits: Vec<SnippetTextEdit>,
471 }
472
473 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
474 #[serde(rename_all = "camelCase")]
475 pub struct SnippetTextEdit {
476 pub range: Range,
477 pub new_text: String,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub insert_text_format: Option<lsp_types::InsertTextFormat>,
480 /// The annotation id if this is an annotated
481 #[serde(skip_serializing_if = "Option::is_none")]
482 pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>,
483 }
484
485 pub enum HoverRequest {}
486
487 impl Request for HoverRequest {
488 type Params = HoverParams;
489 type Result = Option<Hover>;
490 const METHOD: &'static str = lsp_types::request::HoverRequest::METHOD;
491 }
492
493 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
494 #[serde(rename_all = "camelCase")]
495 pub struct HoverParams {
496 pub text_document: TextDocumentIdentifier,
497 pub position: PositionOrRange,
498
499 #[serde(flatten)]
500 pub work_done_progress_params: WorkDoneProgressParams,
501 }
502
503 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
504 #[serde(untagged)]
505 pub enum PositionOrRange {
506 Position(lsp_types::Position),
507 Range(lsp_types::Range),
508 }
509
510 #[derive(Debug, PartialEq, Clone, Deserialize, Serialize)]
511 pub struct Hover {
512 #[serde(flatten)]
513 pub hover: lsp_types::Hover,
514 #[serde(skip_serializing_if = "Vec::is_empty")]
515 pub actions: Vec<CommandLinkGroup>,
516 }
517
518 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
519 pub struct CommandLinkGroup {
520 #[serde(skip_serializing_if = "Option::is_none")]
521 pub title: Option<String>,
522 pub commands: Vec<CommandLink>,
523 }
524
525 // LSP v3.15 Command does not have a `tooltip` field, vscode supports one.
526 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
527 pub struct CommandLink {
528 #[serde(flatten)]
529 pub command: lsp_types::Command,
530 #[serde(skip_serializing_if = "Option::is_none")]
531 pub tooltip: Option<String>,
532 }
533
534 pub enum ExternalDocs {}
535
536 impl Request for ExternalDocs {
537 type Params = lsp_types::TextDocumentPositionParams;
538 type Result = ExternalDocsResponse;
539 const METHOD: &'static str = "experimental/externalDocs";
540 }
541
542 #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
543 #[serde(untagged)]
544 pub enum ExternalDocsResponse {
545 Simple(Option<lsp_types::Url>),
546 WithLocal(ExternalDocsPair),
547 }
548
549 #[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
550 #[serde(rename_all = "camelCase")]
551 pub struct ExternalDocsPair {
552 pub web: Option<lsp_types::Url>,
553 pub local: Option<lsp_types::Url>,
554 }
555
556 pub enum OpenCargoToml {}
557
558 impl Request for OpenCargoToml {
559 type Params = OpenCargoTomlParams;
560 type Result = Option<lsp_types::GotoDefinitionResponse>;
561 const METHOD: &'static str = "experimental/openCargoToml";
562 }
563
564 #[derive(Serialize, Deserialize, Debug)]
565 #[serde(rename_all = "camelCase")]
566 pub struct OpenCargoTomlParams {
567 pub text_document: TextDocumentIdentifier,
568 }
569
570 /// Information about CodeLens, that is to be resolved.
571 #[derive(Debug, Serialize, Deserialize)]
572 #[serde(rename_all = "camelCase")]
573 pub struct CodeLensResolveData {
574 pub version: i32,
575 pub kind: CodeLensResolveDataKind,
576 }
577
578 #[derive(Debug, Serialize, Deserialize)]
579 #[serde(rename_all = "camelCase")]
580 pub enum CodeLensResolveDataKind {
581 Impls(lsp_types::request::GotoImplementationParams),
582 References(lsp_types::TextDocumentPositionParams),
583 }
584
585 pub fn negotiated_encoding(caps: &lsp_types::ClientCapabilities) -> PositionEncoding {
586 let client_encodings = match &caps.general {
587 Some(general) => general.position_encodings.as_deref().unwrap_or_default(),
588 None => &[],
589 };
590
591 for enc in client_encodings {
592 if enc == &PositionEncodingKind::UTF8 {
593 return PositionEncoding::Utf8;
594 } else if enc == &PositionEncodingKind::UTF32 {
595 return PositionEncoding::Wide(WideEncoding::Utf32);
596 }
597 // NB: intentionally prefer just about anything else to utf-16.
598 }
599
600 PositionEncoding::Wide(WideEncoding::Utf16)
601 }
602
603 pub enum MoveItem {}
604
605 impl Request for MoveItem {
606 type Params = MoveItemParams;
607 type Result = Vec<SnippetTextEdit>;
608 const METHOD: &'static str = "experimental/moveItem";
609 }
610
611 #[derive(Serialize, Deserialize, Debug)]
612 #[serde(rename_all = "camelCase")]
613 pub struct MoveItemParams {
614 pub direction: MoveItemDirection,
615 pub text_document: TextDocumentIdentifier,
616 pub range: Range,
617 }
618
619 #[derive(Serialize, Deserialize, Debug)]
620 pub enum MoveItemDirection {
621 Up,
622 Down,
623 }
624
625 #[derive(Debug)]
626 pub enum WorkspaceSymbol {}
627
628 impl Request for WorkspaceSymbol {
629 type Params = WorkspaceSymbolParams;
630 type Result = Option<Vec<lsp_types::SymbolInformation>>;
631 const METHOD: &'static str = "workspace/symbol";
632 }
633
634 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
635 #[serde(rename_all = "camelCase")]
636 pub struct WorkspaceSymbolParams {
637 #[serde(flatten)]
638 pub partial_result_params: PartialResultParams,
639
640 #[serde(flatten)]
641 pub work_done_progress_params: WorkDoneProgressParams,
642
643 /// A non-empty query string
644 pub query: String,
645
646 pub search_scope: Option<WorkspaceSymbolSearchScope>,
647
648 pub search_kind: Option<WorkspaceSymbolSearchKind>,
649 }
650
651 #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
652 #[serde(rename_all = "camelCase")]
653 pub enum WorkspaceSymbolSearchScope {
654 Workspace,
655 WorkspaceAndDependencies,
656 }
657
658 #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
659 #[serde(rename_all = "camelCase")]
660 pub enum WorkspaceSymbolSearchKind {
661 OnlyTypes,
662 AllSymbols,
663 }
664
665 /// The document on type formatting request is sent from the client to
666 /// the server to format parts of the document during typing. This is
667 /// almost same as lsp_types::request::OnTypeFormatting, but the
668 /// result has SnippetTextEdit in it instead of TextEdit.
669 #[derive(Debug)]
670 pub enum OnTypeFormatting {}
671
672 impl Request for OnTypeFormatting {
673 type Params = DocumentOnTypeFormattingParams;
674 type Result = Option<Vec<SnippetTextEdit>>;
675 const METHOD: &'static str = "textDocument/onTypeFormatting";
676 }
677
678 #[derive(Debug, Serialize, Deserialize)]
679 pub struct CompletionResolveData {
680 pub position: lsp_types::TextDocumentPositionParams,
681 pub imports: Vec<CompletionImport>,
682 }
683
684 #[derive(Debug, Serialize, Deserialize)]
685 pub struct InlayHintResolveData {}
686
687 #[derive(Debug, Serialize, Deserialize)]
688 pub struct CompletionImport {
689 pub full_import_path: String,
690 pub imported_name: String,
691 }
692
693 #[derive(Debug, Deserialize, Default)]
694 pub struct ClientCommandOptions {
695 pub commands: Vec<String>,
696 }