mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
move scopes to file
This commit is contained in:
parent
846114a6e9
commit
aaca7d003b
11 changed files with 280 additions and 196 deletions
|
@ -51,6 +51,10 @@
|
|||
}
|
||||
],
|
||||
"commands": [
|
||||
{
|
||||
"command": "libsyntax-rust.createFile",
|
||||
"title": "Show Rust syntax tree"
|
||||
},
|
||||
{
|
||||
"command": "libsyntax-rust.syntaxTree",
|
||||
"title": "Show Rust syntax tree"
|
||||
|
|
|
@ -81,11 +81,21 @@ export function activate(context: vscode.ExtensionContext) {
|
|||
let e = await vscode.window.showTextDocument(doc)
|
||||
e.revealRange(range, vscode.TextEditorRevealType.InCenter)
|
||||
})
|
||||
console.log("ping")
|
||||
|
||||
registerCommand('libsyntax-rust.run', async (cmd: ProcessSpec) => {
|
||||
let task = createTask(cmd)
|
||||
await vscode.tasks.executeTask(task)
|
||||
})
|
||||
registerCommand('libsyntax-rust.createFile', async (uri_: string) => {
|
||||
console.log(`uri: ${uri_}`)
|
||||
let uri = vscode.Uri.parse(uri_)
|
||||
let edit = new vscode.WorkspaceEdit()
|
||||
edit.createFile(uri)
|
||||
await vscode.workspace.applyEdit(edit)
|
||||
let doc = await vscode.workspace.openTextDocument(uri)
|
||||
await vscode.window.showTextDocument(doc)
|
||||
console.log("Done")
|
||||
})
|
||||
|
||||
dispose(vscode.workspace.registerTextDocumentContentProvider(
|
||||
'libsyntax-rust',
|
||||
|
|
|
@ -12,12 +12,9 @@ extern crate rayon;
|
|||
mod symbol_index;
|
||||
mod module_map;
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use std::{
|
||||
fmt,
|
||||
path::{Path},
|
||||
path::{Path, PathBuf},
|
||||
sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, Ordering::SeqCst},
|
||||
|
@ -26,13 +23,16 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use once_cell::sync::OnceCell;
|
||||
use rayon::prelude::*;
|
||||
|
||||
use libsyntax2::{
|
||||
File,
|
||||
TextUnit, TextRange, SmolStr,
|
||||
ast::{self, AstNode, NameOwner},
|
||||
SyntaxKind::*,
|
||||
};
|
||||
use libeditor::{LineIndex, FileSymbol, find_node_at_offset};
|
||||
use libeditor::{Diagnostic, LineIndex, FileSymbol, find_node_at_offset};
|
||||
|
||||
use self::{
|
||||
symbol_index::FileSymbols,
|
||||
|
@ -130,6 +130,9 @@ impl WorldState {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum QuickFix {
|
||||
CreateFile(PathBuf),
|
||||
}
|
||||
|
||||
impl World {
|
||||
pub fn file_syntax(&self, file_id: FileId) -> Result<File> {
|
||||
|
@ -210,6 +213,29 @@ impl World {
|
|||
Ok(vec![])
|
||||
}
|
||||
|
||||
pub fn diagnostics(&self, file_id: FileId) -> Result<Vec<(Diagnostic, Option<QuickFix>)>> {
|
||||
let syntax = self.file_syntax(file_id)?;
|
||||
let mut res = libeditor::diagnostics(&syntax)
|
||||
.into_iter()
|
||||
.map(|d| (d, None))
|
||||
.collect::<Vec<_>>();
|
||||
for module in syntax.ast().modules() {
|
||||
if module.has_semi() && self.resolve_module(file_id, module).is_empty() {
|
||||
if let Some(name) = module.name() {
|
||||
let d = Diagnostic {
|
||||
range: name.syntax().range(),
|
||||
msg: "unresolved module".to_string(),
|
||||
};
|
||||
let quick_fix = self.data.module_map.suggested_child_mod_path(module)
|
||||
.map(QuickFix::CreateFile);
|
||||
|
||||
res.push((d, quick_fix))
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
fn index_resolve(&self, name_ref: ast::NameRef) -> Vec<(FileId, FileSymbol)> {
|
||||
let name = name_ref.text();
|
||||
let mut query = Query::new(name.to_string());
|
||||
|
|
|
@ -93,6 +93,11 @@ impl ModuleMap {
|
|||
res
|
||||
}
|
||||
|
||||
pub fn suggested_child_mod_path(&self, m: ast::Module) -> Option<PathBuf> {
|
||||
let name = m.name()?;
|
||||
Some(PathBuf::from(format!("../{}.rs", name.text())))
|
||||
}
|
||||
|
||||
fn links(
|
||||
&self,
|
||||
file_resolver: &FileResolver,
|
||||
|
|
|
@ -44,6 +44,19 @@ fn test_resolve_module() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unresolved_module_diagnostic() {
|
||||
let mut world = WorldState::new();
|
||||
world.change_file(FileId(1), Some("mod foo;".to_string()));
|
||||
|
||||
let snap = world.snapshot(|_id, _path| None);
|
||||
let diagnostics = snap.diagnostics(FileId(1)).unwrap();
|
||||
assert_eq_dbg(
|
||||
r#"[Diagnostic { range: [4; 7), msg: "unresolved module" }]"#,
|
||||
&diagnostics,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_resolve_parent_module() {
|
||||
let mut world = WorldState::new();
|
||||
|
|
0
crates/libeditor/scope.rs
Normal file
0
crates/libeditor/scope.rs
Normal file
|
@ -1,20 +1,14 @@
|
|||
use std::{
|
||||
fmt,
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use libsyntax2::{
|
||||
File, TextUnit, AstNode, SyntaxNodeRef, SyntaxNode, SmolStr,
|
||||
ast::{self, NameOwner},
|
||||
File, TextUnit, AstNode,
|
||||
ast::self,
|
||||
algo::{
|
||||
ancestors,
|
||||
walk::preorder,
|
||||
generate,
|
||||
},
|
||||
};
|
||||
|
||||
use {
|
||||
AtomEdit, find_node_at_offset,
|
||||
scope::{FnScopes, compute_scopes},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -43,178 +37,3 @@ fn complete(name_ref: ast::NameRef, scopes: &FnScopes) -> Vec<CompletionItem> {
|
|||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn compute_scopes(fn_def: ast::FnDef) -> FnScopes {
|
||||
let mut scopes = FnScopes::new();
|
||||
let root = scopes.root_scope();
|
||||
fn_def.param_list().into_iter()
|
||||
.flat_map(|it| it.params())
|
||||
.filter_map(|it| it.pat())
|
||||
.for_each(|it| scopes.add_bindings(root, it));
|
||||
|
||||
if let Some(body) = fn_def.body() {
|
||||
compute_block_scopes(body, &mut scopes, root)
|
||||
}
|
||||
scopes
|
||||
}
|
||||
|
||||
fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
|
||||
for stmt in block.statements() {
|
||||
match stmt {
|
||||
ast::Stmt::LetStmt(stmt) => {
|
||||
scope = scopes.new_scope(scope);
|
||||
if let Some(pat) = stmt.pat() {
|
||||
scopes.add_bindings(scope, pat);
|
||||
}
|
||||
if let Some(expr) = stmt.initializer() {
|
||||
scopes.set_scope(expr.syntax(), scope)
|
||||
}
|
||||
}
|
||||
ast::Stmt::ExprStmt(expr_stmt) => {
|
||||
if let Some(expr) = expr_stmt.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(expr) = block.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
|
||||
match expr {
|
||||
ast::Expr::IfExpr(e) => {
|
||||
let cond_scope = e.condition().and_then(|cond| {
|
||||
compute_cond_scopes(cond, scopes, scope)
|
||||
});
|
||||
if let Some(block) = e.then_branch() {
|
||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
||||
}
|
||||
if let Some(block) = e.else_branch() {
|
||||
compute_block_scopes(block, scopes, scope);
|
||||
}
|
||||
},
|
||||
ast::Expr::WhileExpr(e) => {
|
||||
let cond_scope = e.condition().and_then(|cond| {
|
||||
compute_cond_scopes(cond, scopes, scope)
|
||||
});
|
||||
if let Some(block) = e.body() {
|
||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
||||
}
|
||||
},
|
||||
ast::Expr::BlockExpr(e) => {
|
||||
if let Some(block) = e.block() {
|
||||
compute_block_scopes(block, scopes, scope);
|
||||
}
|
||||
}
|
||||
// ForExpr(e) => TODO,
|
||||
_ => {
|
||||
expr.syntax().children()
|
||||
.filter_map(ast::Expr::cast)
|
||||
.for_each(|expr| compute_expr_scopes(expr, scopes, scope))
|
||||
}
|
||||
};
|
||||
|
||||
fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
|
||||
if let Some(expr) = cond.expr() {
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
if let Some(pat) = cond.pat() {
|
||||
let s = scopes.new_scope(scope);
|
||||
scopes.add_bindings(s, pat);
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ScopeId = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FnScopes {
|
||||
scopes: Vec<ScopeData>,
|
||||
scope_for: HashMap<SyntaxNode, ScopeId>,
|
||||
}
|
||||
|
||||
impl FnScopes {
|
||||
fn new() -> FnScopes {
|
||||
FnScopes {
|
||||
scopes: vec![],
|
||||
scope_for: HashMap::new(),
|
||||
}
|
||||
}
|
||||
fn root_scope(&mut self) -> ScopeId {
|
||||
let res = self.scopes.len();
|
||||
self.scopes.push(ScopeData { parent: None, entries: vec![] });
|
||||
res
|
||||
}
|
||||
fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
|
||||
let res = self.scopes.len();
|
||||
self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
|
||||
res
|
||||
}
|
||||
fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
|
||||
let entries = preorder(pat.syntax())
|
||||
.filter_map(ast::BindPat::cast)
|
||||
.filter_map(ScopeEntry::new);
|
||||
self.scopes[scope].entries.extend(entries);
|
||||
}
|
||||
fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
|
||||
self.scope_for.insert(node.owned(), scope);
|
||||
}
|
||||
fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
|
||||
&self.scopes[scope].entries
|
||||
}
|
||||
fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
|
||||
ancestors(node)
|
||||
.filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
|
||||
.next()
|
||||
}
|
||||
fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
|
||||
generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ScopeData {
|
||||
parent: Option<ScopeId>,
|
||||
entries: Vec<ScopeEntry>
|
||||
}
|
||||
|
||||
struct ScopeEntry {
|
||||
syntax: SyntaxNode
|
||||
}
|
||||
|
||||
impl ScopeEntry {
|
||||
fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
|
||||
if pat.name().is_some() {
|
||||
Some(ScopeEntry { syntax: pat.syntax().owned() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> SmolStr {
|
||||
self.ast().name()
|
||||
.unwrap()
|
||||
.text()
|
||||
}
|
||||
|
||||
fn ast(&self) -> ast::BindPat {
|
||||
ast::BindPat::cast(self.syntax.borrowed())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScopeEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("ScopeEntry")
|
||||
.field("name", &self.name())
|
||||
.field("syntax", &self.syntax)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ mod edit;
|
|||
mod code_actions;
|
||||
mod typing;
|
||||
mod completion;
|
||||
mod scope;
|
||||
|
||||
use libsyntax2::{
|
||||
File, TextUnit, TextRange, SyntaxNodeRef,
|
||||
|
|
183
crates/libeditor/src/scope.rs
Normal file
183
crates/libeditor/src/scope.rs
Normal file
|
@ -0,0 +1,183 @@
|
|||
use std::{
|
||||
fmt,
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use libsyntax2::{
|
||||
SyntaxNodeRef, SyntaxNode, SmolStr, AstNode,
|
||||
ast::{self, NameOwner},
|
||||
algo::{ancestors, generate, walk::preorder}
|
||||
};
|
||||
|
||||
pub fn compute_scopes(fn_def: ast::FnDef) -> FnScopes {
|
||||
let mut scopes = FnScopes::new();
|
||||
let root = scopes.root_scope();
|
||||
fn_def.param_list().into_iter()
|
||||
.flat_map(|it| it.params())
|
||||
.filter_map(|it| it.pat())
|
||||
.for_each(|it| scopes.add_bindings(root, it));
|
||||
|
||||
if let Some(body) = fn_def.body() {
|
||||
compute_block_scopes(body, &mut scopes, root)
|
||||
}
|
||||
scopes
|
||||
}
|
||||
|
||||
fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
|
||||
for stmt in block.statements() {
|
||||
match stmt {
|
||||
ast::Stmt::LetStmt(stmt) => {
|
||||
scope = scopes.new_scope(scope);
|
||||
if let Some(pat) = stmt.pat() {
|
||||
scopes.add_bindings(scope, pat);
|
||||
}
|
||||
if let Some(expr) = stmt.initializer() {
|
||||
scopes.set_scope(expr.syntax(), scope)
|
||||
}
|
||||
}
|
||||
ast::Stmt::ExprStmt(expr_stmt) => {
|
||||
if let Some(expr) = expr_stmt.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(expr) = block.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
|
||||
match expr {
|
||||
ast::Expr::IfExpr(e) => {
|
||||
let cond_scope = e.condition().and_then(|cond| {
|
||||
compute_cond_scopes(cond, scopes, scope)
|
||||
});
|
||||
if let Some(block) = e.then_branch() {
|
||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
||||
}
|
||||
if let Some(block) = e.else_branch() {
|
||||
compute_block_scopes(block, scopes, scope);
|
||||
}
|
||||
},
|
||||
ast::Expr::WhileExpr(e) => {
|
||||
let cond_scope = e.condition().and_then(|cond| {
|
||||
compute_cond_scopes(cond, scopes, scope)
|
||||
});
|
||||
if let Some(block) = e.body() {
|
||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
||||
}
|
||||
},
|
||||
ast::Expr::BlockExpr(e) => {
|
||||
if let Some(block) = e.block() {
|
||||
compute_block_scopes(block, scopes, scope);
|
||||
}
|
||||
}
|
||||
// ForExpr(e) => TODO,
|
||||
_ => {
|
||||
expr.syntax().children()
|
||||
.filter_map(ast::Expr::cast)
|
||||
.for_each(|expr| compute_expr_scopes(expr, scopes, scope))
|
||||
}
|
||||
};
|
||||
|
||||
fn compute_cond_scopes(cond: ast::Condition, scopes: &mut FnScopes, scope: ScopeId) -> Option<ScopeId> {
|
||||
if let Some(expr) = cond.expr() {
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
if let Some(pat) = cond.pat() {
|
||||
let s = scopes.new_scope(scope);
|
||||
scopes.add_bindings(s, pat);
|
||||
Some(s)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type ScopeId = usize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FnScopes {
|
||||
scopes: Vec<ScopeData>,
|
||||
scope_for: HashMap<SyntaxNode, ScopeId>,
|
||||
}
|
||||
|
||||
impl FnScopes {
|
||||
fn new() -> FnScopes {
|
||||
FnScopes {
|
||||
scopes: vec![],
|
||||
scope_for: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
|
||||
&self.scopes[scope].entries
|
||||
}
|
||||
pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item=ScopeId> + 'a {
|
||||
generate(self.scope_for(node), move |&scope| self.scopes[scope].parent)
|
||||
}
|
||||
fn root_scope(&mut self) -> ScopeId {
|
||||
let res = self.scopes.len();
|
||||
self.scopes.push(ScopeData { parent: None, entries: vec![] });
|
||||
res
|
||||
}
|
||||
fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
|
||||
let res = self.scopes.len();
|
||||
self.scopes.push(ScopeData { parent: Some(parent), entries: vec![] });
|
||||
res
|
||||
}
|
||||
fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
|
||||
let entries = preorder(pat.syntax())
|
||||
.filter_map(ast::BindPat::cast)
|
||||
.filter_map(ScopeEntry::new);
|
||||
self.scopes[scope].entries.extend(entries);
|
||||
}
|
||||
fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
|
||||
self.scope_for.insert(node.owned(), scope);
|
||||
}
|
||||
fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
|
||||
ancestors(node)
|
||||
.filter_map(|it| self.scope_for.get(&it.owned()).map(|&scope| scope))
|
||||
.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ScopeData {
|
||||
parent: Option<ScopeId>,
|
||||
entries: Vec<ScopeEntry>
|
||||
}
|
||||
|
||||
pub struct ScopeEntry {
|
||||
syntax: SyntaxNode
|
||||
}
|
||||
|
||||
impl ScopeEntry {
|
||||
fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
|
||||
if pat.name().is_some() {
|
||||
Some(ScopeEntry { syntax: pat.syntax().owned() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
pub fn name(&self) -> SmolStr {
|
||||
self.ast().name()
|
||||
.unwrap()
|
||||
.text()
|
||||
}
|
||||
fn ast(&self) -> ast::BindPat {
|
||||
ast::BindPat::cast(self.syntax.borrowed())
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScopeEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("ScopeEntry")
|
||||
.field("name", &self.name())
|
||||
.field("syntax", &self.syntax)
|
||||
.finish()
|
||||
}
|
||||
}
|
|
@ -29,8 +29,8 @@ pub(crate) fn literal(p: &mut Parser) -> Option<CompletedMarker> {
|
|||
pub(super) const ATOM_EXPR_FIRST: TokenSet =
|
||||
token_set_union![
|
||||
LITERAL_FIRST,
|
||||
token_set![L_PAREN, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW, L_CURLY, RETURN_KW,
|
||||
IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
|
||||
token_set![L_CURLY, L_PAREN, L_BRACK, PIPE, MOVE_KW, IF_KW, WHILE_KW, MATCH_KW, UNSAFE_KW,
|
||||
RETURN_KW, IDENT, SELF_KW, SUPER_KW, COLONCOLON, BREAK_KW, CONTINUE_KW, LIFETIME ],
|
||||
];
|
||||
|
||||
pub(super) fn atom_expr(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
|
||||
|
|
|
@ -7,7 +7,7 @@ use languageserver_types::{
|
|||
CompletionItem,
|
||||
};
|
||||
use serde_json::{to_value, from_value};
|
||||
use libanalysis::{Query};
|
||||
use libanalysis::{Query, QuickFix};
|
||||
use libeditor;
|
||||
use libsyntax2::{
|
||||
TextUnit,
|
||||
|
@ -177,6 +177,30 @@ pub fn handle_code_action(
|
|||
};
|
||||
res.push(cmd);
|
||||
}
|
||||
|
||||
for (diag, quick_fix) in world.analysis().diagnostics(file_id)? {
|
||||
let quick_fix = match quick_fix {
|
||||
Some(quick_fix) => quick_fix,
|
||||
None => continue,
|
||||
};
|
||||
if !contains_offset_nonstrict(diag.range, offset) {
|
||||
continue;
|
||||
}
|
||||
let cmd = match quick_fix {
|
||||
QuickFix::CreateFile(path) => {
|
||||
let path = &path.to_str().unwrap()[3..]; // strip `../` b/c url is weird
|
||||
let uri = params.text_document.uri.join(path)
|
||||
.unwrap();
|
||||
let uri = ::url_serde::Ser::new(&uri);
|
||||
Command {
|
||||
title: "Create file".to_string(),
|
||||
command: "libsyntax-rust.createFile".to_string(),
|
||||
arguments: Some(vec![to_value(uri).unwrap()]),
|
||||
}
|
||||
}
|
||||
};
|
||||
res.push(cmd)
|
||||
}
|
||||
return Ok(Some(res));
|
||||
}
|
||||
|
||||
|
@ -355,11 +379,10 @@ pub fn publish_diagnostics(
|
|||
uri: Url
|
||||
) -> Result<req::PublishDiagnosticsParams> {
|
||||
let file_id = world.uri_to_file_id(&uri)?;
|
||||
let file = world.analysis().file_syntax(file_id)?;
|
||||
let line_index = world.analysis().file_line_index(file_id)?;
|
||||
let diagnostics = libeditor::diagnostics(&file)
|
||||
let diagnostics = world.analysis().diagnostics(file_id)?
|
||||
.into_iter()
|
||||
.map(|d| Diagnostic {
|
||||
.map(|(d, _quick_fix)| Diagnostic {
|
||||
range: d.range.conv_with(&line_index),
|
||||
severity: Some(DiagnosticSeverity::Error),
|
||||
code: None,
|
||||
|
|
Loading…
Reference in a new issue