@tishlang/tish 1.9.2 → 1.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/bin/tish +0 -0
  2. package/crates/js_to_tish/src/transform/expr.rs +8 -6
  3. package/crates/js_to_tish/src/transform/stmt.rs +12 -13
  4. package/crates/tish/Cargo.toml +1 -1
  5. package/crates/tish/src/cargo_native_registry.rs +4 -1
  6. package/crates/tish/src/main.rs +11 -8
  7. package/crates/tish/tests/integration_test.rs +145 -7
  8. package/crates/tish_ast/src/ast.rs +3 -9
  9. package/crates/tish_build_utils/src/lib.rs +43 -15
  10. package/crates/tish_builtins/src/array.rs +2 -3
  11. package/crates/tish_builtins/src/construct.rs +15 -28
  12. package/crates/tish_builtins/src/globals.rs +18 -16
  13. package/crates/tish_builtins/src/helpers.rs +1 -4
  14. package/crates/tish_builtins/src/lib.rs +1 -0
  15. package/crates/tish_builtins/src/object.rs +10 -10
  16. package/crates/tish_builtins/src/string.rs +1 -3
  17. package/crates/tish_builtins/src/symbol.rs +83 -0
  18. package/crates/tish_compile/src/codegen.rs +123 -138
  19. package/crates/tish_compile/src/lib.rs +25 -3
  20. package/crates/tish_compile/src/resolve.rs +6 -3
  21. package/crates/tish_compile/src/types.rs +6 -6
  22. package/crates/tish_compile_js/src/codegen.rs +8 -5
  23. package/crates/tish_core/src/console_style.rs +9 -0
  24. package/crates/tish_core/src/json.rs +17 -7
  25. package/crates/tish_core/src/macros.rs +2 -2
  26. package/crates/tish_core/src/value.rs +192 -4
  27. package/crates/tish_cranelift_runtime/Cargo.toml +4 -0
  28. package/crates/tish_eval/src/eval.rs +135 -73
  29. package/crates/tish_eval/src/http.rs +18 -12
  30. package/crates/tish_eval/src/lib.rs +29 -0
  31. package/crates/tish_eval/src/regex.rs +1 -1
  32. package/crates/tish_eval/src/value.rs +89 -4
  33. package/crates/tish_eval/src/value_convert.rs +30 -8
  34. package/crates/tish_fmt/src/lib.rs +4 -1
  35. package/crates/tish_lexer/src/lib.rs +7 -2
  36. package/crates/tish_llvm/src/lib.rs +2 -2
  37. package/crates/tish_lsp/src/builtin_goto.rs +111 -10
  38. package/crates/tish_lsp/src/import_goto.rs +35 -22
  39. package/crates/tish_lsp/src/main.rs +118 -85
  40. package/crates/tish_native/src/build.rs +187 -10
  41. package/crates/tish_native/src/lib.rs +92 -8
  42. package/crates/tish_parser/src/lib.rs +5 -2
  43. package/crates/tish_parser/src/parser.rs +45 -75
  44. package/crates/tish_pg/src/error.rs +1 -1
  45. package/crates/tish_pg/src/lib.rs +61 -73
  46. package/crates/tish_resolve/src/lib.rs +283 -158
  47. package/crates/tish_resolve/src/pos.rs +10 -2
  48. package/crates/tish_runtime/Cargo.toml +3 -0
  49. package/crates/tish_runtime/src/http.rs +39 -39
  50. package/crates/tish_runtime/src/http_fetch.rs +12 -12
  51. package/crates/tish_runtime/src/lib.rs +26 -43
  52. package/crates/tish_runtime/src/native_promise.rs +0 -11
  53. package/crates/tish_runtime/src/promise.rs +14 -1
  54. package/crates/tish_runtime/src/promise_io.rs +1 -4
  55. package/crates/tish_runtime/src/ws.rs +40 -27
  56. package/crates/tish_runtime/tests/fetch_readable_stream.rs +10 -8
  57. package/crates/tish_ui/src/jsx.rs +6 -4
  58. package/crates/tish_ui/src/lib.rs +2 -2
  59. package/crates/tish_ui/src/runtime/hooks.rs +5 -15
  60. package/crates/tish_ui/src/runtime/mod.rs +16 -17
  61. package/crates/tish_vm/Cargo.toml +2 -0
  62. package/crates/tish_vm/src/vm.rs +218 -153
  63. package/crates/tish_wasm/src/lib.rs +33 -7
  64. package/crates/tish_wasm_runtime/Cargo.toml +4 -1
  65. package/crates/tish_wasm_runtime/src/lib.rs +2 -1
  66. package/crates/tishlang_cargo_bindgen/src/classify.rs +1 -3
  67. package/crates/tishlang_cargo_bindgen/src/discover.rs +10 -5
  68. package/crates/tishlang_cargo_bindgen/src/infer.rs +18 -8
  69. package/crates/tishlang_cargo_bindgen/src/lib.rs +25 -26
  70. package/crates/tishlang_cargo_bindgen/src/main.rs +41 -38
  71. package/crates/tishlang_cargo_bindgen/src/metadata.rs +4 -1
  72. package/justfile +3 -3
  73. package/package.json +1 -1
  74. package/platform/darwin-arm64/tish +0 -0
  75. package/platform/darwin-x64/tish +0 -0
  76. package/platform/linux-arm64/tish +0 -0
  77. package/platform/linux-x64/tish +0 -0
  78. package/platform/win32-x64/tish.exe +0 -0
@@ -12,9 +12,83 @@ use std::sync::Arc;
12
12
  use ahash::AHashMap;
13
13
  use tishlang_ast::{FunParam, Statement};
14
14
  use tishlang_core::NativeFn as CoreNativeFn;
15
+ use tishlang_core::TishSymbol;
15
16
 
16
- /// Property map for interpreter `Value::Object` (uses `eval::Value`, not `tishlang_core::Value`).
17
+ /// Property map for interpreter object string keys (uses `eval::Value`, not `tishlang_core::Value`).
17
18
  pub type PropMap = AHashMap<Arc<str>, Value>;
19
+
20
+ /// Interpreter object: string keys plus optional symbol-keyed properties.
21
+ #[derive(Clone, Debug, Default)]
22
+ pub struct EvalObjectData {
23
+ pub strings: PropMap,
24
+ pub symbols: Option<AHashMap<u64, Value>>,
25
+ }
26
+
27
+ impl EvalObjectData {
28
+ pub fn from_strings(strings: PropMap) -> Self {
29
+ Self {
30
+ strings,
31
+ symbols: None,
32
+ }
33
+ }
34
+ }
35
+
36
+ pub fn eval_object_get(obj: &Value, key: &Value) -> Option<Value> {
37
+ let Value::Object(od) = obj else {
38
+ return None;
39
+ };
40
+ let b = od.borrow();
41
+ match key {
42
+ Value::Symbol(s) => b.symbols.as_ref()?.get(&s.id).cloned(),
43
+ Value::Number(n) => {
44
+ let k: Arc<str> = n.to_string().into();
45
+ b.strings.get(&k).cloned()
46
+ }
47
+ Value::String(k) => b.strings.get(k.as_ref()).cloned(),
48
+ _ => None,
49
+ }
50
+ }
51
+
52
+ pub fn eval_object_set(obj: &Value, key: &Value, val: Value) -> Result<(), String> {
53
+ let Value::Object(od) = obj else {
54
+ return Err("Cannot set property on non-object".to_string());
55
+ };
56
+ let mut b = od.borrow_mut();
57
+ match key {
58
+ Value::Symbol(s) => {
59
+ if b.symbols.is_none() {
60
+ b.symbols = Some(AHashMap::default());
61
+ }
62
+ b.symbols.as_mut().unwrap().insert(s.id, val);
63
+ Ok(())
64
+ }
65
+ Value::Number(n) => {
66
+ b.strings.insert(n.to_string().into(), val);
67
+ Ok(())
68
+ }
69
+ Value::String(k) => {
70
+ b.strings.insert(Arc::clone(k), val);
71
+ Ok(())
72
+ }
73
+ _ => Err("Object key must be string, number, or symbol".to_string()),
74
+ }
75
+ }
76
+
77
+ pub fn eval_object_has(obj: &Value, key: &Value) -> bool {
78
+ let Value::Object(od) = obj else {
79
+ return false;
80
+ };
81
+ let b = od.borrow();
82
+ match key {
83
+ Value::Symbol(s) => b.symbols.as_ref().is_some_and(|m| m.contains_key(&s.id)),
84
+ Value::Number(n) => {
85
+ let k: Arc<str> = n.to_string().into();
86
+ b.strings.contains_key(&k)
87
+ }
88
+ Value::String(k) => b.strings.contains_key(k.as_ref()),
89
+ _ => false,
90
+ }
91
+ }
18
92
  use tishlang_core::TishOpaque;
19
93
  #[cfg(feature = "http")]
20
94
  use tishlang_core::TishPromise;
@@ -34,7 +108,8 @@ pub enum Value {
34
108
  Bool(bool),
35
109
  Null,
36
110
  Array(Rc<RefCell<Vec<Value>>>),
37
- Object(Rc<RefCell<PropMap>>),
111
+ Object(Rc<RefCell<EvalObjectData>>),
112
+ Symbol(Arc<TishSymbol>),
38
113
  /// User-defined function with AST body
39
114
  Function {
40
115
  formals: Arc<[FunParam]>,
@@ -109,6 +184,7 @@ impl std::fmt::Debug for Value {
109
184
  Value::CoreFn(_) => write!(f, "CoreFn"),
110
185
  Value::Opaque(o) => write!(f, "{}(opaque)", o.type_name()),
111
186
  Value::OpaqueMethod(_, _) => write!(f, "[Function]"),
187
+ Value::Symbol(s) => write!(f, "Symbol({})", s.id),
112
188
  }
113
189
  }
114
190
  }
@@ -137,11 +213,19 @@ impl std::fmt::Display for Value {
137
213
  Value::Object(obj) => {
138
214
  let inner: Vec<String> = obj
139
215
  .borrow()
216
+ .strings
140
217
  .iter()
141
218
  .map(|(k, v)| format!("{}: {}", k.as_ref(), v))
142
219
  .collect();
143
220
  write!(f, "{{{}}}", inner.join(", "))
144
221
  }
222
+ Value::Symbol(s) => {
223
+ if let Some(d) = &s.description {
224
+ write!(f, "Symbol({})", d)
225
+ } else {
226
+ write!(f, "Symbol()")
227
+ }
228
+ }
145
229
  Value::Function { .. } => write!(f, "[Function]"),
146
230
  Value::Native(_) => write!(f, "[NativeFunction]"),
147
231
  #[cfg(feature = "http")]
@@ -195,6 +279,7 @@ impl Value {
195
279
  (Value::Null, Value::Null) => true,
196
280
  (Value::Array(a), Value::Array(b)) => Rc::ptr_eq(a, b),
197
281
  (Value::Object(a), Value::Object(b)) => Rc::ptr_eq(a, b),
282
+ (Value::Symbol(a), Value::Symbol(b)) => Arc::ptr_eq(a, b),
198
283
  (Value::Opaque(a), Value::Opaque(b)) => Arc::ptr_eq(a, b),
199
284
  (Value::OpaqueMethod(a, ak), Value::OpaqueMethod(b, bk)) => {
200
285
  Arc::ptr_eq(a, b) && ak == bk
@@ -210,7 +295,7 @@ impl Value {
210
295
 
211
296
  /// Create a new object Value from a property map.
212
297
  pub fn object(map: PropMap) -> Self {
213
- Value::Object(Rc::new(RefCell::new(map)))
298
+ Value::Object(Rc::new(RefCell::new(EvalObjectData::from_strings(map))))
214
299
  }
215
300
 
216
301
  /// Create an empty array Value.
@@ -220,7 +305,7 @@ impl Value {
220
305
 
221
306
  /// Create an empty object Value.
222
307
  pub fn empty_object() -> Self {
223
- Value::Object(Rc::new(RefCell::new(PropMap::default())))
308
+ Value::Object(Rc::new(RefCell::new(EvalObjectData::default())))
224
309
  }
225
310
 
226
311
  /// Extract the number value, if this is a Number.
@@ -4,11 +4,12 @@ use std::cell::RefCell;
4
4
  use std::rc::Rc;
5
5
  use std::sync::Arc;
6
6
 
7
- use tishlang_core::{ObjectMap, Value as CoreValue, VmRef};
8
7
  #[cfg(feature = "regex")]
9
8
  use tishlang_core::TishRegExp;
9
+ use ahash::AHashMap;
10
+ use tishlang_core::{ObjectData, ObjectMap, Value as CoreValue, VmRef};
10
11
 
11
- use crate::value::{PropMap, Value};
12
+ use crate::value::{EvalObjectData, PropMap, Value};
12
13
 
13
14
  /// Convert interpreter Value to core Value. Fails for interpreter-only variants.
14
15
  pub fn eval_to_core(v: &Value) -> Result<CoreValue, String> {
@@ -25,12 +26,23 @@ pub fn eval_to_core(v: &Value) -> Result<CoreValue, String> {
25
26
  Ok(CoreValue::Array(VmRef::new(out)))
26
27
  }
27
28
  Value::Object(map) => {
28
- let mut out = ObjectMap::default();
29
- for (k, v) in map.borrow().iter() {
30
- out.insert(Arc::clone(k), eval_to_core(v)?);
29
+ let b = map.borrow();
30
+ let mut strings = ObjectMap::default();
31
+ for (k, v) in b.strings.iter() {
32
+ strings.insert(Arc::clone(k), eval_to_core(v)?);
31
33
  }
32
- Ok(CoreValue::Object(VmRef::new(out)))
34
+ let symbols = if let Some(ss) = &b.symbols {
35
+ let mut sm = AHashMap::default();
36
+ for (id, v) in ss.iter() {
37
+ sm.insert(*id, eval_to_core(v)?);
38
+ }
39
+ Some(sm)
40
+ } else {
41
+ None
42
+ };
43
+ Ok(CoreValue::Object(VmRef::new(ObjectData { strings, symbols })))
33
44
  }
45
+ Value::Symbol(s) => Ok(CoreValue::Symbol(Arc::clone(s))),
34
46
  Value::Opaque(o) => Ok(CoreValue::Opaque(Arc::clone(o))),
35
47
  _ => Err(format!(
36
48
  "Cannot pass {:?} to native function (unsupported type)",
@@ -54,12 +66,22 @@ pub fn core_to_eval(v: CoreValue) -> Value {
54
66
  Value::Array(Rc::new(RefCell::new(out)))
55
67
  }
56
68
  CoreValue::Object(map) => {
69
+ let b = map.borrow();
57
70
  let mut out = PropMap::default();
58
- for (k, v) in map.borrow().iter() {
71
+ for (k, v) in b.strings.iter() {
59
72
  out.insert(Arc::clone(k), core_to_eval(v.clone()));
60
73
  }
61
- Value::Object(Rc::new(RefCell::new(out)))
74
+ let mut eod = EvalObjectData::from_strings(out);
75
+ if let Some(ss) = &b.symbols {
76
+ let mut es = AHashMap::default();
77
+ for (id, v) in ss.iter() {
78
+ es.insert(*id, core_to_eval(v.clone()));
79
+ }
80
+ eod.symbols = Some(es);
81
+ }
82
+ Value::Object(Rc::new(RefCell::new(eod)))
62
83
  }
84
+ CoreValue::Symbol(s) => Value::Symbol(Arc::clone(&s)),
63
85
  CoreValue::Opaque(o) => Value::Opaque(o),
64
86
  #[cfg(feature = "http")]
65
87
  CoreValue::Promise(p) => Value::CorePromise(Arc::clone(&p)),
@@ -1023,7 +1023,10 @@ mod tests {
1023
1023
  fn jsx_multiline_when_mixed_children() {
1024
1024
  let src = "let x = <div>a{b}</div>\n";
1025
1025
  let out = format_source(src).unwrap();
1026
- assert!(out.contains('\n'), "expected line breaks in formatted JSX: {out:?}");
1026
+ assert!(
1027
+ out.contains('\n'),
1028
+ "expected line breaks in formatted JSX: {out:?}"
1029
+ );
1027
1030
  let _ = tishlang_parser::parse(&out).unwrap();
1028
1031
  }
1029
1032
  }
@@ -701,11 +701,16 @@ mod tests {
701
701
  #[test]
702
702
  fn line_comment_does_not_emit_spurious_indent_before_next_line() {
703
703
  let with_comment = "fn f() {\n return {\n a: 1, // c\n b: 2\n }\n}\n";
704
- let tokens: Vec<_> = Lexer::new(with_comment).collect::<Result<Vec<_>, _>>().unwrap();
704
+ let tokens: Vec<_> = Lexer::new(with_comment)
705
+ .collect::<Result<Vec<_>, _>>()
706
+ .unwrap();
705
707
  assert!(
706
708
  !tokens.iter().any(|t| t.kind == TokenKind::Indent),
707
709
  "unexpected Indent after line comment: {:?}",
708
- tokens.iter().map(|t| format!("{:?}", t.kind)).collect::<Vec<_>>()
710
+ tokens
711
+ .iter()
712
+ .map(|t| format!("{:?}", t.kind))
713
+ .collect::<Vec<_>>()
709
714
  );
710
715
  }
711
716
  }
@@ -26,8 +26,8 @@ pub fn compile_to_native(
26
26
  let program = merge_modules(modules)
27
27
  .map(|m| m.program)
28
28
  .map_err(|e| LlvmError {
29
- message: e.to_string(),
30
- })?;
29
+ message: e.to_string(),
30
+ })?;
31
31
  let chunk = tishlang_bytecode::compile(&program).map_err(|e| LlvmError {
32
32
  message: e.to_string(),
33
33
  })?;
@@ -33,16 +33,117 @@ fn is_ident_char(c: char) -> bool {
33
33
 
34
34
  /// HTML / SVG intrinsic tag names (lowercase) that JSX lowers to `h("tag", …)`; must stay sorted for `binary_search`.
35
35
  const HTML_INTRINSIC_TAGS: &[&str] = &[
36
- "a", "abbr", "address", "area", "article", "aside", "audio", "b", "base", "bdi", "bdo",
37
- "blockquote", "body", "br", "button", "canvas", "caption", "cite", "code", "col", "colgroup",
38
- "data", "datalist", "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed",
39
- "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4", "h5", "h6",
40
- "head", "header", "hr", "html", "i", "iframe", "img", "input", "ins", "kbd", "label", "legend",
41
- "li", "link", "main", "map", "mark", "meta", "meter", "nav", "noscript", "object", "ol",
42
- "optgroup", "option", "output", "p", "param", "picture", "pre", "progress", "q", "rp", "rt",
43
- "ruby", "s", "samp", "script", "section", "select", "slot", "small", "source", "span", "strong",
44
- "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template", "textarea",
45
- "tfoot", "th", "thead", "time", "title", "tr", "track", "u", "ul", "var", "video", "wbr",
36
+ "a",
37
+ "abbr",
38
+ "address",
39
+ "area",
40
+ "article",
41
+ "aside",
42
+ "audio",
43
+ "b",
44
+ "base",
45
+ "bdi",
46
+ "bdo",
47
+ "blockquote",
48
+ "body",
49
+ "br",
50
+ "button",
51
+ "canvas",
52
+ "caption",
53
+ "cite",
54
+ "code",
55
+ "col",
56
+ "colgroup",
57
+ "data",
58
+ "datalist",
59
+ "dd",
60
+ "del",
61
+ "details",
62
+ "dfn",
63
+ "dialog",
64
+ "div",
65
+ "dl",
66
+ "dt",
67
+ "em",
68
+ "embed",
69
+ "fieldset",
70
+ "figcaption",
71
+ "figure",
72
+ "footer",
73
+ "form",
74
+ "h1",
75
+ "h2",
76
+ "h3",
77
+ "h4",
78
+ "h5",
79
+ "h6",
80
+ "head",
81
+ "header",
82
+ "hr",
83
+ "html",
84
+ "i",
85
+ "iframe",
86
+ "img",
87
+ "input",
88
+ "ins",
89
+ "kbd",
90
+ "label",
91
+ "legend",
92
+ "li",
93
+ "link",
94
+ "main",
95
+ "map",
96
+ "mark",
97
+ "meta",
98
+ "meter",
99
+ "nav",
100
+ "noscript",
101
+ "object",
102
+ "ol",
103
+ "optgroup",
104
+ "option",
105
+ "output",
106
+ "p",
107
+ "param",
108
+ "picture",
109
+ "pre",
110
+ "progress",
111
+ "q",
112
+ "rp",
113
+ "rt",
114
+ "ruby",
115
+ "s",
116
+ "samp",
117
+ "script",
118
+ "section",
119
+ "select",
120
+ "slot",
121
+ "small",
122
+ "source",
123
+ "span",
124
+ "strong",
125
+ "style",
126
+ "sub",
127
+ "summary",
128
+ "sup",
129
+ "svg",
130
+ "table",
131
+ "tbody",
132
+ "td",
133
+ "template",
134
+ "textarea",
135
+ "tfoot",
136
+ "th",
137
+ "thead",
138
+ "time",
139
+ "title",
140
+ "tr",
141
+ "track",
142
+ "u",
143
+ "ul",
144
+ "var",
145
+ "video",
146
+ "wbr",
46
147
  ];
47
148
 
48
149
  static SOURCE_MAP: OnceLock<HashMap<String, BuiltinDef>> = OnceLock::new();
@@ -9,11 +9,11 @@ use regex::Regex;
9
9
  use tower_lsp::lsp_types::{Location, Position, Range, Url};
10
10
 
11
11
  use tishlang_ast::{ImportSpecifier, Program, Statement};
12
- use tishlang_resolve::member_access_chain_at_cursor;
13
12
  use tishlang_compile::{
14
13
  export_name_to_rust_ident, is_builtin_native_spec, is_cargo_native_spec, is_native_import,
15
14
  normalize_builtin_spec, read_project_tish_config, resolve_bare_spec, resolve_native_modules,
16
15
  };
16
+ use tishlang_resolve::member_access_chain_at_cursor;
17
17
 
18
18
  /// Pick a workspace / project root for resolving `package.json` and `node_modules`.
19
19
  fn infer_project_root(file_path: &Path, roots: &[PathBuf]) -> Option<PathBuf> {
@@ -43,7 +43,10 @@ fn location_from_rust_path(path: &Path, line: u32, col: u32) -> Option<Location>
43
43
  Some(Location {
44
44
  uri,
45
45
  range: Range {
46
- start: Position { line, character: col },
46
+ start: Position {
47
+ line,
48
+ character: col,
49
+ },
47
50
  end: Position {
48
51
  line,
49
52
  character: end_char.max(col.saturating_add(1)),
@@ -63,13 +66,10 @@ fn resolve_cargo_dep_crate_root(
63
66
  Ok(r.source_root())
64
67
  }
65
68
  serde_json::Value::Object(map) => {
66
- let path_str = map
67
- .get("path")
68
- .and_then(|v| v.as_str())
69
- .ok_or_else(|| {
70
- "cargo:… rustDependencies entry must be a version string or an object with \"path\""
71
- .to_string()
72
- })?;
69
+ let path_str = map.get("path").and_then(|v| v.as_str()).ok_or_else(|| {
70
+ "cargo:… rustDependencies entry must be a version string or an object with \"path\""
71
+ .to_string()
72
+ })?;
73
73
  let glue = Path::new(path_str);
74
74
  let glue = if glue.is_absolute() {
75
75
  glue.to_path_buf()
@@ -79,7 +79,8 @@ fn resolve_cargo_dep_crate_root(
79
79
  let glue = glue.canonicalize().unwrap_or(glue);
80
80
  let glue_cargo = glue.join("Cargo.toml");
81
81
  if glue_cargo.is_file() {
82
- match tishlang_cargo_bindgen::resolve_dependency_from_manifest(&glue_cargo, dep_key) {
82
+ match tishlang_cargo_bindgen::resolve_dependency_from_manifest(&glue_cargo, dep_key)
83
+ {
83
84
  Ok(r) => Ok(r.source_root()),
84
85
  Err(_) if glue.join("src").is_dir() => Ok(glue),
85
86
  Err(e) => Err(e),
@@ -128,7 +129,8 @@ fn rust_def_for_crate_root(crate_root: &Path, tish_export: &str) -> Option<Locat
128
129
  if name.is_empty() {
129
130
  continue;
130
131
  }
131
- if let Ok((path, line, col)) = tishlang_cargo_bindgen::rust_public_fn_location(crate_root, name)
132
+ if let Ok((path, line, col)) =
133
+ tishlang_cargo_bindgen::rust_public_fn_location(crate_root, name)
132
134
  {
133
135
  return location_from_rust_path(&path, line, col);
134
136
  }
@@ -218,11 +220,11 @@ fn try_rust_member_on_crate(
218
220
  }
219
221
 
220
222
  /// Optional `| …` hover line after the 1-based line in a native package’s `lsp-pragmas.d.tish`.
221
- fn parse_lsp_pragmas_native(src: &str) -> HashMap<String, (crate::builtin_goto::BuiltinDef, Option<String>)> {
222
- let re = Regex::new(
223
- r"(?m)^\s*//\s*@tish-source\s+(\S+)\s+(\S+)\s+(\d+)(?:\s*\|\s*(.*?))?\s*$",
224
- )
225
- .expect("native lsp pragma regex");
223
+ fn parse_lsp_pragmas_native(
224
+ src: &str,
225
+ ) -> HashMap<String, (crate::builtin_goto::BuiltinDef, Option<String>)> {
226
+ let re = Regex::new(r"(?m)^\s*//\s*@tish-source\s+(\S+)\s+(\S+)\s+(\d+)(?:\s*\|\s*(.*?))?\s*$")
227
+ .expect("native lsp pragma regex");
226
228
  let mut m = HashMap::new();
227
229
  for cap in re.captures_iter(src) {
228
230
  let sym = cap[1].to_string();
@@ -256,7 +258,11 @@ fn pragma_key_for_native_member(
256
258
  }
257
259
  match imported_for_prefix {
258
260
  Some(prefix) => {
259
- let tail: String = members.iter().map(|m| m.as_ref()).collect::<Vec<_>>().join(".");
261
+ let tail: String = members
262
+ .iter()
263
+ .map(|m| m.as_ref())
264
+ .collect::<Vec<_>>()
265
+ .join(".");
260
266
  if tail.is_empty() {
261
267
  None
262
268
  } else {
@@ -375,14 +381,16 @@ pub fn native_member_definition(
375
381
  .get("rustDependencies")
376
382
  .and_then(|v| v.get(dep_key))
377
383
  .cloned()?;
378
- cargo_crate_root_cached(&project_root, &spec, dep_key, &raw, cargo_src_cache).ok()?
384
+ cargo_crate_root_cached(&project_root, &spec, dep_key, &raw, cargo_src_cache)
385
+ .ok()?
379
386
  } else {
380
387
  let mods = resolve_native_modules(program, &project_root).ok()?;
381
388
  let m = mods.iter().find(|mm| mm.spec == spec)?;
382
389
  m.crate_path.clone()
383
390
  };
384
391
 
385
- if let Some(loc) = try_rust_member_on_crate(&crate_root, &members, imported_for_prefix) {
392
+ if let Some(loc) = try_rust_member_on_crate(&crate_root, &members, imported_for_prefix)
393
+ {
386
394
  return Some(NativeMemberDefinition {
387
395
  location: loc,
388
396
  doc: None,
@@ -492,9 +500,14 @@ pub fn definition_for_import(
492
500
  .get("rustDependencies")
493
501
  .and_then(|v| v.get(dep_key))
494
502
  .cloned()?;
495
- let crate_root =
496
- cargo_crate_root_cached(&project_root, &spec, dep_key, &raw, cargo_src_cache)
497
- .ok()?;
503
+ let crate_root = cargo_crate_root_cached(
504
+ &project_root,
505
+ &spec,
506
+ dep_key,
507
+ &raw,
508
+ cargo_src_cache,
509
+ )
510
+ .ok()?;
498
511
  return rust_def_for_crate_root(&crate_root, imported);
499
512
  }
500
513