Repository: rust-analyzer/rust-analyzer
Pull request #6993 (2020-12-22 00:25:54)

Clean up descriptions for settings
Use two consecutive newlines (`\n\n`) to actually continue text on a
new line.

Use proper markup to reference related settings.

Consistently format references to files, command line arguments, etc.
as `code`. Format mentions of UI elements in _italic_.

Fix typos, add missing full-stops, add missing default values.

Veykril: The tests fail because the settings are generated from code and they check whether those are in sync now so you want to edit the lines here https://github.com/rust-analyzer/rust-analyzer/blob/ba71685343ccdca9de3899d2ae634aaa8185c359/crates/rust-analyzer/src/config.rs#L25-L174 and here instead https://github.com/rust-analyzer/rust-analyzer/blob/ba71685343ccdca9de3899d2ae634aaa8185c359/crates/rust-analyzer/src/config.rs#L714-L770
And then regenerate them(not sure how you would do this though I don't think `cargo xtask codegen` does that)

Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 09752b817f..919d58925e 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -15,9 +15,12 @@ env:
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
-  dist-windows:
-    name: dist (Windows)
-    runs-on: windows-latest
+  dist:
+    name: dist
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        os: [ubuntu-16.04, windows-latest, macos-latest]
 
     steps:
     - name: Checkout repository
@@ -27,7 +30,8 @@ jobs:
     # which takes a long time. The fastest way to do this is to rename the
     # existing folder, as deleting it takes about as much time as not doing
     # anything and just updating rust-docs.
-    - name: Rename existing rust toolchain
+    - name: Rename existing rust toolchain (Windows)
+      if: matrix.os == 'windows-latest'
       run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old
 
     - name: Install Rust toolchain
@@ -37,116 +41,38 @@ jobs:
         profile: minimal
         override: true
 
-    - name: Dist
-      run: cargo xtask dist
-      env:
-        RA_TARGET: x86_64-pc-windows-msvc
-
-    - name: Upload artifacts
-      uses: actions/upload-artifact@v1
-      with:
-        name: dist-windows-latest
-        path: ./dist
-
-  dist-ubuntu:
-    name: dist (Ubuntu 16.04)
-    runs-on: ubuntu-16.04
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
-
-    - name: Install Rust toolchain
-      uses: actions-rs/toolchain@v1
-      with:
-        toolchain: stable
-        profile: minimal
-        override: true
-
     - name: Install Nodejs
+      if: matrix.os == 'ubuntu-16.04'
       uses: actions/setup-node@v1
       with:
         node-version: 12.x
 
     - name: Dist
-      if: github.ref == 'refs/heads/release'
+      if: matrix.os == 'ubuntu-16.04' && github.ref == 'refs/heads/release'
       run: cargo xtask dist --client 0.2.$GITHUB_RUN_NUMBER
-      env:
-        RA_TARGET: x86_64-unknown-linux-gnu
 
     - name: Dist
-      if: github.ref != 'refs/heads/release'
+      if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release'
       run: cargo xtask dist --nightly --client 0.3.$GITHUB_RUN_NUMBER-nightly
-      env:
-        RA_TARGET: x86_64-unknown-linux-gnu
-
-    - name: Nightly analysis-stats check
-      if: github.ref != 'refs/heads/release'
-      run: ./dist/rust-analyzer-x86_64-unknown-linux-gnu analysis-stats .
-
-    - name: Upload artifacts
-      uses: actions/upload-artifact@v1
-      with:
-        name: dist-ubuntu-16.04
-        path: ./dist
-
-  dist-macos-latest:
-    name: dist (MacOS latest)
-    runs-on: macos-latest
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
-
-    - name: Install Rust toolchain
-      uses: actions-rs/toolchain@v1
-      with:
-        toolchain: stable
-        profile: minimal
-        override: true
 
     - name: Dist
+      if: matrix.os != 'ubuntu-16.04'
       run: cargo xtask dist
-      env:
-        RA_TARGET: x86_64-apple-darwin
-
-    - name: Upload artifacts
-      uses: actions/upload-artifact@v1
-      with:
-        name: dist-macos-latest
-        path: ./dist
 
-  dist-macos-11:
-    name: dist (MacOS 11.0)
-    runs-on: macos-11.0
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
-
-    - name: Install Rust toolchain (beta)
-      uses: actions-rs/toolchain@v1
-      with:
-        toolchain: beta
-        target: aarch64-apple-darwin
-        profile: minimal
-        override: true
-
-    - name: Dist
-      run: cargo xtask dist
-      env:
-        RA_TARGET: aarch64-apple-darwin
+    - name: Nightly analysis-stats check
+      if: matrix.os == 'ubuntu-16.04' && github.ref != 'refs/heads/release'
+      run: ./dist/rust-analyzer-linux analysis-stats .
 
     - name: Upload artifacts
       uses: actions/upload-artifact@v1
       with:
-        name: dist-macos-11.0
+        name: dist-${{ matrix.os }}
         path: ./dist
 
   publish:
     name: publish
     runs-on: ubuntu-16.04
-    needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11']
+    needs: ['dist']
     steps:
     - name: Install Nodejs
       uses: actions/setup-node@v1
@@ -165,10 +91,6 @@ jobs:
     - run: echo "HEAD_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
     - run: 'echo "HEAD_SHA: $HEAD_SHA"'
 
-    - uses: actions/download-artifact@v1
-      with:
-        name: dist-macos-11.0
-        path: dist
     - uses: actions/download-artifact@v1
       with:
         name: dist-macos-latest
@@ -181,7 +103,7 @@ jobs:
       with:
         name: dist-windows-latest
         path: dist
-    - run: ls -al ./dist
+    - run: ls -all ./dist
 
     - name: Publish Release
       uses: ./.github/actions/github-release
diff --git a/crates/assists/src/assist_context.rs b/crates/assists/src/assist_context.rs
index 80cf9aba11..69499ea326 100644
--- a/crates/assists/src/assist_context.rs
+++ b/crates/assists/src/assist_context.rs
@@ -4,10 +4,10 @@ use std::mem;
 
 use algo::find_covering_element;
 use hir::Semantics;
-use ide_db::base_db::{AnchoredPathBuf, FileId, FileRange};
+use ide_db::base_db::{FileId, FileRange};
 use ide_db::{
     label::Label,
-    source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
+    source_change::{SourceChange, SourceFileEdit},
     RootDatabase,
 };
 use syntax::{
@@ -209,7 +209,6 @@ pub(crate) struct AssistBuilder {
     file_id: FileId,
     is_snippet: bool,
     source_file_edits: Vec<SourceFileEdit>,
-    file_system_edits: Vec<FileSystemEdit>,
 }
 
 impl AssistBuilder {
@@ -219,7 +218,6 @@ impl AssistBuilder {
             file_id,
             is_snippet: false,
             source_file_edits: Vec::default(),
-            file_system_edits: Vec::default(),
         }
     }
 
@@ -284,17 +282,12 @@ impl AssistBuilder {
             algo::diff(&node, &new).into_text_edit(&mut self.edit);
         }
     }
-    pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
-        let file_system_edit =
-            FileSystemEdit::CreateFile { dst: dst.clone(), initial_contents: content.into() };
-        self.file_system_edits.push(file_system_edit);
-    }
 
     fn finish(mut self) -> SourceChange {
         self.commit();
         SourceChange {
             source_file_edits: mem::take(&mut self.source_file_edits),
-            file_system_edits: mem::take(&mut self.file_system_edits),
+            file_system_edits: Default::default(),
             is_snippet: self.is_snippet,
         }
     }
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs
deleted file mode 100644
index 5fc190fa67..0000000000
--- a/crates/assists/src/handlers/extract_module_to_file.rs
+++ /dev/null
@@ -1,170 +0,0 @@
-use ast::edit::IndentLevel;
-use ide_db::base_db::{AnchoredPathBuf, SourceDatabaseExt};
-use syntax::{
-    ast::{self, edit::AstNodeEdit, NameOwner},
-    AstNode,
-};
-
-use crate::{AssistContext, AssistId, AssistKind, Assists};
-
-// Assist: extract_module_to_file
-//
-// This assist extract module to file.
-//
-// ```
-// mod foo {<|>
-//     fn t() {}
-// }
-// ```
-// ->
-// ```
-// mod foo;
-// ```
-pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let assist_id = AssistId("extract_module_to_file", AssistKind::RefactorExtract);
-    let assist_label = "Extract module to file";
-    let db = ctx.db();
-    let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
-    let module_items = module_ast.item_list()?;
-    let dedent_module_items_text = module_items.dedent(IndentLevel(1)).to_string();
-    let module_name = module_ast.name()?;
-    let target = module_ast.syntax().text_range();
-    let anchor_file_id = ctx.frange.file_id;
-    let sr = db.file_source_root(anchor_file_id);
-    let sr = db.source_root(sr);
-    let file_path = sr.path_for_file(&anchor_file_id)?;
-    let (file_name, file_ext) = file_path.name_and_extension()?;
-    acc.add(assist_id, assist_label, target, |builder| {
-        builder.replace(target, format!("mod {};", module_name));
-        let path = if is_main_or_lib(file_name) {
-            format!("./{}.{}", module_name, file_ext.unwrap())
-        } else {
-            format!("./{}/{}.{}", file_name, module_name, file_ext.unwrap())
-        };
-        let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
-        let contents = update_module_items_string(dedent_module_items_text);
-        builder.create_file(dst, contents);
-    })
-}
-fn is_main_or_lib(file_name: &str) -> bool {
-    file_name == "main".to_string() || file_name == "lib".to_string()
-}
-fn update_module_items_string(items_str: String) -> String {
-    let mut items_string_lines: Vec<&str> = items_str.lines().collect();
-    items_string_lines.pop(); // Delete last line
-    items_string_lines.reverse();
-    items_string_lines.pop(); // Delete first line
-    items_string_lines.reverse();
-
-    let string = items_string_lines.join("\n");
-    format!("{}", string)
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::tests::check_assist;
-
-    use super::*;
-
-    #[test]
-    fn extract_module_to_file_with_basic_module() {
-        check_assist(
-            extract_module_to_file,
-            r#"
-//- /foo.rs crate:foo
-mod tests {<|>
-    #[test] fn t() {}
-}
-"#,
-            r#"
-//- /foo.rs
-mod tests;
-//- /foo/tests.rs
-#[test] fn t() {}"#,
-        )
-    }
-
-    #[test]
-    fn extract_module_to_file_with_file_path() {
-        check_assist(
-            extract_module_to_file,
-            r#"
-//- /src/foo.rs crate:foo
-mod bar {<|>
-    fn f() {
-
-    }
-}
-fn main() {
-    println!("Hello, world!");
-}
-"#,
-            r#"
-//- /src/foo.rs
-mod bar;
-fn main() {
-    println!("Hello, world!");
-}
-//- /src/foo/bar.rs
-fn f() {
-
-}"#,
-        )
-    }
-
-    #[test]
-    fn extract_module_to_file_with_main_filw() {
-        check_assist(
-            extract_module_to_file,
-            r#"
-//- /main.rs
-mod foo {<|>
-    fn f() {
-
-    }
-}
-fn main() {
-    println!("Hello, world!");
-}
-"#,
-            r#"
-//- /main.rs
-mod foo;
-fn main() {
-    println!("Hello, world!");
-}
-//- /foo.rs
-fn f() {
-
-}"#,
-        )
-    }
-
-    #[test]
-    fn extract_module_to_file_with_lib_file() {
-        check_assist(
-            extract_module_to_file,
-            r#"
-//- /lib.rs
-mod foo {<|>
-    fn f() {
-
-    }
-}
-fn main() {
-    println!("Hello, world!");
-}
-"#,
-            r#"
-//- /lib.rs
-mod foo;
-fn main() {
-    println!("Hello, world!");
-}
-//- /foo.rs
-fn f() {
-
-}"#,
-        )
-    }
-}
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 6b89b2d044..6e736ccb38 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -129,7 +129,6 @@ mod handlers {
     mod convert_integer_literal;
     mod early_return;
     mod expand_glob_import;
-    mod extract_module_to_file;
     mod extract_struct_from_enum_variant;
     mod extract_variable;
     mod fill_match_arms;
@@ -180,7 +179,6 @@ mod handlers {
             convert_integer_literal::convert_integer_literal,
             early_return::convert_to_guarded_return,
             expand_glob_import::expand_glob_import,
-            extract_module_to_file::extract_module_to_file,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_variable::extract_variable,
             fill_match_arms::fill_match_arms,
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 3ad30f0c9e..049f808dc6 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -619,7 +619,6 @@ fn test_fn() {
                                                 ),
                                                 path: "foo.rs",
                                             },
-                                            initial_contents: "",
                                         },
                                     ],
                                     is_snippet: false,
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index d79f5c1700..e8b8966238 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -40,7 +40,6 @@ impl DiagnosticWithFix for UnresolvedModule {
                     anchor: self.file.original_file(sema.db),
                     path: self.candidate.clone(),
                 },
-                initial_contents: "".to_string(),
             }
             .into(),
             unresolved_module.syntax().text_range(),
diff --git a/crates/ide_db/src/source_change.rs b/crates/ide_db/src/source_change.rs
index 10c0abdaca..e87d98dadc 100644
--- a/crates/ide_db/src/source_change.rs
+++ b/crates/ide_db/src/source_change.rs
@@ -44,7 +44,7 @@ impl From<Vec<SourceFileEdit>> for SourceChange {
 
 #[derive(Debug, Clone)]
 pub enum FileSystemEdit {
-    CreateFile { dst: AnchoredPathBuf, initial_contents: String },
+    CreateFile { dst: AnchoredPathBuf },
     MoveFile { src: FileId, dst: AnchoredPathBuf },
 }
 
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1f4b5c24c5..11cdae57f7 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -33,7 +33,7 @@ config_data! {
         callInfo_full: bool = "true",
 
         /// Automatically refresh project info via `cargo metadata` on
-        /// Cargo.toml changes.
+        /// `Cargo.toml` changes.
         cargo_autoreload: bool           = "true",
         /// Activate all available features.
         cargo_allFeatures: bool          = "false",
@@ -52,7 +52,7 @@ config_data! {
         /// Run specified `cargo check` command for diagnostics on save.
         checkOnSave_enable: bool                         = "true",
         /// Check with all features (will be passed as `--all-features`).
-        /// Defaults to `rust-analyzer.cargo.allFeatures`.
+        /// Defaults to `#rust-analyzer.cargo.allFeatures#`.
         checkOnSave_allFeatures: Option<bool>            = "null",
         /// Check all targets and tests (will be passed as `--all-targets`).
         checkOnSave_allTargets: bool                     = "true",
@@ -61,12 +61,12 @@ config_data! {
         /// Do not activate the `default` feature.
         checkOnSave_noDefaultFeatures: Option<bool>      = "null",
         /// Check for a specific target. Defaults to
-        /// `rust-analyzer.cargo.target`.
+        /// `#rust-analyzer.cargo.target#`.
         checkOnSave_target: Option<String>               = "null",
         /// Extra arguments for `cargo check`.
         checkOnSave_extraArgs: Vec<String>               = "[]",
         /// List of features to activate. Defaults to
-        /// `rust-analyzer.cargo.features`.
+        /// `#rust-analyzer.cargo.features#`.
         checkOnSave_features: Option<Vec<String>>        = "null",
         /// Advanced option, fully override the command rust-analyzer uses for
         /// checking. The command should include `--message-format=json` or
@@ -80,7 +80,7 @@ config_data! {
         /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
         completion_postfix_enable: bool          = "true",
         /// Toggles the additional completions that automatically add imports when completed.
-        /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
+        /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = "true",
 
         /// Whether to show native rust-analyzer diagnostics.
@@ -90,13 +90,13 @@ config_data! {
         diagnostics_enableExperimental: bool    = "true",
         /// List of rust-analyzer diagnostics to disable.
         diagnostics_disabled: FxHashSet<String> = "[]",
-        /// List of warnings that should be displayed with info severity.\nThe
+        /// List of warnings that should be displayed with info severity.\n\nThe
         /// warnings will be indicated by a blue squiggly underline in code and
-        /// a blue icon in the problems panel.
+        /// a blue icon in the `Problems Panel`.
         diagnostics_warningsAsHint: Vec<String> = "[]",
-        /// List of warnings that should be displayed with hint severity.\nThe
+        /// List of warnings that should be displayed with hint severity.\n\nThe
         /// warnings will be indicated by faded text or three dots in code and
-        /// will not show up in the problems panel.
+        /// will not show up in the `Problems Panel`.
         diagnostics_warningsAsInfo: Vec<String> = "[]",
 
         /// Controls file watching implementation.
@@ -121,7 +121,7 @@ config_data! {
 
         /// Whether to show inlay type hints for method chains.
         inlayHints_chainingHints: bool      = "true",
-        /// Maximum length for inlay hints.
+        /// Maximum length for inlay hints. Default is unlimited.
         inlayHints_maxLength: Option<usize> = "null",
         /// Whether to show function parameter name inlay hints at the call
         /// site.
@@ -145,27 +145,27 @@ config_data! {
         lens_methodReferences: bool = "false",
 
         /// Disable project auto-discovery in favor of explicitly specified set
-        /// of projects.  \nElements must be paths pointing to Cargo.toml,
-        /// rust-project.json, or JSON objects in rust-project.json format.
+        /// of projects.\n\nElements must be paths pointing to `Cargo.toml`,
+        /// `rust-project.json`, or JSON objects in `rust-project.json` format.
         linkedProjects: Vec<ManifestOrProjectJson> = "[]",
-        /// Number of syntax trees rust-analyzer keeps in memory.
+        /// Number of syntax trees rust-analyzer keeps in memory.  Defaults to 128.
         lruCapacity: Option<usize>                 = "null",
         /// Whether to show `can't find Cargo.toml` error message.
         notifications_cargoTomlNotFound: bool      = "true",
-        /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be
+        /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be
         /// enabled.
         procMacro_enable: bool                     = "false",
 
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_overrideCargo: Option<String> = "null",
         /// Additional arguments to be passed to cargo for runnables such as
-        /// tests or binaries.\nFor example, it may be '--release'.
+        /// tests or binaries.\nFor example, it may be `--release`.
         runnables_cargoExtraArgs: Vec<String>   = "[]",
 
         /// Path to the rust compiler sources, for usage in rustc_private projects.
         rustcSource : Option<String> = "null",
 
-        /// Additional arguments to rustfmt.
+        /// Additional arguments to `rustfmt`.
         rustfmt_extraArgs: Vec<String>               = "[]",
         /// Advanced option, fully override the command rust-analyzer uses for
         /// formatting.
@@ -758,7 +758,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
             ],
             "enumDescriptions": [
                 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
-                "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name",
+                "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.",
                 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
             ],
         },
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 5a1ae96aa0..e0561b5a7a 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -634,47 +634,30 @@ pub(crate) fn snippet_text_document_edit(
     Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
 }
 
-pub(crate) fn snippet_text_document_ops(
+pub(crate) fn resource_op(
     snap: &GlobalStateSnapshot,
     file_system_edit: FileSystemEdit,
-) -> Vec<lsp_ext::SnippetDocumentChangeOperation> {
-    let mut ops = Vec::new();
+) -> lsp_types::ResourceOp {
     match file_system_edit {
-        FileSystemEdit::CreateFile { dst, initial_contents } => {
+        FileSystemEdit::CreateFile { dst } => {
             let uri = snap.anchored_path(&dst);
-            let create_file = lsp_types::ResourceOp::Create(lsp_types::CreateFile {
-                uri: uri.clone(),
+            lsp_types::ResourceOp::Create(lsp_types::CreateFile {
+                uri,
                 options: None,
                 annotation_id: None,
-            });
-            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(create_file));
-            if !initial_contents.is_empty() {
-                let text_document =
-                    lsp_types::OptionalVersionedTextDocumentIdentifier { uri, version: None };
-                let range = range(&LineIndex::new(""), TextRange::empty(TextSize::from(0)));
-                let text_edit = lsp_ext::SnippetTextEdit {
-                    range,
-                    new_text: initial_contents,
-                    insert_text_format: Some(lsp_types::InsertTextFormat::PlainText),
-                };
-                let edit_file =
-                    lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] };
-                ops.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit_file));
-            }
+            })
         }
         FileSystemEdit::MoveFile { src, dst } => {
             let old_uri = snap.file_id_to_url(src);
             let new_uri = snap.anchored_path(&dst);
-            let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
+            lsp_types::ResourceOp::Rename(lsp_types::RenameFile {
                 old_uri,
                 new_uri,
                 options: None,
                 annotation_id: None,
-            });
-            ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file))
+            })
         }
     }
-    ops
 }
 
 pub(crate) fn snippet_workspace_edit(
@@ -683,8 +666,8 @@ pub(crate) fn snippet_workspace_edit(
 ) -> Result<lsp_ext::SnippetWorkspaceEdit> {
     let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
     for op in source_change.file_system_edits {
-        let ops = snippet_text_document_ops(snap, op);
-        document_changes.extend_from_slice(&ops);
+        let op = resource_op(&snap, op);
+        document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Op(op));
     }
     for edit in source_change.source_file_edits {
         let edit = snippet_text_document_edit(&snap, source_change.is_snippet, edit)?;
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index cb2ae6fc10..3025dc8d69 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -5,7 +5,7 @@ rust-analyzer.assist.importPrefix (default: `"plain"`)::
 rust-analyzer.callInfo.full (default: `true`)::
  Show function name and docs in parameter hints.
 rust-analyzer.cargo.autoreload (default: `true`)::
- Automatically refresh project info via `cargo metadata` on  Cargo.toml changes.
+ Automatically refresh project info via `cargo metadata` on  `Cargo.toml` changes.
 rust-analyzer.cargo.allFeatures (default: `false`)::
  Activate all available features.
 rust-analyzer.cargo.features (default: `[]`)::
@@ -21,7 +21,7 @@ rust-analyzer.cargo.noSysroot (default: `false`)::
 rust-analyzer.checkOnSave.enable (default: `true`)::
  Run specified `cargo check` command for diagnostics on save.
 rust-analyzer.checkOnSave.allFeatures (default: `null`)::
- Check with all features (will be passed as `--all-features`).  Defaults to `rust-analyzer.cargo.allFeatures`.
+ Check with all features (will be passed as `--all-features`).  Defaults to `#rust-analyzer.cargo.allFeatures#`.
 rust-analyzer.checkOnSave.allTargets (default: `true`)::
  Check all targets and tests (will be passed as `--all-targets`).
 rust-analyzer.checkOnSave.command (default: `"check"`)::
@@ -29,11 +29,11 @@ rust-analyzer.checkOnSave.command (default: `"check"`)::
 rust-analyzer.checkOnSave.noDefaultFeatures (default: `null`)::
  Do not activate the `default` feature.
 rust-analyzer.checkOnSave.target (default: `null`)::
- Check for a specific target. Defaults to  `rust-analyzer.cargo.target`.
+ Check for a specific target. Defaults to  `#rust-analyzer.cargo.target#`.
 rust-analyzer.checkOnSave.extraArgs (default: `[]`)::
  Extra arguments for `cargo check`.
 rust-analyzer.checkOnSave.features (default: `null`)::
- List of features to activate. Defaults to  `rust-analyzer.cargo.features`.
+ List of features to activate. Defaults to  `#rust-analyzer.cargo.features#`.
 rust-analyzer.checkOnSave.overrideCommand (default: `null`)::
  Advanced option, fully override the command rust-analyzer uses for  checking. The command should include `--message-format=json` or  similar option.
 rust-analyzer.completion.addCallArgumentSnippets (default: `true`)::
@@ -43,7 +43,7 @@ rust-analyzer.completion.addCallParenthesis (default: `true`)::
 rust-analyzer.completion.postfix.enable (default: `true`)::
  Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
 rust-analyzer.completion.autoimport.enable (default: `true`)::
- Toggles the additional completions that automatically add imports when completed.  Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
+ Toggles the additional completions that automatically add imports when completed.  Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
 rust-analyzer.diagnostics.enable (default: `true`)::
  Whether to show native rust-analyzer diagnostics.
 rust-analyzer.diagnostics.enableExperimental (default: `true`)::
@@ -51,9 +51,9 @@ rust-analyzer.diagnostics.enableExperimental (default: `true`)::
 rust-analyzer.diagnostics.disabled (default: `[]`)::
  List of rust-analyzer diagnostics to disable.
 rust-analyzer.diagnostics.warningsAsHint (default: `[]`)::
- List of warnings that should be displayed with info severity.\nThe  warnings will be indicated by a blue squiggly underline in code and  a blue icon in the problems panel.
+ List of warnings that should be displayed with info severity.\n\nThe  warnings will be indicated by a blue squiggly underline in code and  a blue icon in the `Problems Panel`.
 rust-analyzer.diagnostics.warningsAsInfo (default: `[]`)::
- List of warnings that should be displayed with hint severity.\nThe  warnings will be indicated by faded text or three dots in code and  will not show up in the problems panel.
+ List of warnings that should be displayed with hint severity.\n\nThe  warnings will be indicated by faded text or three dots in code and  will not show up in the `Problems Panel`.
 rust-analyzer.files.watcher (default: `"client"`)::
  Controls file watching implementation.
 rust-analyzer.hoverActions.debug (default: `true`)::
@@ -71,7 +71,7 @@ rust-analyzer.hoverActions.linksInHover (default: `true`)::
 rust-analyzer.inlayHints.chainingHints (default: `true`)::
  Whether to show inlay type hints for method chains.
 rust-analyzer.inlayHints.maxLength (default: `null`)::
- Maximum length for inlay hints.
+ Maximum length for inlay hints. Default is unlimited.
 rust-analyzer.inlayHints.parameterHints (default: `true`)::
  Whether to show function parameter name inlay hints at the call  site.
 rust-analyzer.inlayHints.typeHints (default: `true`)::
@@ -87,20 +87,20 @@ rust-analyzer.lens.run (default: `true`)::
 rust-analyzer.lens.methodReferences (default: `false`)::
  Whether to show `Method References` lens. Only applies when  `#rust-analyzer.lens.enable#` is set.
 rust-analyzer.linkedProjects (default: `[]`)::
- Disable project auto-discovery in favor of explicitly specified set  of projects.  \nElements must be paths pointing to Cargo.toml,  rust-project.json, or JSON objects in rust-project.json format.
+ Disable project auto-discovery in favor of explicitly specified set  of projects.\n\nElements must be paths pointing to `Cargo.toml`,  `rust-project.json`, or JSON objects in `rust-project.json` format.
 rust-analyzer.lruCapacity (default: `null`)::
- Number of syntax trees rust-analyzer keeps in memory.
+ Number of syntax trees rust-analyzer keeps in memory.  Defaults to 128.
 rust-analyzer.notifications.cargoTomlNotFound (default: `true`)::
  Whether to show `can't find Cargo.toml` error message.
 rust-analyzer.procMacro.enable (default: `false`)::
- Enable Proc macro support, cargo.loadOutDirsFromCheck must be  enabled.
+ Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be  enabled.
 rust-analyzer.runnables.overrideCargo (default: `null`)::
  Command to be executed instead of 'cargo' for runnables.
 rust-analyzer.runnables.cargoExtraArgs (default: `[]`)::
- Additional arguments to be passed to cargo for runnables such as  tests or binaries.\nFor example, it may be '--release'.
+ Additional arguments to be passed to cargo for runnables such as  tests or binaries.\nFor example, it may be `--release`.
 rust-analyzer.rustcSource (default: `null`)::
  Path to the rust compiler sources, for usage in rustc_private projects.
 rust-analyzer.rustfmt.extraArgs (default: `[]`)::
- Additional arguments to rustfmt.
+ Additional arguments to `rustfmt`.
 rust-analyzer.rustfmt.overrideCommand (default: `null`)::
  Advanced option, fully override the command rust-analyzer uses for  formatting.
diff --git a/editors/code/.vscodeignore b/editors/code/.vscodeignore
index c1cf00fa01..5096ce4dab 100644
--- a/editors/code/.vscodeignore
+++ b/editors/code/.vscodeignore
@@ -4,5 +4,6 @@
 !package.json
 !package-lock.json
 !ra_syntax_tree.tmGrammar.json
+!rust.tmGrammar.json
 !icon.png
 !README.md
diff --git a/editors/code/package.json b/editors/code/package.json
index abcc84edac..e410fd168b 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -250,12 +250,12 @@
                         }
                     ],
                     "default": null,
-                    "description": "Environment variables passed to the runnable launched using `Test ` or `Debug` lens or `rust-analyzer.run` command."
+                    "markdownDescription": "Environment variables passed to the runnable launched using `Test` or `Debug` lens or `rust-analyzer.run` command."
                 },
                 "rust-analyzer.inlayHints.enable": {
                     "type": "boolean",
                     "default": true,
-                    "description": "Whether to show inlay hints"
+                    "description": "Whether to show inlay hints."
                 },
                 "rust-analyzer.updates.channel": {
                     "type": "string",
@@ -265,15 +265,15 @@
                     ],
                     "default": "stable",
                     "markdownEnumDescriptions": [
-                        "`\"stable\"` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general",
-                        "`\"nightly\"` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**"
+                        "`stable` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general.",
+                        "`nightly` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**."
                     ],
-                    "markdownDescription": "Choose `\"nightly\"` updates to get the latest features and bug fixes every day. While `\"stable\"` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs"
+                    "markdownDescription": "Choose `nightly` updates to get the latest features and bug fixes every day. While `stable` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs."
                 },
                 "rust-analyzer.updates.askBeforeDownload": {
                     "type": "boolean",
                     "default": true,
-                    "description": "Whether to ask for permission before downloading any files from the Internet"
+                    "description": "Whether to ask for permission before downloading any files from the Internet."
                 },
                 "rust-analyzer.serverPath": {
                     "type": [
@@ -281,7 +281,7 @@
                         "string"
                     ],
                     "default": null,
-                    "description": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then \"rust-analyzer.updates.channel\" setting is not used"
+                    "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used"
                 },
                 "rust-analyzer.trace.server": {
                     "type": "string",
@@ -297,10 +297,10 @@
                         "Full log"
                     ],
                     "default": "off",
-                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)"
+                    "description": "Trace requests to the rust-analyzer (this is usually overly verbose and not recommended for regular users)."
                 },
                 "rust-analyzer.trace.extension": {
-                    "description": "Enable logging of VS Code extensions itself",
+                    "description": "Enable logging of VS Code extensions itself.",
                     "type": "boolean",
                     "default": false
                 },
@@ -327,14 +327,14 @@
                     }
                 },
                 "rust-analyzer.debug.openDebugPane": {
-                    "description": "Whether to open up the Debug Pane on debugging start.",
+                    "markdownDescription": "Whether to open up the `Debug Panel` on debugging start.",
                     "type": "boolean",
                     "default": false
                 },
                 "rust-analyzer.debug.engineSettings": {
                     "type": "object",
                     "default": {},
-                    "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }"
+                    "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
                 },
                 "rust-analyzer.assist.importMergeBehaviour": {
                     "markdownDescription": "The strategy to use when inserting new imports or merging imports.",
@@ -362,7 +362,7 @@
                     ],
                     "enumDescriptions": [
                         "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
-                        "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name",
+                        "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.",
                         "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
                     ]
                 },
@@ -372,7 +372,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.cargo.autoreload": {
-                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes.",
+                    "markdownDescription": "Automatically refresh project info via `cargo metadata` on `Cargo.toml` changes.",
                     "default": true,
                     "type": "boolean"
                 },
@@ -418,7 +418,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.checkOnSave.allFeatures": {
-                    "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`.",
+                    "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `#rust-analyzer.cargo.allFeatures#`.",
                     "default": null,
                     "type": [
                         "null",
@@ -444,7 +444,7 @@
                     ]
                 },
                 "rust-analyzer.checkOnSave.target": {
-                    "markdownDescription": "Check for a specific target. Defaults to `rust-analyzer.cargo.target`.",
+                    "markdownDescription": "Check for a specific target. Defaults to `#rust-analyzer.cargo.target#`.",
                     "default": null,
                     "type": [
                         "null",
@@ -460,7 +460,7 @@
                     }
                 },
                 "rust-analyzer.checkOnSave.features": {
-                    "markdownDescription": "List of features to activate. Defaults to `rust-analyzer.cargo.features`.",
+                    "markdownDescription": "List of features to activate. Defaults to `#rust-analyzer.cargo.features#`.",
                     "default": null,
                     "type": [
                         "null",
@@ -497,7 +497,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.completion.autoimport.enable": {
-                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
+                    "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
                     "default": true,
                     "type": "boolean"
                 },
@@ -521,7 +521,7 @@
                     "uniqueItems": true
                 },
                 "rust-analyzer.diagnostics.warningsAsHint": {
-                    "markdownDescription": "List of warnings that should be displayed with info severity.\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.",
+                    "markdownDescription": "List of warnings that should be displayed with info severity.\\n\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the `Problems Panel`.",
                     "default": [],
                     "type": "array",
                     "items": {
@@ -529,7 +529,7 @@
                     }
                 },
                 "rust-analyzer.diagnostics.warningsAsInfo": {
-                    "markdownDescription": "List of warnings that should be displayed with hint severity.\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.",
+                    "markdownDescription": "List of warnings that should be displayed with hint severity.\\n\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the `Problems Panel`.",
                     "default": [],
                     "type": "array",
                     "items": {
@@ -577,7 +577,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.inlayHints.maxLength": {
-                    "markdownDescription": "Maximum length for inlay hints.",
+                    "markdownDescription": "Maximum length for inlay hints. Default is unlimited.",
                     "default": null,
                     "type": [
                         "null",
@@ -621,7 +621,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.linkedProjects": {
-                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.  \\nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format.",
+                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects.\\n\\nElements must be paths pointing to `Cargo.toml`, `rust-project.json`, or JSON objects in `rust-project.json` format.",
                     "default": [],
                     "type": "array",
                     "items": {
@@ -632,7 +632,7 @@
                     }
                 },
                 "rust-analyzer.lruCapacity": {
-                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory.",
+                    "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory.  Defaults to 128.",
                     "default": null,
                     "type": [
                         "null",
@@ -646,7 +646,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.procMacro.enable": {
-                    "markdownDescription": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.",
+                    "markdownDescription": "Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be enabled.",
                     "default": false,
                     "type": "boolean"
                 },
@@ -659,7 +659,7 @@
                     ]
                 },
                 "rust-analyzer.runnables.cargoExtraArgs": {
-                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be '--release'.",
+                    "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be `--release`.",
                     "default": [],
                     "type": "array",
                     "items": {
@@ -675,7 +675,7 @@
                     ]
                 },
                 "rust-analyzer.rustfmt.extraArgs": {
-                    "markdownDescription": "Additional arguments to rustfmt.",
+                    "markdownDescription": "Additional arguments to `rustfmt`.",
                     "default": [],
                     "type": "array",
                     "items": {
@@ -748,6 +748,11 @@
             }
         ],
         "grammars": [
+            {
+                "language": "rust",
+                "scopeName": "source.rust",
+                "path": "rust.tmGrammar.json"
+            },
             {
                 "language": "ra_syntax_tree",
                 "scopeName": "source.ra_syntax_tree",
diff --git a/editors/code/rust.tmGrammar.json b/editors/code/rust.tmGrammar.json
new file mode 100644
index 0000000000..4759bb1162
--- /dev/null
+++ b/editors/code/rust.tmGrammar.json
@@ -0,0 +1,1140 @@
+{
+    "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+    "name": "Rust",
+    "fileTypes": [
+        "rs"
+    ],
+    "scopeName": "source.rust",
+    "patterns": [
+        {
+            "comment": "boxed slice literal",
+            "begin": "(<)(\\[)",
+            "beginCaptures": {
+                "1": {
+                    "name": "punctuation.brackets.angle.rust"
+                },
+                "2": {
+                    "name": "punctuation.brackets.square.rust"
+                }
+            },
+            "end": ">",
+            "endCaptures": {
+                "0": {
+                    "name": "punctuation.brackets.angle.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#block-comments"
+                },
+                {
+                    "include": "#comments"
+                },
+                {
+                    "include": "#gtypes"
+                },
+                {
+                    "include": "#lvariables"
+                },
+                {
+                    "include": "#lifetimes"
+                },
+                {
+                    "include": "#punctuation"
+                },
+                {
+                    "include": "#types"
+                }
+            ]
+        },
+        {
+            "comment": "macro type metavariables",
+            "name": "meta.macro.metavariable.type.rust",
+            "match": "(\\$)((crate)|([A-Z][A-Za-z0-9_]*))((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?",
+            "captures": {
+                "1": {
+                    "name": "keyword.operator.macro.dollar.rust"
+                },
+                "3": {
+                    "name": "keyword.other.crate.rust"
+                },
+                "4": {
+                    "name": "entity.name.type.metavariable.rust"
+                },
+                "6": {
+                    "name": "keyword.operator.key-value.rust"
+                },
+                "7": {
+                    "name": "variable.other.metavariable.specifier.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#keywords"
+                }
+            ]
+        },
+        {
+            "comment": "macro metavariables",
+            "name": "meta.macro.metavariable.rust",
+            "match": "(\\$)([a-z][A-Za-z0-9_]*)((:)(block|expr|ident|item|lifetime|literal|meta|path?|stmt|tt|ty|vis))?",
+            "captures": {
+                "1": {
+                    "name": "keyword.operator.macro.dollar.rust"
+                },
+                "2": {
+                    "name": "variable.other.metavariable.name.rust"
+                },
+                "4": {
+                    "name": "keyword.operator.key-value.rust"
+                },
+                "5": {
+                    "name": "variable.other.metavariable.specifier.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#keywords"
+                }
+            ]
+        },
+        {
+            "comment": "macro rules",
+            "name": "meta.macro.rules.rust",
+            "match": "\\b(macro_rules!)\\s+(([a-z0-9_]+)|([A-Z][a-z0-9_]*))\\s+(\\{)",
+            "captures": {
+                "1": {
+                    "name": "entity.name.function.macro.rules.rust"
+                },
+                "3": {
+                    "name": "entity.name.function.macro.rust"
+                },
+                "4": {
+                    "name": "entity.name.type.macro.rust"
+                },
+                "5": {
+                    "name": "punctuation.brackets.curly.rust"
+                }
+            }
+        },
+        {
+            "comment": "attributes",
+            "name": "meta.attribute.rust",
+            "begin": "(#)(\\!?)(\\[)",
+            "beginCaptures": {
+                "1": {
+                    "name": "punctuation.definition.attribute.rust"
+                },
+                "2": {
+                    "name": "keyword.operator.attribute.inner.rust"
+                },
+                "3": {
+                    "name": "punctuation.brackets.attribute.rust"
+                }
+            },
+            "end": "\\]",
+            "endCaptures": {
+                "0": {
+                    "name": "punctuation.brackets.attribute.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#block-comments"
+                },
+                {
+                    "include": "#comments"
+                },
+                {
+                    "include": "#keywords"
+                },
+                {
+                    "include": "#punctuation"
+                },
+                {
+                    "include": "#strings"
+                },
+                {
+                    "include": "#gtypes"
+                },
+                {
+                    "include": "#types"
+                }
+            ]
+        },
+        {
+            "comment": "modules",
+            "match": "(mod)\\s+((?:r#(?!crate|[Ss]elf|super))?[a-z][A-Za-z0-9_]*)",
+            "captures": {
+                "1": {
+                    "name": "storage.type.rust"
+                },
+                "2": {
+                    "name": "entity.name.module.rust"
+                }
+            }
+        },
+        {
+            "comment": "external crate imports",
+            "name": "meta.import.rust",
+            "begin": "\\b(extern)\\s+(crate)",
+            "beginCaptures": {
+                "1": {
+                    "name": "storage.type.rust"
+                },
+                "2": {
+                    "name": "keyword.other.crate.rust"
+                }
+            },
+            "end": ";",
+            "endCaptures": {
+                "0": {
+                    "name": "punctuation.semi.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#block-comments"
+                },
+                {
+                    "include": "#comments"
+                },
+                {
+                    "include": "#keywords"
+                },
+                {
+                    "include": "#punctuation"
+                }
+            ]
+        },
+        {
+            "comment": "use statements",
+            "name": "meta.use.rust",
+            "begin": "\\b(use)\\s",
+            "beginCaptures": {
+                "1": {
+                    "name": "keyword.other.rust"
+                }
+            },
+            "end": ";",
+            "endCaptures": {
+                "0": {
+                    "name": "punctuation.semi.rust"
+                }
+            },
+            "patterns": [
+                {
+                    "include": "#block-comments"
+                },
+                {
+                    "include": "#comments"
+                },
+                {
+                    "include": "#keywords"
+                },
+                {
+                    "include": "#namespaces"
+                },
+                {
+                    "include": "#punctuation"
+                },
+                {
+                    "include": "#types"
+                },
+                {
+                    "include": "#lvariables"
+                }
+            ]
+        },
+        {
+            "include": "#block-comments"
+        },
+        {
+            "include": "#comments"
+        },
+        {
+            "include": "#lvariables"
+        },
+        {
+            "include": "#constants"
+        },
+        {
+            "include": "#gtypes"
+        },
+        {
+            "include": "#functions"
+        },
+        {
+            "include": "#types"
+        },
+        {
+            "include": "#keywords"
+        },
+        {
+            "include": "#lifetimes"
+        },
+        {
+            "include": "#macros"
+        },
+        {
+            "include": "#namespaces"
+        },
+        {
+            "include": "#punctuation"
+        },
+        {
+            "include": "#strings"
+        },
+        {
+            "include": "#variables"
+        }
+    ],
+    "repository": {
+        "comments": {
+            "patterns": [
+                {
+                    "comment": "documentation comments",
+                    "name": "comment.line.documentation.rust",
+                    "match": "^\\s*///.*"
+                },
+                {
+                    "comment": "line comments",
+                    "name": "comment.line.double-slash.rust",
+                    "match": "\\s*//.*"
+                }
+            ]
+        },
+        "block-comments": {
+            "patterns": [
+                {
+                    "comment": "empty block comments",
+                    "name": "comment.block.rust",
+                    "match": "/\\*\\*/"
+                },
+                {
+                    "comment": "block documentation comments",
+                    "name": "comment.block.documentation.rust",
+                    "begin": "/\\*\\*",
+                    "end": "\\*/",
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        }
+                    ]
+                },
+                {
+                    "comment": "block comments",
+                    "name": "comment.block.rust",
+                    "begin": "/\\*(?!\\*)",
+                    "end": "\\*/",
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        }
+                    ]
+                }
+            ]
+        },
+        "constants": {
+            "patterns": [
+                {
+                    "comment": "ALL CAPS constants",
+                    "name": "constant.other.caps.rust",
+                    "match": "\\b[A-Z]{2}[A-Z0-9_]*\\b"
+                },
+                {
+                    "comment": "constant declarations",
+                    "match": "\\b(const)\\s+([A-Z][A-Za-z0-9_]*)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "storage.type.rust"
+                        },
+                        "2": {
+                            "name": "constant.other.caps.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "decimal integers and floats",
+                    "name": "constant.numeric.decimal.rust",
+                    "match": "\\b\\d[\\d_]*(\\.?)[\\d_]*(?:(E)([+-])([\\d_]+))?(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b",
+                    "captures": {
+                        "1": {
+                            "name": "punctuation.separator.dot.decimal.rust"
+                        },
+                        "2": {
+                            "name": "keyword.operator.exponent.rust"
+                        },
+                        "3": {
+                            "name": "keyword.operator.exponent.sign.rust"
+                        },
+                        "4": {
+                            "name": "constant.numeric.decimal.exponent.mantissa.rust"
+                        },
+                        "5": {
+                            "name": "entity.name.type.numeric.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "hexadecimal integers",
+                    "name": "constant.numeric.hex.rust",
+                    "match": "\\b0x[\\da-fA-F_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.numeric.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "octal integers",
+                    "name": "constant.numeric.oct.rust",
+                    "match": "\\b0o[0-7_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.numeric.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "binary integers",
+                    "name": "constant.numeric.bin.rust",
+                    "match": "\\b0b[01_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.numeric.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "booleans",
+                    "name": "constant.language.bool.rust",
+                    "match": "\\b(true|false)\\b"
+                }
+            ]
+        },
+        "escapes": {
+            "comment": "escapes: ASCII, byte, Unicode, quote, regex",
+            "name": "constant.character.escape.rust",
+            "match": "(\\\\)(?:(?:(x[0-7][0-7a-fA-F])|(u(\\{)[\\da-fA-F]{4,6}(\\}))|.))",
+            "captures": {
+                "1": {
+                    "name": "constant.character.escape.backslash.rust"
+                },
+                "2": {
+                    "name": "constant.character.escape.bit.rust"
+                },
+                "3": {
+                    "name": "constant.character.escape.unicode.rust"
+                },
+                "4": {
+                    "name": "constant.character.escape.unicode.punctuation.rust"
+                },
+                "5": {
+                    "name": "constant.character.escape.unicode.punctuation.rust"
+                }
+            }
+        },
+        "functions": {
+            "patterns": [
+                {
+                    "comment": "pub as a function",
+                    "match": "\\b(pub)(\\()",
+                    "captures": {
+                        "1": {
+                            "name": "keyword.other.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.brackets.round.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "function definition",
+                    "name": "meta.function.definition.rust",
+                    "begin": "\\b(fn)\\s+((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)((\\()|(<))",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "keyword.other.fn.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.function.rust"
+                        },
+                        "4": {
+                            "name": "punctuation.brackets.round.rust"
+                        },
+                        "5": {
+                            "name": "punctuation.brackets.angle.rust"
+                        }
+                    },
+                    "end": "\\{|;",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.brackets.curly.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        },
+                        {
+                            "include": "#comments"
+                        },
+                        {
+                            "include": "#keywords"
+                        },
+                        {
+                            "include": "#lvariables"
+                        },
+                        {
+                            "include": "#constants"
+                        },
+                        {
+                            "include": "#gtypes"
+                        },
+                        {
+                            "include": "#functions"
+                        },
+                        {
+                            "include": "#lifetimes"
+                        },
+                        {
+                            "include": "#macros"
+                        },
+                        {
+                            "include": "#namespaces"
+                        },
+                        {
+                            "include": "#punctuation"
+                        },
+                        {
+                            "include": "#strings"
+                        },
+                        {
+                            "include": "#types"
+                        },
+                        {
+                            "include": "#variables"
+                        }
+                    ]
+                },
+                {
+                    "comment": "function/method calls, chaining",
+                    "name": "meta.function.call.rust",
+                    "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(\\()",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "entity.name.function.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.brackets.round.rust"
+                        }
+                    },
+                    "end": "\\)",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.brackets.round.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        },
+                        {
+                            "include": "#comments"
+                        },
+                        {
+                            "include": "#keywords"
+                        },
+                        {
+                            "include": "#lvariables"
+                        },
+                        {
+                            "include": "#constants"
+                        },
+                        {
+                            "include": "#gtypes"
+                        },
+                        {
+                            "include": "#functions"
+                        },
+                        {
+                            "include": "#lifetimes"
+                        },
+                        {
+                            "include": "#macros"
+                        },
+                        {
+                            "include": "#namespaces"
+                        },
+                        {
+                            "include": "#punctuation"
+                        },
+                        {
+                            "include": "#strings"
+                        },
+                        {
+                            "include": "#types"
+                        },
+                        {
+                            "include": "#variables"
+                        }
+                    ]
+                },
+                {
+                    "comment": "function/method calls with turbofish",
+                    "name": "meta.function.call.rust",
+                    "begin": "((?:r#(?!crate|[Ss]elf|super))?[A-Za-z0-9_]+)(?=::<.*>\\()",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "entity.name.function.rust"
+                        }
+                    },
+                    "end": "\\)",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.brackets.round.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        },
+                        {
+                            "include": "#comments"
+                        },
+                        {
+                            "include": "#keywords"
+                        },
+                        {
+                            "include": "#lvariables"
+                        },
+                        {
+                            "include": "#constants"
+                        },
+                        {
+                            "include": "#gtypes"
+                        },
+                        {
+                            "include": "#functions"
+                        },
+                        {
+                            "include": "#lifetimes"
+                        },
+                        {
+                            "include": "#macros"
+                        },
+                        {
+                            "include": "#namespaces"
+                        },
+                        {
+                            "include": "#punctuation"
+                        },
+                        {
+                            "include": "#strings"
+                        },
+                        {
+                            "include": "#types"
+                        },
+                        {
+                            "include": "#variables"
+                        }
+                    ]
+                }
+            ]
+        },
+        "keywords": {
+            "patterns": [
+                {
+                    "comment": "control flow keywords",
+                    "name": "keyword.control.rust",
+                    "match": "\\b(await|break|continue|do|else|for|if|loop|match|return|try|while|yield)\\b"
+                },
+                {
+                    "comment": "storage keywords",
+                    "name": "storage.type.rust",
+                    "match": "\\b(const|enum|extern|let|macro|mod|struct|trait|type)\\b"
+                },
+                {
+                    "comment": "storage modifiers",
+                    "name": "storage.modifier.rust",
+                    "match": "\\b(abstract|static)\\b"
+                },
+                {
+                    "comment": "other keywords",
+                    "name": "keyword.other.rust",
+                    "match": "\\b(as|async|become|box|dyn|move|final|impl|in|override|priv|pub|ref|typeof|union|unsafe|unsized|use|virtual|where)\\b"
+                },
+                {
+                    "comment": "fn",
+                    "name": "keyword.other.fn.rust",
+                    "match": "\\bfn\\b"
+                },
+                {
+                    "comment": "crate",
+                    "name": "keyword.other.crate.rust",
+                    "match": "\\bcrate\\b"
+                },
+                {
+                    "comment": "mut",
+                    "name": "storage.modifier.mut.rust",
+                    "match": "\\bmut\\b"
+                },
+                {
+                    "comment": "logical operators",
+                    "name": "keyword.operator.logical.rust",
+                    "match": "(\\^|\\||\\|\\||&&|<<|>>|!)(?!=)"
+                },
+                {
+                    "comment": "logical AND, borrow references",
+                    "name": "keyword.operator.borrow.and.rust",
+                    "match": "&(?![&=])"
+                },
+                {
+                    "comment": "assignment operators",
+                    "name": "keyword.operator.assignment.rust",
+                    "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|<<=|>>=)"
+                },
+                {
+                    "comment": "single equal",
+                    "name": "keyword.operator.assignment.equal.rust",
+                    "match": "(?<![<>])=(?!=|>)"
+                },
+                {
+                    "comment": "comparison operators",
+                    "name": "keyword.operator.comparison.rust",
+                    "match": "(=(=)?(?!>)|!=|<=|(?<!=)>=)"
+                },
+                {
+                    "comment": "math operators",
+                    "name": "keyword.operator.math.rust",
+                    "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))"
+                },
+                {
+                    "comment": "less than, greater than (special case)",
+                    "match": "(?:\\b|(?:(\\))|(\\])|(\\})))[ \\t]+([<>])[ \\t]+(?:\\b|(?:(\\()|(\\[)|(\\{)))",
+                    "captures": {
+                        "1": {
+                            "name": "punctuation.brackets.round.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.brackets.square.rust"
+                        },
+                        "3": {
+                            "name": "punctuation.brackets.curly.rust"
+                        },
+                        "4": {
+                            "name": "keyword.operator.comparison.rust"
+                        },
+                        "5": {
+                            "name": "punctuation.brackets.round.rust"
+                        },
+                        "6": {
+                            "name": "punctuation.brackets.square.rust"
+                        },
+                        "7": {
+                            "name": "punctuation.brackets.curly.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "namespace operator",
+                    "name": "keyword.operator.namespace.rust",
+                    "match": "::"
+                },
+                {
+                    "comment": "dereference asterisk",
+                    "match": "(\\*)(?=\\w+)",
+                    "captures": {
+                        "1": {
+                            "name": "keyword.operator.dereference.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "subpattern binding",
+                    "name": "keyword.operator.subpattern.rust",
+                    "match": "@"
+                },
+                {
+                    "comment": "dot access",
+                    "name": "keyword.operator.access.dot.rust",
+                    "match": "\\.(?!\\.)"
+                },
+                {
+                    "comment": "ranges, range patterns",
+                    "name": "keyword.operator.range.rust",
+                    "match": "\\.{2}(=|\\.)?"
+                },
+                {
+                    "comment": "colon",
+                    "name": "keyword.operator.key-value.rust",
+                    "match": ":(?!:)"
+                },
+                {
+                    "comment": "dashrocket, skinny arrow",
+                    "name": "keyword.operator.arrow.skinny.rust",
+                    "match": "->"
+                },
+                {
+                    "comment": "hashrocket, fat arrow",
+                    "name": "keyword.operator.arrow.fat.rust",
+                    "match": "=>"
+                },
+                {
+                    "comment": "dollar macros",
+                    "name": "keyword.operator.macro.dollar.rust",
+                    "match": "\\$"
+                },
+                {
+                    "comment": "question mark operator, questionably sized, macro kleene matcher",
+                    "name": "keyword.operator.question.rust",
+                    "match": "\\?"
+                }
+            ]
+        },
+        "interpolations": {
+            "comment": "curly brace interpolations",
+            "name": "meta.interpolation.rust",
+            "match": "({)[^\"{}]*(})",
+            "captures": {
+                "1": {
+                    "name": "punctuation.definition.interpolation.rust"
+                },
+                "2": {
+                    "name": "punctuation.definition.interpolation.rust"
+                }
+            }
+        },
+        "lifetimes": {
+            "patterns": [
+                {
+                    "comment": "named lifetime parameters",
+                    "match": "(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b",
+                    "captures": {
+                        "1": {
+                            "name": "punctuation.definition.lifetime.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.type.lifetime.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "borrowing references to named lifetimes",
+                    "match": "(\\&)(['])([a-zA-Z_][0-9a-zA-Z_]*)(?!['])\\b",
+                    "captures": {
+                        "1": {
+                            "name": "keyword.operator.borrow.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.definition.lifetime.rust"
+                        },
+                        "3": {
+                            "name": "entity.name.type.lifetime.rust"
+                        }
+                    }
+                }
+            ]
+        },
+        "macros": {
+            "patterns": [
+                {
+                    "comment": "macros",
+                    "name": "meta.macro.rust",
+                    "match": "(([a-z_][A-Za-z0-9_]*!)|([A-Z_][A-Za-z0-9_]*!))",
+                    "captures": {
+                        "2": {
+                            "name": "entity.name.function.macro.rust"
+                        },
+                        "3": {
+                            "name": "entity.name.type.macro.rust"
+                        }
+                    }
+                }
+            ]
+        },
+        "namespaces": {
+            "patterns": [
+                {
+                    "comment": "namespace (non-type, non-function path segment)",
+                    "match": "(?<![A-Za-z0-9_])([a-z0-9_]+)((?<!super|self)::)",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.namespace.rust"
+                        },
+                        "2": {
+                            "name": "keyword.operator.namespace.rust"
+                        }
+                    }
+                }
+            ]
+        },
+        "types": {
+            "patterns": [
+                {
+                    "comment": "numeric types",
+                    "match": "(?<![A-Za-z])(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "entity.name.type.numeric.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "parameterized types",
+                    "begin": "\\b([A-Z][A-Za-z0-9]*)(<)",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "entity.name.type.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.brackets.angle.rust"
+                        }
+                    },
+                    "end": ">",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.brackets.angle.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#block-comments"
+                        },
+                        {
+                            "include": "#comments"
+                        },
+                        {
+                            "include": "#keywords"
+                        },
+                        {
+                            "include": "#lvariables"
+                        },
+                        {
+                            "include": "#lifetimes"
+                        },
+                        {
+                            "include": "#punctuation"
+                        },
+                        {
+                            "include": "#types"
+                        },
+                        {
+                            "include": "#variables"
+                        }
+                    ]
+                },
+                {
+                    "comment": "primitive types",
+                    "name": "entity.name.type.primitive.rust",
+                    "match": "\\b(bool|char|str)\\b"
+                },
+                {
+                    "comment": "trait declarations",
+                    "match": "\\b(trait)\\s+([A-Z][A-Za-z0-9]*)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "storage.type.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.type.trait.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "struct declarations",
+                    "match": "\\b(struct)\\s+([A-Z][A-Za-z0-9]*)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "storage.type.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.type.struct.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "enum declarations",
+                    "match": "\\b(enum)\\s+([A-Z][A-Za-z0-9_]*)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "storage.type.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.type.enum.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "type declarations",
+                    "match": "\\b(type)\\s+([A-Z][A-Za-z0-9_]*)\\b",
+                    "captures": {
+                        "1": {
+                            "name": "storage.type.rust"
+                        },
+                        "2": {
+                            "name": "entity.name.type.declaration.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "types",
+                    "name": "entity.name.type.rust",
+                    "match": "\\b[A-Z][A-Za-z0-9]*\\b(?!!)"
+                }
+            ]
+        },
+        "gtypes": {
+            "patterns": [
+                {
+                    "comment": "option types",
+                    "name": "entity.name.type.option.rust",
+                    "match": "\\b(Some|None)\\b"
+                },
+                {
+                    "comment": "result types",
+                    "name": "entity.name.type.result.rust",
+                    "match": "\\b(Ok|Err)\\b"
+                }
+            ]
+        },
+        "punctuation": {
+            "patterns": [
+                {
+                    "comment": "comma",
+                    "name": "punctuation.comma.rust",
+                    "match": ","
+                },
+                {
+                    "comment": "curly braces",
+                    "name": "punctuation.brackets.curly.rust",
+                    "match": "[{}]"
+                },
+                {
+                    "comment": "parentheses, round brackets",
+                    "name": "punctuation.brackets.round.rust",
+                    "match": "[()]"
+                },
+                {
+                    "comment": "semicolon",
+                    "name": "punctuation.semi.rust",
+                    "match": ";"
+                },
+                {
+                    "comment": "square brackets",
+                    "name": "punctuation.brackets.square.rust",
+                    "match": "[\\[\\]]"
+                },
+                {
+                    "comment": "angle brackets",
+                    "name": "punctuation.brackets.angle.rust",
+                    "match": "(?<!=)[<>]"
+                }
+            ]
+        },
+        "strings": {
+            "patterns": [
+                {
+                    "comment": "double-quoted strings and byte strings",
+                    "name": "string.quoted.double.rust",
+                    "begin": "(b?)(\")",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "string.quoted.byte.raw.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.definition.string.rust"
+                        }
+                    },
+                    "end": "\"",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.definition.string.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#escapes"
+                        },
+                        {
+                            "include": "#interpolations"
+                        }
+                    ]
+                },
+                {
+                    "comment": "double-quoted raw strings and raw byte strings",
+                    "name": "string.quoted.double.rust",
+                    "begin": "(b?r)(#*)(\")",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "string.quoted.byte.raw.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.definition.string.raw.rust"
+                        },
+                        "3": {
+                            "name": "punctuation.definition.string.rust"
+                        }
+                    },
+                    "end": "(\")(\\2)",
+                    "endCaptures": {
+                        "1": {
+                            "name": "punctuation.definition.string.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.definition.string.raw.rust"
+                        }
+                    }
+                },
+                {
+                    "comment": "characters and bytes",
+                    "name": "string.quoted.single.char.rust",
+                    "begin": "(b)?(')",
+                    "beginCaptures": {
+                        "1": {
+                            "name": "string.quoted.byte.raw.rust"
+                        },
+                        "2": {
+                            "name": "punctuation.definition.char.rust"
+                        }
+                    },
+                    "end": "'",
+                    "endCaptures": {
+                        "0": {
+                            "name": "punctuation.definition.char.rust"
+                        }
+                    },
+                    "patterns": [
+                        {
+                            "include": "#escapes"
+                        }
+                    ]
+                }
+            ]
+        },
+        "lvariables": {
+            "patterns": [
+                {
+                    "comment": "self",
+                    "name": "variable.language.self.rust",
+                    "match": "\\b[Ss]elf\\b"
+                },
+                {
+                    "comment": "super",
+                    "name": "variable.language.super.rust",
+                    "match": "\\bsuper\\b"
+                }
+            ]
+        },
+        "variables": {
+            "patterns": [
+                {
+                    "comment": "variables",
+                    "name": "variable.other.rust",
+                    "match": "\\b(?<!(?<!\\.)\\.)(?:r#(?!(crate|[Ss]elf|super)))?[a-z0-9_]+\\b"
+                }
+            ]
+        }
+    }
+}
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 9d4823a34d..92bc4d7f72 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -470,7 +470,7 @@ export function resolveCodeAction(ctx: Ctx): Cmd {
             return;
         }
         const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit);
-        await vscode.workspace.applyEdit(edit);
+        await applySnippetWorkspaceEdit(edit);
     };
 }
 
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index d07ad94204..9e15a5a4c9 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -58,74 +58,30 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
 }
 
 fn dist_server() -> Result<()> {
-    let target = get_target();
-    if target.contains("-linux-gnu") {
+    if cfg!(target_os = "linux") {
         env::set_var("CC", "clang");
     }
+    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release").run()?;
+
+    let (src, dst) = if cfg!(target_os = "linux") {
+        ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux")
+    } else if cfg!(target_os = "windows") {
+        ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe")
+    } else if cfg!(target_os = "macos") {
+        ("./target/release/rust-analyzer", "./dist/rust-analyzer-mac")
+    } else {
+        panic!("Unsupported OS")
+    };
 
-    let toolchain = toolchain(&target);
-    cmd!("cargo +{toolchain} build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target} --release").run()?;
+    let src = Path::new(src);
+    let dst = Path::new(dst);
 
-    let suffix = exe_suffix(&target);
-    let src =
-        Path::new("target").join(&target).join("release").join(format!("rust-analyzer{}", suffix));
-    let dst = Path::new("dist").join(format!("rust-analyzer-{}{}", target, suffix));
     cp(&src, &dst)?;
     gzip(&src, &dst.with_extension("gz"))?;
 
-    // FIXME: the old names are temporarily kept for client compatibility, but they should be removed
-    // Remove this block after a couple of releases
-    match target.as_ref() {
-        "x86_64-unknown-linux-gnu" => {
-            cp(&src, "dist/rust-analyzer-linux")?;
-            gzip(&src, Path::new("dist/rust-analyzer-linux.gz"))?;
-        }
-        "x86_64-pc-windows-msvc" => {
-            cp(&src, "dist/rust-analyzer-windows.exe")?;
-            gzip(&src, Path::new("dist/rust-analyzer-windows.gz"))?;
-        }
-        "x86_64-apple-darwin" => {
-            cp(&src, "dist/rust-analyzer-mac")?;
-            gzip(&src, Path::new("dist/rust-analyzer-mac.gz"))?;
-        }
-        _ => {}
-    }
-
     Ok(())
 }
 
-fn get_target() -> String {
-    match env::var("RA_TARGET") {
-        Ok(target) => target,
-        _ => {
-            if cfg!(target_os = "linux") {
-                "x86_64-unknown-linux-gnu".to_string()
-            } else if cfg!(target_os = "windows") {
-                "x86_64-pc-windows-msvc".to_string()
-            } else if cfg!(target_os = "macos") {
-                "x86_64-apple-darwin".to_string()
-            } else {
-                panic!("Unsupported OS, maybe try setting RA_TARGET")
-            }
-        }
-    }
-}
-
-fn exe_suffix(target: &str) -> String {
-    if target.contains("-windows-") {
-        ".exe".into()
-    } else {
-        "".into()
-    }
-}
-
-fn toolchain(target: &str) -> String {
-    match target {
-        "aarch64-apple-darwin" => "beta".to_string(),
-        _ => "stable".to_string(),
-    }
-}
-
 fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
     let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
     let mut input = io::BufReader::new(File::open(src_path)?);


Test patch:
diff --git a/crates/assists/src/tests.rs b/crates/assists/src/tests.rs
index b41f4874a5..709a34d03a 100644
--- a/crates/assists/src/tests.rs
+++ b/crates/assists/src/tests.rs
@@ -2,7 +2,6 @@ mod generated;
 
 use hir::Semantics;
 use ide_db::base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt};
-use ide_db::source_change::FileSystemEdit;
 use ide_db::RootDatabase;
 use syntax::TextRange;
 use test_utils::{assert_eq_text, extract_offset, extract_range};
@@ -48,7 +47,7 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
     let before = db.file_text(file_id).to_string();
     let frange = FileRange { file_id, range: selection.into() };
 
-    let assist = Assist::resolved(&db, &AssistConfig::default(), frange)
+    let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange)
         .into_iter()
         .find(|assist| assist.assist.id.0 == assist_id)
         .unwrap_or_else(|| {
@@ -64,12 +63,9 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
         });
 
     let actual = {
+        let change = assist.source_change.source_file_edits.pop().unwrap();
         let mut actual = before;
-        for source_file_edit in assist.source_change.source_file_edits {
-            if source_file_edit.file_id == file_id {
-                source_file_edit.edit.apply(&mut actual)
-            }
-        }
+        change.edit.apply(&mut actual);
         actual
     };
     assert_eq_text!(&after, &actual);
@@ -103,8 +99,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
         (Some(assist), ExpectedResult::After(after)) => {
             let mut source_change = assist.source_change;
             assert!(!source_change.source_file_edits.is_empty());
-            let skip_header = source_change.source_file_edits.len() == 1
-                && source_change.file_system_edits.len() == 0;
+            let skip_header = source_change.source_file_edits.len() == 1;
             source_change.source_file_edits.sort_by_key(|it| it.file_id);
 
             let mut buf = String::new();
@@ -120,21 +115,6 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
                 buf.push_str(&text);
             }
 
-            for file_system_edit in source_change.file_system_edits.clone() {
-                match file_system_edit {
-                    FileSystemEdit::CreateFile { dst, initial_contents } => {
-                        let sr = db.file_source_root(dst.anchor);
-                        let sr = db.source_root(sr);
-                        let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
-                        base.pop();
-                        let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
-                        format_to!(buf, "//- {}\n", created_file_path);
-                        buf.push_str(&initial_contents);
-                    }
-                    _ => (),
-                }
-            }
-
             assert_eq_text!(after, &buf);
         }
         (Some(assist), ExpectedResult::Target(target)) => {
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index e9093ec536..cc7c4a3433 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -235,21 +235,6 @@ fn qux(bar: Bar, baz: Baz) {}
     )
 }
 
-#[test]
-fn doctest_extract_module_to_file() {
-    check_doc_test(
-        "extract_module_to_file",
-        r#####"
-mod foo {<|>
-    fn t() {}
-}
-"#####,
-        r#####"
-mod foo;
-"#####,
-    )
-}
-
 #[test]
 fn doctest_extract_struct_from_enum_variant() {
     check_doc_test(