diff --git a/.gitignore b/.gitignore index 6351270..fc3d3f3 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ target **/build .mist/ + +analyzer.bat +analyzer.sh diff --git a/analyzer.bat b/analyzer.bat deleted file mode 100644 index 446d793..0000000 --- a/analyzer.bat +++ /dev/null @@ -1,9 +0,0 @@ -@echo off - -cd D:\projects\mist\mist - -mist build >nul 2>&1 - -cd mist-test - -D:\projects\mist\mist\target\debug\mist-analyzer.exe diff --git a/crates/analyzer/src/lib.rs b/crates/analyzer/src/lib.rs index 4936726..27a0050 100644 --- a/crates/analyzer/src/lib.rs +++ b/crates/analyzer/src/lib.rs @@ -1004,6 +1004,17 @@ impl LanguageServer for Backend { keyword_completion_items().filter(|item| !existing.contains(&item.label)), ); + if is_at_module_scope(&source, mist_pos.line, mist_pos.character) { + cleaned.push(CompletionItem { + label: "declaration".to_string(), + kind: Some(CompletionItemKind::SNIPPET), + insert_text: Some("$1 $2($3)\n{\n$4\n}".to_string()), + insert_text_format: Some(InsertTextFormat::SNIPPET), + sort_text: Some("1".to_string()), + ..Default::default() + }); + } + for item in &mut cleaned { if item.label.starts_with("__") { item.sort_text = Some("zzzz".to_string()); @@ -1024,6 +1035,17 @@ impl LanguageServer for Backend { keyword_completion_items().filter(|item| !existing.contains(&item.label)), ); + if is_at_module_scope(&source, mist_pos.line, mist_pos.character) { + cleaned.push(CompletionItem { + label: "declaration".to_string(), + kind: Some(CompletionItemKind::SNIPPET), + insert_text: Some("$1 $2($3)\n{\n$4\n}".to_string()), + insert_text_format: Some(InsertTextFormat::SNIPPET), + sort_text: Some("1".to_string()), + ..Default::default() + }); + } + for item in &mut cleaned { if item.label.starts_with("__") { item.sort_text = Some("zzzz".to_string()); @@ -1555,6 +1577,36 @@ fn ensure_implicit_packages_impl(docs: &mut HashMap, src_root: &P } } +/// Check if the cursor is at module scope (top-level, not inside a function +/// body, class body, or any other brace-delimited block). +fn is_at_module_scope(source: &str, line: u32, character: u32) -> bool { + let cursor_offset = match byte_offset_from_lsp(source, line, character) { + Some(offset) => offset, + None => return false, + }; + + let mut depth: i32 = 0; + let mut in_string = false; + + for c in source[..cursor_offset].chars() { + if in_string { + if c == '"' { + in_string = false; + } + continue; + } + + match c { + '{' => depth += 1, + '}' if depth > 0 => depth -= 1, + '"' => in_string = true, + _ => {} + } + } + + depth == 0 +} + fn clean_completion_item(mut item: CompletionItem) -> CompletionItem { item.text_edit = None; item.additional_text_edits = None;