L
ling-miao
↓ 0 downloadsmiao: a Ling-native version control system — temples, souls, rites and talismans instead of repos, branches, commits and tags; adaptive whole/delta/chunk storage; SSH temple fairs for sharing; a LingStationX-themed GUI; ROYGBIV everywhere
Keywords vcs, version-control, git, miao, ling
lingfu install ling-miaoCode / Files (268)
ling/diffy.ling
# ━━━ diffy.ling — yinyang: line diffs, delta scripts, chunking, merge ━━━
# yin (阴) is what darkens away: deletions, red.
# yang (阳) is what comes to light: additions, green.
# fns prefixed dy_.
# ── core line diff ────────────────────────────────────────────────────
# returns a flat strided ops list: [kind, count, kind, count, ...]
# kinds: "=" advance both, "-" advance a only (yin), "+" advance b only (yang)
fn dy_ops(la, lb) {
bind na = len(la)
bind nb = len(lb)
# common prefix
bind p = 0.0
bind lim = min(na, nb)
bind go = true
while go {
if p >= lim {
bind go = false
} else if list_get(la, p) == list_get(lb, p) {
bind p = p + 1.0
} else {
bind go = false
}
}
# common suffix (not overlapping the prefix)
bind s = 0.0
bind go = true
while go {
if s >= lim - p {
bind go = false
} else if list_get(la, na - 1.0 - s) == list_get(lb, nb - 1.0 - s) {
bind s = s + 1.0
} else {
bind go = false
}
}
bind ma = na - p - s
bind mb = nb - p - s
bind ops = list_new()
if p > 0.0 {
bind ops = list_push(ops, "=")
bind ops = list_push(ops, p)
}
if ma > 0.0 || mb > 0.0 {
if ma * mb > 160000.0 || ma < 0.5 || mb < 0.5 {
# too large for LCS (or pure insert/delete): one replace block
if ma > 0.0 {
bind ops = list_push(ops, "-")
bind ops = list_push(ops, ma)
}
if mb > 0.0 {
bind ops = list_push(ops, "+")
bind ops = list_push(ops, mb)
}
} else {
bind mid = dy_lcs_ops(la, lb, p, ma, mb)
bind k = 0.0
while k < len(mid) {
bind ops = list_push(ops, list_get(mid, k))
bind k = k + 1.0
}
}
}
if s > 0.0 {
bind ops = list_push(ops, "=")
bind ops = list_push(ops, s)
}
return ops
}
# LCS over the middle window la[p..p+ma) x lb[p..p+mb); returns strided ops
fn dy_lcs_ops(la, lb, p, ma, mb) {
# build DP table rows (list of lists), row size mb+1
bind rows = list_new()
bind row0 = list_new()
bind j = 0.0
while j <= mb {
bind row0 = list_push(row0, 0.0)
bind j = j + 1.0
}
bind rows = list_push(rows, row0)
bind i = 1.0
while i <= ma {
bind prev = list_get(rows, i - 1.0)
bind row = list_new()
bind row = list_push(row, 0.0)
bind ai = list_get(la, p + i - 1.0)
bind j = 1.0
while j <= mb {
if ai == list_get(lb, p + j - 1.0) {
bind row = list_push(row, list_get(prev, j - 1.0) + 1.0)
} else {
bind row = list_push(row, max(list_get(prev, j), list_get(row, j - 1.0)))
}
bind j = j + 1.0
}
bind rows = list_push(rows, row)
bind i = i + 1.0
}
# backtrack -> reversed per-step kinds
bind steps = list_new()
bind i = ma
bind j = mb
bind go = true
while go {
if i < 0.5 && j < 0.5 {
bind go = false
} else if i < 0.5 {
bind steps = list_push(steps, "+")
bind j = j - 1.0
} else if j < 0.5 {
bind steps = list_push(steps, "-")
bind i = i - 1.0
} else if list_get(la, p + i - 1.0) == list_get(lb, p + j - 1.0) {
bind steps = list_push(steps, "=")
bind i = i - 1.0
bind j = j - 1.0
} else {
bind up = list_get(list_get(rows, i - 1.0), j)
bind lf = list_get(list_get(rows, i), j - 1.0)
if up >= lf {
bind steps = list_push(steps, "-")
bind i = i - 1.0
} else {
bind steps = list_push(steps, "+")
bind j = j - 1.0
}
}
}
# walk steps in reverse, coalescing runs; prefer emitting "-" before "+"
bind ops = list_new()
bind k = len(steps) - 1.0
bind cur = ""
bind count = 0.0
while k >= 0.0 {
bind kind = list_get(steps, k)
if kind == cur {
bind count = count + 1.0
} else {
if count > 0.0 {
bind ops = list_push(ops, cur)
bind ops = list_push(ops, count)
}
bind cur = kind
bind count = 1.0
}
bind k = k - 1.0
}
if count > 0.0 {
bind ops = list_push(ops, cur)
bind ops = list_push(ops, count)
}
return ops
}
# ── delta scripts (storage format for text spirits) ───────────────────
# script lines: c <start> <count> copy from base
# i <count> insert the next <count> literal lines
fn dy_delta_make(base_text, new_text) {
bind la = split(base_text, "\n")
bind lb = split(new_text, "\n")
bind ops = dy_ops(la, lb)
bind out = ""
bind apos = 0.0
bind bpos = 0.0
bind k = 0.0
while k < len(ops) {
bind kind = list_get(ops, k)
bind n = list_get(ops, k + 1.0)
if kind == "=" {
bind out = out + "c " + apos + " " + n + "\n"
bind apos = apos + n
bind bpos = bpos + n
} else if kind == "-" {
bind apos = apos + n
} else {
bind out = out + "i " + n + "\n"
bind q = 0.0
while q < n {
bind out = out + list_get(lb, bpos + q) + "\n"
bind q = q + 1.0
}
bind bpos = bpos + n
}
bind k = k + 2.0
}
return out
}
fn dy_delta_apply(base_text, script) {
bind la = split(base_text, "\n")
bind sl = split(script, "\n")
bind out = list_new()
bind i = 0.0
while i < len(sl) {
bind ln = list_get(sl, i)
if str_starts_with(ln, "c ") {
bind parts = split(ln, " ")
bind start = to_number(list_get(parts, 1.0))
bind n = to_number(list_get(parts, 2.0))
bind q = 0.0
while q < n {
bind out = list_push(out, list_get(la, start + q))
bind q = q + 1.0
}
bind i = i + 1.0
} else if str_starts_with(ln, "i ") {
bind n = to_number(str_slice(ln, 2.0, 99.0))
bind q = 0.0
while q < n {
bind out = list_push(out, list_get(sl, i + 1.0 + q))
bind q = q + 1.0
}
bind i = i + 1.0 + n
} else {
bind i = i + 1.0
}
}
return list_join(out, "\n")
}
# ── fenshen 分身: content-defined chunking over a hex string ──────────
# boundaries at the anchor byte pair 0x2e71, min 64 KiB, max 256 KiB per
# chunk. shift-resistant: an insert only re-stores the chunks it touches.
fn dy_chunks(hx) {
bind minh = 131072.0
bind maxh = 524288.0
bind n = len(hx)
bind out = list_new()
bind pos = 0.0
while pos < n {
if n - pos <= maxh {
bind out = list_push(out, str_slice(hx, pos, n - pos))
bind pos = n
} else {
bind win = str_slice(hx, pos + minh, maxh - minh)
# find an even-aligned anchor
bind woff = 0.0
bind f = 0.0 - 1.0
bind go = true
while go {
bind rest = str_slice(win, woff, len(win) - woff)
bind g = str_find(rest, "2e71")
if g < 0.0 {
bind go = false
} else if floor((woff + g) / 2.0) * 2.0 == woff + g {
bind f = woff + g
bind go = false
} else {
bind woff = woff + g + 1.0
}
}
bind cut = pos + maxh
if f >= 0.0 { bind cut = pos + minh + f + 4.0 }
bind out = list_push(out, str_slice(hx, pos, cut - pos))
bind pos = cut
}
}
return out
}
# ── edits extraction (for merge): ops -> [starts, ends, repl_lists] ───
fn dy_edits(base_lines, new_lines) {
bind ops = dy_ops(base_lines, new_lines)
bind starts = list_new()
bind ends = list_new()
bind repls = list_new()
bind apos = 0.0
bind bpos = 0.0
bind k = 0.0
bind open = false
bind es = 0.0
bind repl = list_new()
while k < len(ops) {
bind kind = list_get(ops, k)
bind n = list_get(ops, k + 1.0)
if kind == "=" {
if open {
bind starts = list_push(starts, es)
bind ends = list_push(ends, apos)
bind repls = list_push(repls, repl)
bind open = false
}
bind apos = apos + n
bind bpos = bpos + n
} else {
if open == false {
bind open = true
bind es = apos
bind repl = list_new()
}
if kind == "-" {
bind apos = apos + n
} else {
bind q = 0.0
while q < n {
bind repl = list_push(repl, list_get(new_lines, bpos + q))
bind q = q + 1.0
}
bind bpos = bpos + n
}
}
bind k = k + 2.0
}
if open {
bind starts = list_push(starts, es)
bind ends = list_push(ends, apos)
bind repls = list_push(repls, repl)
}
return [starts, ends, repls]
}
# ── harmonize: three-way text merge. returns [merged_text, conflicts] ─
fn dy_merge3(base, ours, theirs, label_o, label_t) {
if ours == theirs { return [ours, 0.0] }
if ours == base { return [theirs, 0.0] }
if theirs == base { return [ours, 0.0] }
bind lbase = split(base, "\n")
bind eo = dy_edits(lbase, split(ours, "\n"))
bind et = dy_edits(lbase, split(theirs, "\n"))
bind os = list_get(eo, 0.0)
bind oe = list_get(eo, 1.0)
bind orp = list_get(eo, 2.0)
bind ts = list_get(et, 0.0)
bind te = list_get(et, 1.0)
bind trp = list_get(et, 2.0)
bind out = list_new()
bind conflicts = 0.0
bind cur = 0.0
bind i = 0.0
bind j = 0.0
bind go = true
while go {
bind has_o = i < len(os)
bind has_t = j < len(ts)
if has_o == false && has_t == false {
bind go = false
} else {
# which edit comes first?
bind so = 99999999.0
bind st2 = 99999999.0
if has_o { bind so = list_get(os, i) }
if has_t { bind st2 = list_get(ts, j) }
# overlap test: edits [so,eo) and [st,et) touch?
bind overlap = false
if has_o {
if has_t {
bind a1 = list_get(os, i)
bind a2 = list_get(oe, i)
bind b1 = list_get(ts, j)
bind b2 = list_get(te, j)
if a1 < b2 && b1 < a2 { bind overlap = true }
# two insertions at the same point: order is ambiguous
if a1 == b1 && a1 == a2 && b1 == b2 { bind overlap = true }
}
}
if overlap {
# expand the conflict region across chained overlaps
bind us = min(list_get(os, i), list_get(ts, j))
bind ue = max(list_get(oe, i), list_get(te, j))
bind oi0 = i
bind tj0 = j
bind grow = true
while grow {
bind grow = false
if i + 1.0 < len(os) {
if list_get(os, i + 1.0) <= ue {
bind i = i + 1.0
bind ue = max(ue, list_get(oe, i))
bind grow = true
}
}
if j + 1.0 < len(ts) {
if list_get(ts, j + 1.0) <= ue {
bind j = j + 1.0
bind ue = max(ue, list_get(te, j))
bind grow = true
}
}
}
# copy base up to the union start
bind q = cur
while q < us {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
# ours version of [us,ue): apply ours edits oi0..i inside the region
bind out = list_push(out, "<<<<<<< " + label_o)
bind out = dy_apply_region(out, lbase, us, ue, os, oe, orp, oi0, i)
bind out = list_push(out, "=======")
bind out = dy_apply_region(out, lbase, us, ue, ts, te, trp, tj0, j)
bind out = list_push(out, ">>>>>>> " + label_t)
bind conflicts = conflicts + 1.0
bind cur = ue
bind i = i + 1.0
bind j = j + 1.0
} else if so <= st2 {
# ours edit applies cleanly
bind q = cur
while q < so {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
bind r = list_get(orp, i)
bind q = 0.0
while q < len(r) {
bind out = list_push(out, list_get(r, q))
bind q = q + 1.0
}
bind cur = list_get(oe, i)
bind i = i + 1.0
} else {
bind q = cur
while q < st2 {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
bind r = list_get(trp, j)
bind q = 0.0
while q < len(r) {
bind out = list_push(out, list_get(r, q))
bind q = q + 1.0
}
bind cur = list_get(te, j)
bind j = j + 1.0
}
}
}
bind q = cur
while q < len(lbase) {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
return [list_join(out, "\n"), conflicts]
}
# apply one side's edits (ei0..ei1) to base region [us,ue), push onto out
fn dy_apply_region(out, lbase, us, ue, ss, ee, rr, ei0, ei1) {
bind pos = us
bind e = ei0
while e <= ei1 {
bind s = list_get(ss, e)
bind q = pos
while q < s {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
bind r = list_get(rr, e)
bind q = 0.0
while q < len(r) {
bind out = list_push(out, list_get(r, q))
bind q = q + 1.0
}
bind pos = list_get(ee, e)
bind e = e + 1.0
}
bind q = pos
while q < ue {
bind out = list_push(out, list_get(lbase, q))
bind q = q + 1.0
}
return out
}
# ── colored unified diff rendering ────────────────────────────────────
fn dy_render(a_text, b_text, header) {
bind la = split(a_text, "\n")
bind lb = split(b_text, "\n")
bind ops = dy_ops(la, lb)
bind out = cx_tal("☯ " + header) + "\n"
bind apos = 0.0
bind bpos = 0.0
bind k = 0.0
bind ctx = 3.0
while k < len(ops) {
bind kind = list_get(ops, k)
bind n = list_get(ops, k + 1.0)
if kind == "=" {
bind is_first = k < 1.0
bind is_last = k + 2.0 >= len(ops)
# trailing context after the previous hunk
bind tail = min(ctx, n)
if is_first { bind tail = 0.0 }
bind q = 0.0
while q < tail {
bind out = out + cx_dim(" " + list_get(la, apos + q)) + "\n"
bind q = q + 1.0
}
# leading context before the next hunk
bind lead = min(ctx, n - tail)
if is_last { bind lead = 0.0 }
if tail + lead < n {
if is_first == false || lead > 0.0 { bind out = out + cx_meta(" ···") + "\n" }
}
bind q = 0.0
while q < lead {
bind out = out + cx_dim(" " + list_get(la, apos + n - lead + q)) + "\n"
bind q = q + 1.0
}
bind apos = apos + n
bind bpos = bpos + n
} else if kind == "-" {
bind out = out + cx_meta("@@ 阴 -" + (apos + 1.0) + "," + n + " @@") + "\n"
bind q = 0.0
while q < n {
bind out = out + cx_err("− " + list_get(la, apos + q)) + "\n"
bind q = q + 1.0
}
bind apos = apos + n
} else {
bind out = out + cx_meta("@@ 阳 +" + (bpos + 1.0) + "," + n + " @@") + "\n"
bind q = 0.0
while q < n {
bind out = out + cx_good("+ " + list_get(lb, bpos + q)) + "\n"
bind q = q + 1.0
}
bind bpos = bpos + n
}
bind k = k + 2.0
}
return out
}