+use std::fmt;
+
+use ra_syntax::AstNode;
use ra_db::{
SourceFileQuery,
salsa::{Database, debug::DebugQueryTable},
use crate::db::RootDatabase;
pub(crate) fn status(db: &RootDatabase) -> String {
- let n_parsed_files = db.query(SourceFileQuery).entries::<Vec<_>>().len();
+ let file_stats = {
+ let mut stats = FilesStats::default();
+ for entry in db.query(SourceFileQuery).entries::<Vec<_>>() {
+ stats.total += 1;
+ if let Some(value) = entry.value {
+ stats.retained += 1;
+ stats.retained_size = stats
+ .retained_size
+ .checked_add(value.syntax().memory_size_of_subtree())
+ .unwrap();
+ }
+ }
+ stats
+ };
let n_defs = {
let interner: &hir::HirInterner = db.as_ref();
interner.len()
};
- format!("#n_parsed_files {}\n#n_defs {}\n", n_parsed_files, n_defs)
+ format!("{}\nn_defs {}\n", file_stats, n_defs)
+}
+
+#[derive(Default)]
+struct FilesStats {
+ total: usize,
+ retained: usize,
+ retained_size: usize,
+}
+
+impl fmt::Display for FilesStats {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let (size, suff) = human_bytes(self.retained_size);
+ write!(
+ fmt,
+ "{} parsed_files, {} ({}{}) retained",
+ self.total, self.retained, size, suff
+ )
+ }
+}
+
+fn human_bytes(bytes: usize) -> (usize, &'static str) {
+ if bytes < 4096 {
+ return (bytes, " bytes");
+ }
+ let kb = bytes / 1024;
+ if kb < 4096 {
+ return (kb, "kb");
+ }
+ let mb = kb / 1024;
+ (mb, "mb")
}
import * as vscode from 'vscode';
import { Server } from '../server';
+const statusUri = vscode.Uri.parse('ra-lsp-status://status');
+
+export class TextDocumentContentProvider
+ implements vscode.TextDocumentContentProvider {
+ public eventEmitter = new vscode.EventEmitter<vscode.Uri>();
+ public syntaxTree: string = 'Not available';
+
+ public provideTextDocumentContent(
+ uri: vscode.Uri
+ ): vscode.ProviderResult<string> {
+ const editor = vscode.window.activeTextEditor;
+ if (editor == null) {
+ return '';
+ }
+ return Server.client.sendRequest<string>('ra/analyzerStatus', null);
+ }
+
+ get onDidChange(): vscode.Event<vscode.Uri> {
+ return this.eventEmitter.event;
+ }
+}
+
+let poller: NodeJS.Timer | null = null;
+
// Shows status of rust-analyzer (for debugging)
-export async function handle() {
- const status = await Server.client.sendRequest<string>(
- 'ra/analyzerStatus',
- null
+
+export function makeCommand(context: vscode.ExtensionContext) {
+ const textDocumentContentProvider = new TextDocumentContentProvider();
+ context.subscriptions.push(
+ vscode.workspace.registerTextDocumentContentProvider(
+ 'ra-lsp-status',
+ textDocumentContentProvider
+ )
);
- const doc = await vscode.workspace.openTextDocument({ content: status });
- await vscode.window.showTextDocument(doc, vscode.ViewColumn.Two);
+
+ context.subscriptions.push({
+ dispose() {
+ if (poller != null) {
+ clearInterval(poller);
+ }
+ }
+ });
+
+ return async function handle() {
+ if (poller == null) {
+ poller = setInterval(
+ () => textDocumentContentProvider.eventEmitter.fire(statusUri),
+ 1000
+ );
+ }
+ const document = await vscode.workspace.openTextDocument(statusUri);
+ return vscode.window.showTextDocument(
+ document,
+ vscode.ViewColumn.Two,
+ true
+ );
+ };
}
}
// Commands are requests from vscode to the language server
- registerCommand('ra-lsp.analyzerStatus', commands.analyzerStatus.handle);
+ registerCommand(
+ 'ra-lsp.analyzerStatus',
+ commands.analyzerStatus.makeCommand(context)
+ );
registerCommand('ra-lsp.syntaxTree', commands.syntaxTree.handle);
registerCommand('ra-lsp.extendSelection', commands.extendSelection.handle);
registerCommand('ra-lsp.matchingBrace', commands.matchingBrace.handle);