Rust

Zed 本机支持 Rust。

内联提示

以下配置可用于更改 Rust 中 rust-analyzer 的内联提示设置

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "inlayHints": {
          "maxLength": null,
          "lifetimeElisionHints": {
            "enable": "skip_trivial",
            "useParameterNames": true
          },
          "closureReturnTypeHints": {
            "enable": "always"
          }
        }
      }
    }
  }
}

有关更多信息,请参阅 Rust Analyzer 手册中的内联提示

目标目录

rust-analyzer 目标目录可以在 initialization_options 中设置

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "rust": {
          "analyzerTargetDir": true
        }
      }
    }
  }
}

设置为 true 会将目标目录设置为 target/rust-analyzer。你可以使用字符串(例如 "target/analyzer")代替 true 来设置自定义目录。

二进制文件

你可以配置 Zed 应该使用哪个 rust-analyzer 二进制文件。

默认情况下,Zed 将尝试在你的 $PATH 中查找 rust-analyzer 并尝试使用它。如果该二进制文件成功执行 rust-analyzer --help,则会使用它。否则,Zed 将回退到安装自己的 rust-analyzer 版本并使用它。

如果要禁用 Zed 查找 rust-analyzer 二进制文件,可以在你的 settings.json 中将 ignore_system_version 设置为 true

{
  "lsp": {
    "rust-analyzer": {
      "binary": {
        "ignore_system_version": true
      }
    }
  }
}

如果你想使用自定义位置的二进制文件,可以指定 path 和可选的 args

{
  "lsp": {
    "rust-analyzer": {
      "binary": {
        "path": "/Users/example/bin/rust-analyzer",
        "args": []
      }
    }
  }
}

"path" 必须是绝对路径。

备用目标

如果你希望 rust-analyzer 为你当前平台以外的目标提供诊断(例如,在 macOS 上运行时为 windows),你可以使用以下 Zed lsp 设置

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "cargo": {
          "target": "x86_64-pc-windows-msvc"
        }
      }
    }
  }
}

如果你正在使用 rustup,并且可以通过运行以下命令找到可用目标三元组的列表(aarch64-apple-darwin, x86_64-unknown-linux-gnu 等)

rustup target list --installed

更多服务器配置

Rust-analyzer 手册 描述了 rust-analyzer 语言服务器的各种功能和配置选项。 Zed 中的 Rust-analyzer 使用默认参数运行。

大型项目和性能

在大型项目中可能导致大量资源使用的一个主要原因是以下功能的组合

rust-analyzer.checkOnSave (default: true)
    Run the check command for diagnostics on save.
rust-analyzer.check.workspace (default: true)
    Whether --workspace should be passed to cargo check. If false, -p <package> will be passed instead.
rust-analyzer.cargo.allTargets (default: true)
    Pass --all-targets to cargo invocation

这意味着每次 Zed 保存时,都会运行 cargo check --workspace --all-targets 命令,检查整个项目(工作区)、lib、doc、test、bin、bench 和 其他目标

虽然这在小型项目中效果很好,但它不能很好地扩展。

替代方法是使用 任务,因为 Zed 已经提供了一个 cargo check --workspace --all-targets 任务以及通过 cmd/ctrl-click 终端输出来导航到错误的能力,并完全限制或关闭保存时检查功能。

保存时检查功能负责根据 cargo check 输出返回部分诊断信息,因此关闭它会将 rust-analyzer 限制为其自己的 诊断

请考虑手册中更多的 rust-analyzer.cargo.rust-analyzer.check. 以及 rust-analyzer.diagnostics. 设置,以便进行更细粒度的配置。这是一个 Zed settings.json 的代码片段(编辑并保存 lsp.rust-analyzer 部分后,语言服务器将自动重启)

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        // get more cargo-less diagnostics from rust-analyzer,
        // which might include false-positives (those can be turned off by their names)
        "diagnostics": {
          "experimental": {
            "enable": true
          }
        },
        // To disable the checking entirely
        // (ignores all cargo and check settings below)
        "checkOnSave": false,
        // To check the `lib` target only.
        "cargo": {
          "allTargets": false
        },
        // Use `-p` instead of `--workspace` for cargo check
        "check": {
          "workspace": false
        }
      }
    }
  }
}

多项目工作区

如果你希望 rust-analyzer 分析同一文件夹中未在 Cargo 工作区中的 [members] 中列出的多个 Rust 项目,则可以在本地项目设置中的 linkedProjects 中列出它们

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "linkedProjects": ["./path/to/a/Cargo.toml", "./path/to/b/Cargo.toml"]
      }
    }
  }
}

代码片段

有一种方法可以从 rust-analyzer 获取自定义完成项,这些完成项将根据代码片段正文转换代码

{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "completion": {
          "snippets": {
            "custom": {
              "Arc::new": {
                "postfix": "arc",
                "body": ["Arc::new(${receiver})"],
                "requires": "std::sync::Arc",
                "scope": "expr"
              },
              "Some": {
                "postfix": "some",
                "body": ["Some(${receiver})"],
                "scope": "expr"
              },
              "Ok": {
                "postfix": "ok",
                "body": ["Ok(${receiver})"],
                "scope": "expr"
              },
              "Rc::new": {
                "postfix": "rc",
                "body": ["Rc::new(${receiver})"],
                "requires": "std::rc::Rc",
                "scope": "expr"
              },
              "Box::pin": {
                "postfix": "boxpin",
                "body": ["Box::pin(${receiver})"],
                "requires": "std::boxed::Box",
                "scope": "expr"
              },
              "vec!": {
                "postfix": "vec",
                "body": ["vec![${receiver}]"],
                "description": "vec![]",
                "scope": "expr"
              }
            }
          }
        }
      }
    }
  }
}