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/dock.ling
# dock.ling - the bottom panel: Problems (the Ling lint) and Output (the run/build log).
fn dock_panel(x, y, w, h) {
g_rect(x, y, w, h, C_BG_PANEL)
u_hsep(x, y, w)
bind names = ["Problems", "Output"]
bind cols = [C_YELLOW, C_GREEN]
bind tab = st_get("dock_tab", 0.0)
bind tx = x + 8.0
bind i = 0.0
while i < 2.0 {
bind nm = list_get(names, i)
bind count = ""
if i == 0.0 && st_llen("problems") > 0.5 { bind count = " (" + num_str(st_llen("problems")) + ")" }
bind tw = g_text_w(12.0, nm + count) + 22.0
if u_tab("dock_t" + num_str(i), tx, y + 4.0, tw, 21.0, nm + count, tab == i, list_get(cols, i)) { st_set("dock_tab", i) }
bind tx = tx + tw + 4.0
bind i = i + 1.0
}
# right-side tools
bind bx = x + w - 26.0
if u_icon_button("dock_x", bx, y + 4.0, 20.0, 20.0, "x", 10.0, C_TEXT_DIM, false) { st_set("show_dock", 0.0) }
if tab == 1.0 {
if st_get("run_job", 0.0 - 1.0) >= 0.0 {
if u_button("dock_stop", bx - 62.0, y + 4.0, 56.0, 20.0, "Stop", C_RED) { run_stop() }
} else {
if u_button("dock_clear", bx - 62.0, y + 4.0, 56.0, 20.0, "Clear", 0.0) { run_clear() }
}
}
bind cy = y + 29.0
bind ch = h - 30.0
if tab == 0.0 { problems_panel(x, cy, w, ch) }
else { output_panel(x, cy, w, ch) }
return 0.0
}
# ── problems ──────────────────────────────────────────────────────────────────
fn problems_panel(x, y, w, h) {
bind n = st_llen("problems")
if n < 0.5 {
bind bi = buf_cur()
bind what = sel(bi >= 0.0 && buf_lang(bi) == "ling", "No problems in " + p_base(buf_path(bi)) + ".", "The Ling lint checks the active .ling file as you type.")
g_text(x + 12.0, y + 10.0, 12.0, C_TEXT_DIM, what)
return 0.0
}
bind off = u_scroll_y("pb_sb", x, y, w, h, n * 22.0 + 6.0, st_get("pb_off", 0.0))
st_set("pb_off", off)
u_clip(x, y, w, h)
bind fp = st_get("problems_for", "")
bind i = 0.0
while i < n {
bind ry = y + 3.0 + i * 22.0 - off
if ry + 22.0 > y && ry < y + h {
bind parts = str_split(st_lget("problems", i), "|")
bind lnum = list_get(parts, 0)
bind msg = sel(len(parts) > 2.0, list_get(parts, 2), "")
bind hot = u_hot(x, ry, w - 12.0, 21.0)
if hot { g_rect(x, ry, w, 21.0, C_HOVER_ROW) }
icon_draw("info", x + 16.0, ry + 10.0, 10.0, E_WARN)
g_text(x + 30.0, ry + 4.0, 12.0, sel(hot, C_TEXT_STRONG, C_TEXT), p_base(fp) + " : " + lnum)
g_text_fit(x + 30.0 + g_text_w(12.0, p_base(fp) + " : " + lnum) + 14.0, ry + 4.0, w - 260.0, 12.0, C_TEXT_DIM, msg)
if hot && u_pressed() {
bind bi = buf_find(fp)
if bi < 0.0 { bind bi = buf_open(fp) }
if bi >= 0.0 {
buf_switch_to(bi)
ed_goto_line(bi, to_number(lnum) - 1.0)
}
}
}
bind i = i + 1.0
}
u_unclip()
return 0.0
}
fn problem_jump(dir) {
bind n = st_llen("problems")
if n < 0.5 { status("No problems") return 0.0 }
bind k = st_get("prob_k", 0.0 - 1.0) + dir
if k < 0.0 { bind k = n - 1.0 }
if k >= n { bind k = 0.0 }
st_set("prob_k", k)
bind fp = st_get("problems_for", "")
bind bi = buf_find(fp)
if bi < 0.0 { bind bi = buf_open(fp) }
if bi >= 0.0 {
buf_switch_to(bi)
bind parts = str_split(st_lget("problems", k), "|")
ed_goto_line(bi, to_number(list_get(parts, 0)) - 1.0)
status("Problem " + num_str(k + 1.0) + "/" + num_str(n) + ": " + list_get(parts, 2))
}
return 0.0
}
# ── output (the run/build log) ────────────────────────────────────────────────
fn output_panel(x, y, w, h) {
bind t = st_get("run_tail", "")
if t == "" {
g_text(x + 12.0, y + 10.0, 12.0, C_TEXT_DIM, "Run a file (F5) or build (F7); what it prints lands here." + sel(plat_has_proc(), "", " (jobs run through a helper script on this ling build)"))
return 0.0
}
bind lines = str_split(t, "\n")
bind n = len(lines)
bind lh = 16.0
bind off = st_get("out_off", 0.0 - 1.0)
bind maxoff = max(0.0, n * lh - h + 8.0)
bind pinned = off < 0.0 || off >= maxoff - lh
if pinned { bind off = maxoff }
bind noff = u_scroll_y("out_sb", x, y, w, h, n * lh + 8.0, off)
if noff != off { bind off = noff }
if off >= maxoff - 1.0 { st_set("out_off", 0.0 - 1.0) } else { st_set("out_off", off) }
u_clip(x, y, w, h)
bind i = floor(off / lh)
bind last = min(n, i + ceil(h / lh) + 1.0)
while i < last {
bind ln = list_get(lines, i)
bind ry = y + 4.0 + i * lh - off
bind col = E_TEXT
bind low = str_lower(ln)
if str_find(low, "error") >= 0.0 { bind col = E_ERROR }
else if str_find(low, "warn") >= 0.0 { bind col = E_WARN }
else if str_starts_with(str_trim(ln), "-->") { bind col = E_INFO }
bind hot = u_hot(x + 4.0, ry, w - 20.0, lh)
g_text_fit(x + 12.0, ry, w - 28.0, 12.0, sel(hot && str_starts_with(str_trim(ln), "-->"), C_TEXT_STRONG, col), ln)
# "--> path" lines from ling errors jump to the file
if hot && u_pressed() && str_starts_with(str_trim(ln), "-->") {
bind p = str_trim(str_slice(str_trim(ln), 3.0, str_len(str_trim(ln)) - 3.0))
if file_exists(p) { buf_open(p) }
}
bind i = i + 1.0
}
u_unclip()
if st_get("run_job", 0.0 - 1.0) >= 0.0 {
bind sp = floor(st_get("now", 0.0) * 8.0) % 4.0
g_text_r(x + w - 16.0, y + 4.0, 11.0, C_GREEN, "running" + str_repeat(".", sp + 1.0))
}
return 0.0
}