diff --git a/test.py b/test.py index 481cc10..9bc3f0a 100644 --- a/test.py +++ b/test.py @@ -1,9 +1,97 @@ -def main(): - print("hello world") - x = 50 +import random +from typing import Any, Dict, List - for i in range(x): - print(i) + +class Employee: + def __init__(self, name: str, age: int, skills: List[str]): + self.name = name + self.age = age + self.skills = skills + self.projects: Dict[str, Dict[str, Any]] = {} + + def add_project(self, project_name: str, details: Dict[str, Any]): + self.projects[project_name] = details + + def __repr__(self): + return f"" + + +class Company: + def __init__(self, name: str): + self.name = name + self.employees: List[Employee] = [] + + def hire_employee(self, employee: Employee): + self.employees.append(employee) + + def list_employees(self): + return [e.name for e in self.employees] + + def employee_summary(self) -> Dict[str, Any]: + summary = {} + for e in self.employees: + summary[e.name] = {"age": e.age, "skills": e.skills, "projects": e.projects} + return summary + + +def random_employee() -> Employee: + names = ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank"] + skills_pool = ["Python", "Go", "Rust", "JavaScript", "SQL", "Docker"] + name = random.choice(names) + age = random.randint(22, 45) + skills = random.sample(skills_pool, k=random.randint(1, 4)) + return Employee(name, age, skills) + + +def generate_company(name: str, num_employees: int) -> Company: + company = Company(name) + for _ in range(num_employees): + emp = random_employee() + # assign some random projects + for pid in range(random.randint(1, 3)): + proj_name = f"Project-{pid+1}" + emp.add_project( + proj_name, + { + "budget": random.randint(1000, 10000), + "deadline": f"2026-0{random.randint(1,9)}-{random.randint(10,28)}", + "tasks": [f"Task-{i+1}" for i in range(random.randint(1, 5))], + }, + ) + company.hire_employee(emp) + return company + + +def main(): + my_company = generate_company("TechCorp", 5) + + print("All employees:") + for emp in my_company.employees: + print(emp) + + summary = my_company.employee_summary() + print("\nEmployee Summary Dictionary:") + for name, info in summary.items(): + print(f"{name}: {info}") + + # Access nested structures + print("\nAccessing nested info:") + for emp in my_company.employees: + for proj, details in emp.projects.items(): + print( + f"{emp.name}'s {proj} budget is {details['budget']} with tasks {details['tasks']}" + ) + + # Filter employees with Python skill + pythonistas = [e.name for e in my_company.employees if "Python" in e.skills] + print(f"\nEmployees with Python skill: {pythonistas}") + + # Update project budget for first employee + if my_company.employees: + first = my_company.employees[0] + for proj in first.projects: + first.projects[proj]["budget"] += 500 + print(f"\nUpdated {first.name}'s projects: {first.projects}") if __name__ == "__main__": diff --git a/ui/model.go b/ui/model.go index a0f4c5c..eb72a0e 100644 --- a/ui/model.go +++ b/ui/model.go @@ -20,11 +20,13 @@ type Model struct { listenBridge chan string listenBridgeExecutionsStopped chan bridge.ExecutionPoint + currLocals map[string]any currExecutionPoint bridge.ExecutionPoint messages []string stdoutOutput viewport.Model codeViewer viewport.Model + localsViewer viewport.Model cursor int breakpoints map[string][]int @@ -36,6 +38,7 @@ func NewModel(b *bridge.Bridge, file string, text string) Model { stdoutOutput := viewport.New(0, 0) codeViewer := viewport.New(0, 0) + localsViewer := viewport.New(0, 0) return Model{ currentFile: file, @@ -46,6 +49,7 @@ func NewModel(b *bridge.Bridge, file string, text string) Model { listenBridge: c, listenBridgeExecutionsStopped: c2, + currLocals: make(map[string]any), currExecutionPoint: bridge.ExecutionPoint{ File: file, Line: 0, @@ -56,6 +60,7 @@ func NewModel(b *bridge.Bridge, file string, text string) Model { cursor: 0, codeViewer: codeViewer, stdoutOutput: stdoutOutput, + localsViewer: localsViewer, } } @@ -73,6 +78,7 @@ func ListenBridgeExecutionsStopped(ch <-chan bridge.ExecutionPoint) tea.Cmd { } } +type LocalsMsg map[string]any type ExecutionStoppedMsg bridge.ExecutionPoint type StdoutMsg string diff --git a/ui/update.go b/ui/update.go index 5f5bd79..8e5e81c 100644 --- a/ui/update.go +++ b/ui/update.go @@ -21,12 +21,27 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, ListenBridge(m.listenBridge) case ExecutionStoppedMsg: m.currExecutionPoint = bridge.ExecutionPoint(msg) - return m, ListenBridgeExecutionsStopped(m.listenBridgeExecutionsStopped) + return m, tea.Batch(ListenBridgeExecutionsStopped(m.listenBridgeExecutionsStopped), m.GetLocals()) + case LocalsMsg: + m.currLocals = map[string]any(msg) + m.localsViewer.SetContent(strings.Join(flattenDict(m.currLocals, 0), "\n")) } return m, nil } +func (m Model) GetLocals() tea.Cmd { + return func() tea.Msg { + vars, err := m.bridge.Locals() + if err != nil { + slog.Error("couldnt get vars", "error", err) + return nil + } + + return LocalsMsg(vars) + } +} + func (m Model) UpdateWindowSize(msg tea.WindowSizeMsg) (tea.Model, tea.Cmd) { m.width = msg.Width m.height = msg.Height @@ -37,9 +52,12 @@ func (m Model) UpdateWindowSize(msg tea.WindowSizeMsg) (tea.Model, tea.Cmd) { m.codeViewer.Width = msg.Width m.codeViewer.Height = editorHeight - m.stdoutOutput.Width = msg.Width + m.stdoutOutput.Width = msg.Width / 2 m.stdoutOutput.Height = outputHeight + m.localsViewer.Width = msg.Width / 2 + m.localsViewer.Height = outputHeight + m.stdoutOutput.SetContent(strings.Join(m.messages, "")) return m, nil @@ -53,7 +71,7 @@ func (m Model) HandleKeyMsg(key tea.KeyMsg) (tea.Model, tea.Cmd) { m.codeViewer.ScrollUp(1) m.cursor = max(0, m.cursor-1) case "j": - m.codeViewer.ScrollUp(1) + m.codeViewer.ScrollDown(1) m.cursor = min(m.textLines-1, m.cursor+1) case "b": lineNumber := m.cursor + 1 diff --git a/ui/view.go b/ui/view.go index 05eeeb1..384b11b 100644 --- a/ui/view.go +++ b/ui/view.go @@ -14,6 +14,21 @@ import ( var panelStyle = lipgloss.NewStyle().Border(lipgloss.NormalBorder()).Padding(0, 1) +func flattenDict(m map[string]interface{}, indent int) []string { + lines := []string{} + prefix := strings.Repeat(" ", indent) + for k, v := range m { + switch val := v.(type) { + case map[string]interface{}: + lines = append(lines, fmt.Sprintf("%s%s:", prefix, k)) + lines = append(lines, flattenDict(val, indent+1)...) + default: + lines = append(lines, fmt.Sprintf("%s%s: %v", prefix, k, val)) + } + } + return lines +} + func (m Model) View() string { var buf bytes.Buffer lexer := lexers.Get("python") @@ -54,9 +69,15 @@ func (m Model) View() string { Width(m.codeViewer.Width - wFrame). Render(m.codeViewer.View()) - bottomPanel := panelStyle.Height(m.stdoutOutput.Height - hFrame). + bottomLeftPanel := panelStyle.Height(m.stdoutOutput.Height - hFrame). Width(m.stdoutOutput.Width - wFrame). Render(m.stdoutOutput.View()) + bottomRightPanel := panelStyle.Height(m.stdoutOutput.Height - hFrame). + Width(m.stdoutOutput.Width - wFrame). + Render(m.localsViewer.View()) + + bottomPanel := lipgloss.JoinHorizontal(lipgloss.Top, bottomLeftPanel, bottomRightPanel) + return lipgloss.JoinVertical(lipgloss.Top, topPanel, bottomPanel) }