feat(tooling): JetBrains IDE support, LSP navigation, barrel imports, package scripts and hooks

- JetBrains plugin 1.4.0: semantic colours (builtin / vendor / own), template strings,
  brace handling, run configurations and a test console, package.ludic and
  package.lock.ludic editing (completion, docs, app preview, colour previews, asset
  navigation), External Libraries for the runtime and packages, doc pages for built-ins
- ludic-lsp: go to definition for imports, document links, hover with inferred types,
  type definition, signature help with parameters, docs from docs/language
- `import "dir"` resolves a barrel `dir/index.ludic`
- package.ludic `entry`, `script` and `hook before|after <command>`; `ludic <script>`,
  `ludic script`, `ludic scripts`
- `ludic test --verbose` and `--test NAME`; the test runner filters by name

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-16 16:00:28 +03:00
parent da57b20156
commit f92d7f89c6
75 changed files with 46802 additions and 40343 deletions

View file

@ -945,8 +945,25 @@ function do_import_dir(rel: pointer) -> void {
}
}
# `import "camp"` names a directory: its index.ludic is the barrel that lists
# what the directory exports (its own imports, relative to itself).
function barrel_of(rel: pointer) -> pointer {
let n = len(rel)
if (n > 6) and (rel[n - 6..n] == ".ludic") { return "" }
if rel[n - 1] == '/' { return rel + "index.ludic" }
return rel + "/index.ludic"
}
function do_import(rel: pointer) -> void {
if (len(rel) > 8) and (rel[len(rel) - 8..len(rel)] == "/*.ludic") { do_import_dir(rel); return }
let barrel = barrel_of(rel)
if barrel != "" {
if (read_file(join_path(cur_dir, barrel)) == null) and Fs.is_dir(join_path(cur_dir, rel)) {
perr(`import: {rel} is a directory with no index.ludic (add {barrel} listing its imports)`)
}
do_import(barrel)
return
}
var full = join_path(cur_dir, rel)
var src = read_file(full)
# #75 — the engine runtime (runtime/native/*) ships with the toolchain, not the