Repository: rust-analyzer/rust-analyzer
Pull request #1347 (2019-05-29 20:59:40)

Add status buffer function to emacs integration
Also fix a minor race condition in the 'extend selection' initialization.


Patch:
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 42dcac3320..9b9212bfcb 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -222,7 +222,6 @@ fn or(left: ItemOrMacro, right: ItemOrMacro) -> ItemOrMacro {
 
 impl CrateDefMap {
     pub(crate) fn crate_def_map_query(db: &impl DefDatabase, krate: Crate) -> Arc<CrateDefMap> {
-        db.check_canceled();
         let _p = profile("crate_def_map_query");
         let def_map = {
             let edition = krate.edition(db);
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index af8ac064c4..ba7ea00174 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -112,7 +112,6 @@ where
         // main name resolution fixed-point loop.
         let mut i = 0;
         loop {
-            self.db.check_canceled();
             match (self.resolve_imports(), self.resolve_macros()) {
                 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break,
                 _ => i += 1,
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index fc90f56d50..e6c78c0d45 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -82,7 +82,6 @@ pub(crate) fn implements_query(
     krate: Crate,
     trait_ref: Canonical<TraitRef>,
 ) -> Option<Solution> {
-    db.check_canceled();
     let _p = profile("implements_query");
     let goal: chalk_ir::Goal = trait_ref.value.to_chalk(db).cast();
     debug!("goal: {:?}", goal);
diff --git a/crates/ra_ide_api/src/snapshots/highlighting.html b/crates/ra_ide_api/src/snapshots/highlighting.html
index d79d35bf31..2a32b32413 100644
--- a/crates/ra_ide_api/src/snapshots/highlighting.html
+++ b/crates/ra_ide_api/src/snapshots/highlighting.html
@@ -19,13 +19,13 @@ pre        { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4e
 </style>
 <pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span>
 <span class="keyword">struct</span> <span class="type">Foo</span> {
-    <span class="keyword">pub</span> <span class="function">x</span>: <span class="type">i32</span>,
-    <span class="keyword">pub</span> <span class="function">y</span>: <span class="type">i32</span>,
+    <span class="keyword">pub</span> <span class="function">x</span>: <span class="text">i32</span>,
+    <span class="keyword">pub</span> <span class="function">y</span>: <span class="text">i32</span>,
 }
 
-<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">T</span> {
+<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type type">T</span>&gt;() -&gt; <span class="type">T</span> {
     <span class="macro">unimplemented</span><span class="macro">!</span>();
-    <span class="function">foo</span>::&lt;<span class="type">i32</span>&gt;();
+    <span class="function">foo</span>::&lt;<span class="type text">i32</span>&gt;();
 }
 
 <span class="comment">// comment</span>
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 4b24754a80..bf4e9c9d14 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -30,14 +30,6 @@ fn is_control_keyword(kind: SyntaxKind) -> bool {
     }
 }
 
-fn is_prim_type(node: &ast::NameRef) -> bool {
-    match node.text().as_str() {
-        "u8" | "i8" | "u16" | "i16" | "u32" | "i32" | "u64" | "i64" | "u128" | "i128" | "usize"
-        | "isize" | "f32" | "f64" | "bool" | "char" | "str" => true,
-        _ => false,
-    }
-}
-
 pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRange> {
     let _p = profile("highlight");
     let source_file = db.parse(file_id).tree;
@@ -70,52 +62,46 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
             ATTR => "attribute",
             NAME_REF => {
                 if let Some(name_ref) = node.as_node().and_then(ast::NameRef::cast) {
-                    // FIXME: revisit this after #1340
-                    if is_prim_type(name_ref) {
-                        "type"
-                    } else {
-                        use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
-                        use hir::{ModuleDef, ImplItem};
+                    use crate::name_ref_kind::{classify_name_ref, NameRefKind::*};
+                    use hir::{ModuleDef, ImplItem};
 
-                        // FIXME: try to reuse the SourceAnalyzers
-                        let analyzer =
-                            hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
-                        match classify_name_ref(db, &analyzer, name_ref) {
-                            Some(Method(_)) => "function",
-                            Some(Macro(_)) => "macro",
-                            Some(FieldAccess(_)) => "field",
-                            Some(AssocItem(ImplItem::Method(_))) => "function",
-                            Some(AssocItem(ImplItem::Const(_))) => "constant",
-                            Some(AssocItem(ImplItem::TypeAlias(_))) => "type",
-                            Some(Def(ModuleDef::Module(_))) => "module",
-                            Some(Def(ModuleDef::Function(_))) => "function",
-                            Some(Def(ModuleDef::Struct(_))) => "type",
-                            Some(Def(ModuleDef::Union(_))) => "type",
-                            Some(Def(ModuleDef::Enum(_))) => "type",
-                            Some(Def(ModuleDef::EnumVariant(_))) => "constant",
-                            Some(Def(ModuleDef::Const(_))) => "constant",
-                            Some(Def(ModuleDef::Static(_))) => "constant",
-                            Some(Def(ModuleDef::Trait(_))) => "type",
-                            Some(Def(ModuleDef::TypeAlias(_))) => "type",
-                            Some(SelfType(_)) => "type",
-                            Some(Pat(ptr)) => {
-                                binding_hash = Some({
-                                    let text = ptr
-                                        .syntax_node_ptr()
-                                        .to_node(&source_file.syntax())
-                                        .text()
-                                        .to_smol_string();
-                                    let shadow_count =
-                                        bindings_shadow_count.entry(text.clone()).or_default();
-                                    calc_binding_hash(file_id, &text, *shadow_count)
-                                });
+                    // FIXME: try to reuse the SourceAnalyzers
+                    let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
+                    match classify_name_ref(db, &analyzer, name_ref) {
+                        Some(Method(_)) => "function",
+                        Some(Macro(_)) => "macro",
+                        Some(FieldAccess(_)) => "field",
+                        Some(AssocItem(ImplItem::Method(_))) => "function",
+                        Some(AssocItem(ImplItem::Const(_))) => "constant",
+                        Some(AssocItem(ImplItem::TypeAlias(_))) => "type",
+                        Some(Def(ModuleDef::Module(_))) => "module",
+                        Some(Def(ModuleDef::Function(_))) => "function",
+                        Some(Def(ModuleDef::Struct(_))) => "type",
+                        Some(Def(ModuleDef::Union(_))) => "type",
+                        Some(Def(ModuleDef::Enum(_))) => "type",
+                        Some(Def(ModuleDef::EnumVariant(_))) => "constant",
+                        Some(Def(ModuleDef::Const(_))) => "constant",
+                        Some(Def(ModuleDef::Static(_))) => "constant",
+                        Some(Def(ModuleDef::Trait(_))) => "type",
+                        Some(Def(ModuleDef::TypeAlias(_))) => "type",
+                        Some(SelfType(_)) => "type",
+                        Some(Pat(ptr)) => {
+                            binding_hash = Some({
+                                let text = ptr
+                                    .syntax_node_ptr()
+                                    .to_node(&source_file.syntax())
+                                    .text()
+                                    .to_smol_string();
+                                let shadow_count =
+                                    bindings_shadow_count.entry(text.clone()).or_default();
+                                calc_binding_hash(file_id, &text, *shadow_count)
+                            });
 
-                                "variable"
-                            }
-                            Some(SelfParam(_)) => "type",
-                            Some(GenericParam(_)) => "type",
-                            None => "text",
+                            "variable"
                         }
+                        Some(SelfParam(_)) => "type",
+                        Some(GenericParam(_)) => "type",
+                        None => "text",
                     }
                 } else {
                     "text"
@@ -152,6 +138,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
                     "text"
                 }
             }
+            TYPE_ALIAS_DEF | TYPE_ARG | TYPE_PARAM => "type",
             INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal",
             LIFETIME => "parameter",
             T![unsafe] => "keyword.unsafe",
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 0ebfd641df..dc817f2d97 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -34,7 +34,7 @@ pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> {
     let requests = world.latest_completed_requests.read();
     for (idx, r) in requests.iter().enumerate() {
         let current = if idx == world.request_idx { "*" } else { " " };
-        writeln!(buf, "{:4}{}{:<36}{}ms", r.id, current, r.method, r.duration.as_millis()).unwrap();
+        writeln!(buf, "{:4}{}{:<36}: {:?}", r.id, current, r.method, r.duration).unwrap();
     }
     Ok(buf)
 }
diff --git a/editors/emacs/ra-emacs-lsp.el b/editors/emacs/ra-emacs-lsp.el
index 84c018b66f..71bc20f17f 100644
--- a/editors/emacs/ra-emacs-lsp.el
+++ b/editors/emacs/ra-emacs-lsp.el
@@ -134,6 +134,13 @@
                             '(rust-analyzer-extend-selection))))
 
 (with-eval-after-load 'expand-region
+  ;; add the expansion for all existing rust-mode buffers. If expand-region is
+  ;; loaded lazily, it might be loaded when the first rust buffer is opened, and
+  ;; then it's too late for the hook for that buffer
+  (dolist (buf (buffer-list))
+    (with-current-buffer buf
+      (when (eq 'rust-mode major-mode)
+        (rust-analyzer--add-er-expansion))))
   (add-hook 'rust-mode-hook 'rust-analyzer--add-er-expansion))
 
 ;; runnables
@@ -170,5 +177,32 @@
                          (rust-analyzer--select-runnable))))
   (rust-analyzer-run (or runnable rust-analyzer--last-runnable)))
 
+;; analyzer status buffer
+(define-derived-mode rust-analyzer-status-mode special-mode "Rust-Analyzer-Status"
+  "Mode for the rust-analyzer status buffer.")
+
+(defvar-local rust-analyzer--status-buffer-workspace nil)
+
+(defun rust-analyzer-status ()
+  "Displays status information for rust-analyzer."
+  (interactive)
+  (let* ((workspace (lsp-find-workspace 'rust-analyzer (buffer-file-name)))
+         (buf (get-buffer-create (concat "*rust-analyzer status " (with-lsp-workspace workspace (lsp-workspace-root)) "*"))))
+    (with-current-buffer buf
+      (rust-analyzer-status-mode)
+      (setq rust-analyzer--status-buffer-workspace workspace)
+      (rust-analyzer-status-buffer-refresh))
+    (pop-to-buffer buf)))
+
+(defun rust-analyzer-status-buffer-refresh ()
+  (interactive)
+  (when rust-analyzer--status-buffer-workspace
+    (let ((inhibit-read-only t))
+      (erase-buffer)
+      (insert (with-lsp-workspace rust-analyzer--status-buffer-workspace
+                (lsp-send-request (lsp-make-request
+                                   "rust-analyzer/analyzerStatus")))))))
+
+
 (provide 'ra-emacs-lsp)
 ;;; ra-emacs-lsp.el ends here


Test patch:
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index f952a03a39..729067395f 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -227,7 +227,7 @@ impl Drop for Server {
 }
 
 fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
-    let timeout = Duration::from_secs(120);
+    let timeout = Duration::from_secs(50);
     select! {
         recv(receiver) -> msg => msg.ok(),
         recv(after(timeout)) -> _ => panic!("timed out"),