plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
f392348
— Peter John
2026-11-02T11:57:28+05:30
tooling: LSP offers and auto-imports std namespaces; queries cover struct/record/match
plum-lsp/src/completion.rs
CHANGED
|
@@ -90,6 +90,20 @@ pub fn topLevelItems(source: &ast::Source) -> Vec<CompletionItem> {
|
|
|
90
90
|
ast::Item::Test(_) => {}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
// `primitive` blocks: a namespace of statics (`Os`, `Base64`, `Math`) or a
|
|
94
|
+
// built-in type's API (`Int`, `Array`), both reached as `Name.f()`.
|
|
95
|
+
for p in &source.primitives {
|
|
96
|
+
if items.iter().any(|i| i.label == p.name) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
let namespace = p.selfFn.is_none();
|
|
100
|
+
items.push(CompletionItem {
|
|
101
|
+
label: p.name.clone(),
|
|
102
|
+
kind: Some(if namespace { CompletionItemKind::MODULE } else { CompletionItemKind::CLASS }),
|
|
103
|
+
detail: Some(if namespace { "namespace" } else { "primitive" }.to_string()),
|
|
104
|
+
..Default::default()
|
|
105
|
+
});
|
|
106
|
+
}
|
|
93
107
|
items
|
|
94
108
|
}
|
|
95
109
|
|
|
@@ -439,6 +453,10 @@ pub fn stdLibIndex(lib_path: &Path) -> HashMap<String, String> {
|
|
|
439
453
|
map.entry(name).or_insert_with(|| import_path.clone());
|
|
440
454
|
}
|
|
441
455
|
}
|
|
456
|
+
// `primitive` namespaces and built-in APIs (`Os`, `Base64`, `Int`).
|
|
457
|
+
for p in &source.primitives {
|
|
458
|
+
map.entry(p.name.clone()).or_insert_with(|| import_path.clone());
|
|
459
|
+
}
|
|
442
460
|
}
|
|
443
461
|
map
|
|
444
462
|
}
|
plum-lsp/src/main.rs
CHANGED
|
@@ -495,6 +495,32 @@ mod tests {
|
|
|
495
495
|
let _ = std::fs::remove_dir_all(&dir);
|
|
496
496
|
}
|
|
497
497
|
|
|
498
|
+
/// The std namespaces (`Os`, `Base64`, `Testing`, `Http`) are offered at the
|
|
499
|
+
/// top level, indexed for auto-import, and complete their statics after `Name.`.
|
|
500
|
+
#[test]
|
|
501
|
+
fn stdNamespacesCompleteAndAutoImport() {
|
|
502
|
+
let index = completion::stdLibIndex(&repoRoot());
|
|
503
|
+
for (name, path) in [("Os", "std/Os"), ("Base64", "std/Base64"), ("Testing", "std/Testing"), ("Http", "std/Http"), ("Int", "std/Int")] {
|
|
504
|
+
assert_eq!(index.get(name).map(String::as_str), Some(path), "{name}");
|
|
505
|
+
}
|
|
506
|
+
let dir = std::env::temp_dir().join(format!("plum-lsp-ns-{}", std::process::id()));
|
|
507
|
+
std::fs::create_dir_all(&dir).unwrap();
|
|
508
|
+
let path = dir.join("t.plum");
|
|
509
|
+
let text = "module t\nimport std/Int\nimport std/Str\nimport std/Os\nimport std/Base64\n\nfun main() =\n x := Os.zzzzzz\n";
|
|
510
|
+
std::fs::write(&path, text).unwrap();
|
|
511
|
+
let labels = |recv: &str| -> Vec<String> {
|
|
512
|
+
memberCompletionFor(&path, &repoRoot(), text, 7, recv).into_iter().map(|i| i.label).collect()
|
|
513
|
+
};
|
|
514
|
+
let os = labels("Os");
|
|
515
|
+
assert!(os.iter().any(|l| l == "readFile") && os.iter().any(|l| l == "writeFile"), "{os:?}");
|
|
516
|
+
let b64 = labels("Base64");
|
|
517
|
+
assert!(b64.iter().any(|l| l == "encode") && b64.iter().any(|l| l == "decode"), "{b64:?}");
|
|
518
|
+
let merged = plum_core::loadAndMerge(&path, &repoRoot()).expect("loads");
|
|
519
|
+
let top: Vec<String> = completion::topLevelItems(&merged).into_iter().map(|i| i.label).collect();
|
|
520
|
+
assert!(top.iter().any(|l| l == "Os") && top.iter().any(|l| l == "Base64"), "{top:?}");
|
|
521
|
+
let _ = std::fs::remove_dir_all(&dir);
|
|
522
|
+
}
|
|
523
|
+
|
|
498
524
|
#[test]
|
|
499
525
|
fn keywordsCurrent() {
|
|
500
526
|
let labels: Vec<String> = completion::keywordItems().into_iter().map(|i| i.label).collect();
|
plum-tooling/tree-sitter-plum/queries/plum/indents.scm
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
[
|
|
2
2
|
(enum)
|
|
3
|
+
(struct)
|
|
4
|
+
(record)
|
|
3
5
|
(primitive)
|
|
4
6
|
(fn)
|
|
5
7
|
(for)
|
|
@@ -7,6 +9,8 @@
|
|
|
7
9
|
(if)
|
|
8
10
|
(else)
|
|
9
11
|
(else_if)
|
|
12
|
+
(match)
|
|
13
|
+
(case)
|
|
10
14
|
(body)
|
|
11
15
|
] @indent
|
|
12
16
|
|
|
@@ -16,7 +20,10 @@
|
|
|
16
20
|
(while)
|
|
17
21
|
(fn)
|
|
18
22
|
(enum)
|
|
23
|
+
(struct)
|
|
24
|
+
(record)
|
|
19
25
|
(primitive)
|
|
26
|
+
(match)
|
|
20
27
|
] @extend
|
|
21
28
|
|
|
22
29
|
[
|
plum-tooling/tree-sitter-plum/queries/plum/tags.scm
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
(enum
|
|
2
2
|
name: (type_identifier) @name) @definition.class
|
|
3
3
|
|
|
4
|
+
(struct
|
|
5
|
+
name: (type_identifier) @name) @definition.class
|
|
6
|
+
|
|
7
|
+
(record
|
|
8
|
+
name: (type_identifier) @name) @definition.class
|
|
9
|
+
|
|
4
10
|
(fn
|
|
5
11
|
name: (fn_identifier) @name) @definition.function
|
|
6
12
|
|
plum-tooling/tree-sitter-plum/queries/plum/textobjects.scm
CHANGED
|
@@ -11,3 +11,7 @@
|
|
|
11
11
|
(comment) @comment.around
|
|
12
12
|
|
|
13
13
|
(primitive) @class.around
|
|
14
|
+
|
|
15
|
+
(struct) @class.around
|
|
16
|
+
|
|
17
|
+
(record) @class.around
|