L
lingcoder
↓ 0 downloadsLingCoder: a Geany / VS Code-style IDE for Ling, written in Ling. Explorer, tabs, syntax-coloured editor with lint, find in files, command palette, run/build panel, and hot-reloaded extensions - including a Claude assistant.
Keywords ide, editor, ling, claude, extensions
lingfu install lingcoderCode / Files (34)
ling/runner.ling
# runner.ling - Run File / Run Project / Build through the platform job system; the log
# streams into the Output panel (dock.ling reads st "run_tail").
fn cache_dir() {
bind d = p_join(app_root(), "cache")
plat_mkdir(d)
return d
}
fn run_log_path() { return p_join(cache_dir(), "run.log") }
# the ling executable: the setting, a build next door, or `ling` on PATH
fn ling_exe_path() {
bind s = str_trim(st_get("ling_exe", ""))
if s != "" { return p_norm(s) }
bind near = p_join(p_dir(app_root()), "ling/target-coder/release/ling.exe")
if file_exists(near) { return near }
bind near = p_join(p_dir(app_root()), "ling/target/release/ling.exe")
if file_exists(near) { return near }
bind near = p_join(p_dir(app_root()), "ling/target/release/ling")
if file_exists(near) { return near }
return "ling"
}
fn run_busy() { return st_get("run_job", 0.0 - 1.0) >= 0.0 }
fn run_start(argv, dir, label) {
if run_busy() { status("A job is already running - Stop it first (Shift+F5)") return 0.0 }
bind exe = ling_exe_path()
bind h = plat_job_start(exe, argv, dir, run_log_path())
if h < 0.0 { status("Could not start " + exe) return 0.0 }
st_set("run_job", h)
st_set("run_label", label)
st_set("run_t0", st_get("now", 0.0))
st_set("run_cmdline", "$ " + p_base(exe) + " " + run_argv_text(argv))
st_set("run_tail", st_get("run_cmdline", "") + "\n")
st_set("show_dock", 1.0)
st_set("dock_tab", 1.0)
st_set("out_off", 0.0 - 1.0)
status(label + " started")
return 0.0
}
fn run_argv_text(argv) {
bind s = ""
bind i = 0.0
while i < len(argv) {
bind s = s + sel(i > 0.0, " ", "") + list_get(argv, i)
bind i = i + 1.0
}
return s
}
fn run_file() {
bind bi = buf_cur()
if bi < 0.0 { status("Open a file to run") return 0.0 }
buf_save_all()
bind p = buf_path(bi)
bind e = p_ext(p)
if syn_lang(p) == "ling" {
run_start(["run", "--interp", p], p_dir(p), "Run " + p_base(p))
} else if e == "bat" || e == "cmd" || e == "sh" {
plat_launch(p)
status("Started " + p_base(p))
} else {
status("Run works on .ling files (this is ." + e + ")")
}
return 0.0
}
# the project entry: Ling.toml's `entry = "..."`, else ling/main.ling, else main.ling
fn proj_entry() {
bind root = proj_root()
if root == "" { return "" }
bind mf = p_join(root, "Ling.toml")
if file_exists(mf) {
bind e = unquote(str_trim(cfg_get(str_replace(plat_read(mf), " = ", "="), "entry", "")))
if e != "" && file_exists(p_join(root, e)) { return p_join(root, e) }
}
if file_exists(p_join(root, "ling/main.ling")) { return p_join(root, "ling/main.ling") }
if file_exists(p_join(root, "main.ling")) { return p_join(root, "main.ling") }
return ""
}
fn run_project() {
bind e = proj_entry()
if e == "" { status("No project entry found (Ling.toml entry=, ling/main.ling or main.ling)") return 0.0 }
buf_save_all()
run_start(["run", "--interp", e], proj_root(), "Run " + proj_name())
return 0.0
}
fn run_build() {
bind root = proj_root()
if root == "" { status("Open a folder to build (Ctrl+Shift+O)") return 0.0 }
buf_save_all()
run_start(["build", ".", "--platform", "win"], root, "Build " + proj_name())
return 0.0
}
fn run_stop() {
if !run_busy() { status("Nothing is running") return 0.0 }
plat_job_kill(st_get("run_job", 0.0 - 1.0))
st_set("run_job", 0.0 - 1.0)
st_set("run_tail", st_get("run_tail", "") + "\n[stopped]\n")
status("Stopped")
return 0.0
}
fn run_clear() {
st_set("run_tail", "")
plat_write(run_log_path(), "")
return 0.0
}
# every frame: pull the log tail, notice the end
fn run_tick() {
if !run_busy() { return 0.0 }
# read the log twice a second (it can be large)
if st_get("now", 0.0) - st_get("run_poll_t", 0.0) < 0.4 { return 0.0 }
st_set("run_poll_t", st_get("now", 0.0))
bind t = plat_job_log(run_log_path())
bind full = st_get("run_cmdline", "") + "\n" + t
# keep the last ~400 lines
bind lines = str_split(full, "\n")
bind n = len(lines)
if n > 400.0 {
bind keep = ""
bind i = n - 400.0
while i < n {
bind keep = keep + list_get(lines, i) + sel(i < n - 1.0, "\n", "")
bind i = i + 1.0
}
bind full = "[... earlier output trimmed ...]\n" + keep
}
st_set("run_tail", full)
bind code = plat_job_poll(st_get("run_job", 0.0 - 1.0), run_log_path())
if code > 0.0 - 1.5 {
st_set("run_job", 0.0 - 1.0)
bind secs = fmt1(st_get("now", 0.0) - st_get("run_t0", 0.0))
st_set("run_tail", st_get("run_tail", "") + "\n[" + st_get("run_label", "") + " finished: exit " + num_str(code) + " in " + secs + " s]\n")
status(st_get("run_label", "") + sel(code == 0.0, " finished", " FAILED (exit " + num_str(code) + ")") + " in " + secs + " s")
}
return 0.0
}