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)
extensions/sample/sample.ling
# sample.ling - the example LingCoder extension: a TODO panel. Shows every hook: _info,
# _commands + _run, _panel_info + _panel, _on_event, and the ide_* API. Every function
# starts with sample_ (the loader enforces it). Edit this file and save: it reloads live.
fn sample_info() { return ["TODO list", "Lists TODO / FIXME lines in the current file; click one to jump to it", "1.0"] }
fn sample_panel_info() { return ["TODO list (sample extension)", "check"] }
fn sample_commands() {
return ["scan|TODO: Scan Current File||check", "header|TODO: Insert File Header||text"]
}
fn sample_run(id) {
if id == "scan" {
sample_scan()
side_show("ext:sample")
return num_str(st_llen("smp_line")) + " TODO(s) in " + p_base(ide_cur_path())
}
if id == "header" {
ide_insert("# " + p_base(ide_cur_path()) + " - what this file is for.\n# TODO: write the real header\n")
return "Header inserted"
}
return ""
}
fn sample_on_event(ev, arg) {
# rescan whenever a file is opened or saved
if ev == "open" || ev == "save" { st_set("smp_stale", 1.0) }
return 0.0
}
fn sample_scan() {
st_lclear("smp_line")
st_lclear("smp_text")
st_set("smp_for", ide_cur_path())
st_set("smp_stale", 0.0)
bind body = ide_cur_text()
if body == "" { return 0.0 }
bind lines = str_split(body, "\n")
bind i = 0.0
while i < len(lines) && st_llen("smp_line") < 200.0 {
bind ln = list_get(lines, i)
if str_find(ln, "TODO") >= 0.0 || str_find(ln, "FIXME") >= 0.0 || str_find(ln, "XXX") >= 0.0 {
st_lpush("smp_line", i + 1.0)
st_lpush("smp_text", str_trim(ln))
}
bind i = i + 1.0
}
return 0.0
}
fn sample_panel(x, y, w, h) {
ds_word(x + 10.0, y + 10.0, 10.0, "TODO", ds_col("ctl"), false)
g_text_r(x + w - 10.0, y + 9.0, 10.0, C_TEXT_DIM, "sample extension")
if st_get("smp_stale", 1.0) > 0.5 || st_get("smp_for", "") != ide_cur_path() { sample_scan() }
bind n = st_llen("smp_line")
bind ry0 = y + 30.0
bind rh = h - 34.0
if n < 0.5 {
g_text_wrap(x + 12.0, ry0 + 6.0, w - 24.0, 11.0, C_TEXT_DIM, "No TODO / FIXME / XXX lines in " + sel(ide_cur_path() == "", "(no file open)", p_base(ide_cur_path())) + ". This panel is extensions/sample/sample.ling - open it to see how extensions work.")
return 0.0
}
bind off = u_scroll_y("smp_sb", x, ry0, w, rh, n * 34.0, st_get("smp_off", 0.0))
st_set("smp_off", off)
u_clip(x, ry0, w, rh)
bind i = 0.0
while i < n {
bind ry = ry0 + 2.0 + i * 34.0 - off
if ry + 34.0 > ry0 && ry < ry0 + rh {
bind hot = u_hot(x, ry, w - 12.0, 33.0)
if hot { g_rect(x, ry, w, 33.0, C_HOVER_ROW) }
icon_draw("check", x + 15.0, ry + 16.0, 10.0, ds_col("ctl"))
g_text(x + 28.0, ry + 4.0, 11.0, sel(hot, C_TEXT_STRONG, C_TEXT), "line " + num_str(st_lget("smp_line", i)))
g_text_fit(x + 28.0, ry + 18.0, w - 44.0, 10.0, C_TEXT_DIM, st_lget("smp_text", i))
if hot && u_pressed() { ide_goto(st_lget("smp_line", i) - 1.0) }
}
bind i = i + 1.0
}
u_unclip()
return 0.0
}