plum

#treesitter#compiler#wasm

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