Repository: nushell/nushell
File: crates/nu-lsp/src/completion.rs (Rust)

Code before:
                            if matches!(arg.shape, SyntaxShape::Block | SyntaxShape::MatchBlock) {
                                format!("{{ {text} }}")
                            } else {
                                text
                            }
                        };

                        for required in signature.required_positional {
                            snippet_text.push(' ');
                            snippet_text.push_str(
                                block_wrapper(&required, format!("${{{}:{}}}", idx, required.name))
                                    .as_str(),
                            );
                            idx += 1;
                        }
                        for optional in signature.optional_positional {
                            snippet_text.push(' ');
                            snippet_text.push_str(
                                block_wrapper(
                                    &optional,
                                    format!("${{{}:{}?}}", idx, optional.name),
                                )
                                .as_str(),
                            );
                            idx += 1;
                        }
                        if let Some(rest) = signature.rest_positional {
                            snippet_text
                                .push_str(format!(" ${{{}:...{}}}", idx, rest.name).as_str());
                            idx += 1;
                        }
                    }
                    // no extra space for a command with args expanded in the snippet
                    if idx == 1 && r.suggestion.append_whitespace {
                        snippet_text.push(' ');
                    }

                    let span = r.suggestion.span;
                    let text_edit = Some(CompletionTextEdit::Edit(TextEdit {
                        range: span_to_range(&Span::new(span.start, span.end), file, 0),
                        new_text: snippet_text,
                    }));

                    CompletionItem {
                        label: r.suggestion.value,
                        label_details: r
                            .kind
                            .as_ref()
                            .map(|kind| match kind {
                                SuggestionKind::Value(t) => t.to_string(),
                                SuggestionKind::Command(cmd) => cmd.to_string(),

Review comment (bug):
I choose nested placeholders for optional keyword args like the `else` in `if` command.

It's documented in LSP specifications of 3.17 like this:
<img width="649" alt="image" src="https://github.com/user-attachments/assets/5106d77c-9f14-4bab-b808-661ef9227590" />

But some editors like neovim don't fully support that format:

```
Failed to parse snippet,
but was able to fix it automatically.

if ${1:cond} { ${2:then_block} } ${3:else ${4:else_expression?}}
```

It simply ignores the 4th placeholder, and I think that's still better than leaving `else` not captured. 

<img width="354" alt="image" src="https://github.com/user-attachments/assets/a500e1c2-30d3-4801-92e4-05cd438e6524" />

PS: zed and helix work perfectly with that format.


Code after:
            matches!(kind, SuggestionKind::Command(_))
                .then_some(engine_state.find_decl(suggestion.suggestion.value.as_bytes(), &[])?)
        });

        let mut snippet_text = suggestion.suggestion.value.clone();
        let mut doc_string = suggestion.suggestion.extra.map(|ex| ex.join("\n"));
        let mut insert_text_format = None;
        let mut idx = 0;
        // use snippet as `insert_text_format` for command argument completion
        if let Some(decl_id) = decl_id {
            let cmd = engine_state.get_decl(decl_id);
            doc_string = Some(Self::get_decl_description(cmd, true));
            insert_text_format = Some(InsertTextFormat::SNIPPET);
            let signature = cmd.signature();
            // add curly brackets around block arguments
            // and keywords, e.g. `=` in `alias foo = bar`
            let mut arg_wrapper = |arg: &PositionalArg, text: String, optional: bool| -> String {
                idx += 1;
                match &arg.shape {
                    SyntaxShape::Block | SyntaxShape::MatchBlock => {
                        format!("{{ ${{{}:{}}} }}", idx, text)
                    }
                    SyntaxShape::Keyword(kwd, _) => {
                        // NOTE: If optional, the keyword should also be in a placeholder so that it can be removed easily.
                        // Here we choose to use nested placeholders. Note that some editors don't fully support this format,
                        // but usually they will simply ignore the inner ones, so it should be fine.
                        if optional {
                            idx += 1;
                            format!(
                                "${{{}:{} ${{{}:{}}}}}",
                                idx - 1,
                                String::from_utf8_lossy(kwd),
                                idx,
                                text
                            )
                        } else {
                            format!("{} ${{{}:{}}}", String::from_utf8_lossy(kwd), idx, text)
                        }
                    }
                    _ => format!("${{{}:{}}}", idx, text),
                }
            };

            for required in signature.required_positional {
                snippet_text.push(' ');
                snippet_text
                    .push_str(arg_wrapper(&required, required.name.clone(), false).as_str());
            }
            for optional in signature.optional_positional {
                snippet_text.push(' ');
                snippet_text