Загрузка данных


import sublime, sublime_plugin, re, random, math
class LuxScriptLiveVisualizer(sublime_plugin.EventListener):
    def on_modified_async(self, view):
        if not view.file_name() or not view.file_name().endswith(('.luxs', '.lux', '.ls')): return
        view.erase_phantoms("lux_live"); code = view.substr(sublime.Region(0, view.size())); lines = code.split('\n')
        res, calcVars, repeatVars, step, lastLightVal, end_line_idx = {}, {}, {}, 1, "0", len(lines) - 1
        cleanExpr = lambda e: re.sub(r'\*([a-zA-Z0-9_а-яА-ЯёЁ]+)', lambda m: str(calcVars[m.group(1)]) if m.group(1) in calcVars else '0', e.replace(',', '.'))
        formatNum = lambda v, d=2: f"{max(0.0, min(1.0, float(v))):.{d}f}".replace('.', ',') if isinstance(v, (int, float)) or v.replace('.','',1).isdigit() else "0"
        safe_eval = lambda expr: float(eval(re.sub(r'[^0-9.+\-*/() ]', '', expr), {"__builtins__": None})) if expr.strip() else 0.0
        for idx, line in enumerate(lines):
            line = line.strip(); if not line: continue
            if 'stop()' in line: res[step] = "stop"; step += 1; end_line_idx = idx; break
            if line.startswith('num('):
                eq = line.find('='); if eq == -1: continue
                name = line[eq+1:].replace('*', '').strip(); inner = line[4:line.find(')')]; arr = []
                for p in inner.split(';'): p = p.strip(); arr.append(repeatVars[p[1:].strip()] if p.startswith('*') and p[1:].strip() in repeatVars else [formatNum(calcVars[p[1:].strip()], 6)] if p.startswith('*') and p[1:].strip() in calcVars else [formatNum(safe_eval(cleanExpr(p)), 6)] if not p.startswith('*') else ["0"])
                repeatVars[name] = [item for sublist in arr for item in sublist]; continue
            if line.startswith('calc('):
                eq = line.find('='); if eq == -1: continue
                calcVars[line[eq+1:].replace('*', '').strip()] = safe_eval(cleanExpr(line[5:line.find(')')])); continue
            if line.startswith('calcrepeat('):
                eq = line.find('='); if eq == -1: continue
                name = line[eq+1:].replace('*', '').strip(); inner = line[11:line.find(')')]; semi = inner.find(';')
                if semi == -1: continue
                count = int(inner[semi+1:].strip() or 0); expr = inner[:semi]; op = next((o for o in ['+','-','*','/'] if o in expr), None)
                if not op: continue
                opIdx = expr.find(op); start = float(safe_eval(cleanExpr(expr[:opIdx]))); opVal = float(safe_eval(cleanExpr(expr[opIdx+1:]))); r = []
                for i in range(count): val = start + (opVal * i) if op == '+' else start - (opVal * i) if op == '-' else start * (opVal ** i) if op == '*' else start / (opVal ** i) if opVal != 0 else start; r.append(formatNum(val, 6))
                repeatVars[name] = r; continue
            if line.startswith('speed('):
                eq = line.find('='); if eq == -1: continue
                name = line[eq+1:].replace('*', '').strip(); inner = line[6:line.find(')')]; semi = inner.find(';')
                if semi == -1: continue
                src = inner[:semi].replace('*', '').strip(); factor = float(inner[semi+1:].strip().replace(',', '.') or 1.0)
                if src in repeatVars and len(repeatVars[src]) > 0 and factor > 0:
                    srcArr, r = repeatVars[src], []
                    if factor.is_integer(): r = [srcArr[i] for i in range(0, len(srcArr), int(factor))]
                    else:
                        for i in range(max(1, math.floor((len(srcArr) - 1) / factor) + 1)):
                            idx_f = i * factor; b = math.floor(idx_f); f = idx_f - b
                            r.append(formatNum(float(srcArr[b].replace(',', '.')) + (float(srcArr[b+1].replace(',', '.')) - float(srcArr[b].replace(',', '.'))) * f, 6) if b + 1 < len(srcArr) else srcArr[b])
                    repeatVars[name] = r
                else: repeatVars[name] = []; continue
            if line.startswith('invert('):
                eq = line.find('='); if eq == -1: continue
                src = line[7:line.find(')')].replace('*', '').strip(); repeatVars[line[eq+1:].replace('*', '').strip()] = list(reversed(repeatVars[src])) if src in repeatVars else []; continue
            if line.startswith('rand('):
                eq = line.find('='); if eq == -1: continue
                name = line[eq+1:].replace('*', '').strip(); inner = line[5:line.find(')')]; semi = inner.find(';')
                if semi == -1: continue
                count = int(inner[semi+1:].strip() or 0); parts = [float(safe_eval(cleanExpr(s))) for s in inner[:semi].split('-'] if s.strip()]
                if len(parts) == 2: repeatVars[name] = [formatNum(random.uniform(min(parts), max(parts)), 6) for _ in range(count)]; continue
            if line.startswith('round('):
                eq = line.find('='); if eq == -1: continue
                name = line[eq+1:].replace('*', '').strip(); inner = line[6:line.find(')')]; semi = inner.find(';')
                if semi == -1: continue
                src = inner[:semi].replace('*', '').strip(); step_s = inner[semi+1:].strip().replace(',', '.'); step_f = float(step_s or 1.0); dec = len(step_s.split('.')) if '.' in step_s else 0
                if src in repeatVars: repeatVars[name] = [formatNum(round(float(v.replace(',', '.')) / step_f) * step_f, dec) for v in repeatVars[src]]
                elif src in calcVars: calcVars[name] = round(calcVars[src] / step_f) * step_f; continue
            if line.startswith('wait('):
                for _ in range(int(line[5:line.find(')')].strip() or 0)): res[step] = lastLightVal; step += 1
                continue
            if line.startswith('repeat('):
                semi = line.rfind(';'); if semi == -1: continue
                parts = [s[:s.find(')')].replace('*', '').strip() for s in line[7:semi].split('light(') if s.strip()]
                for _ in range(int(line[semi+1:line.rfind(')')].strip() or 0)):
                    for p in parts:
                        vals = repeatVars[p] if p in repeatVars else [formatNum(calcVars[p])] if p in calcVars else [p.replace('.', ',')]
                        for v in vals: res[step] = v; step += 1; lastLightVal = v
                continue
            if line.startswith('light('):
                p = line[6:line.find(')')].replace('*', '').strip()
                vals = repeatVars[p] if p in repeatVars else [formatNum(calcVars[p])] if p in calcVars else [p.replace('.', ',')]
                for v in vals: res[step] = v; step += 1; lastLightVal = v
        if not res: return
        bars = "".join([f'<div style="display:inline-block;width:10px;margin-right:2px;text-align:center;"><div style="height:{40-int(float(v.replace(",","."))*40)}px;width:10px;"></div><div style="height:{int(float(v.replace(",","."))*40)}px;width:10px;background-color:#00ffcc;border-radius:2px;"></div><div style="font-size:9px;color:#888;margin-top:3px;">{s}</div></div>' for s, v in res.items() if v != "stop"])
        view.add_phantom("lux_live", sublime.Region(view.text_point(end_line_idx + 1, 0)), f'<body style="padding:10px;background-color:#111;border-radius:4px;margin-top:5px;"><div style="color:#00ffcc;font-weight:bold;font-size:11px;margin-bottom:5px;">LuxScript Live Output:</div><div style="white-space:nowrap;">{bars}</div></body>', sublime.LAYOUT_BELOW)