diff options
| author | eunhhu <[email protected]> | 2026-09-30 15:29:20 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-30 15:29:20 +0100 |
| commit | 72ecae6b6eb1365e722bd6d45acae8a5ccb74b23 (patch) | |
| tree | 3b49bc61da3cee795afdc335bbb149b7df86649e | |
| parent | 8fc6f35b30642f3a8ebbd7f5f47b70195c8ffea1 (diff) | |
| download | vega-72ecae6b6eb1365e722bd6d45acae8a5ccb74b23.tar.gz vega-72ecae6b6eb1365e722bd6d45acae8a5ccb74b23.zip | |
Show a bool as true or false, and make the examples' flags bools
aup and Pure now have a bool (Pure 016): a view or column may be one.
vega_text writes it as true or false, as a string's interpolation does, so
every surface shows the same words: the CLI, the TUI's cells, speech and
the web surface's JSON (a value's text) and page. An app that wants other
words picks them with a conditional (if t.done { "done" } else { "" }).
The flags of the examples are bools: todo's done and urgent, today's done,
the stopwatch's running. vega.when takes the bool as it took the number.
bools checks a bool field and a bool column on the CLI, the TUI, speech
and the web surface: true and false, never 1 and 0.
| -rw-r--r-- | docs/design/001-first-component.md | 3 | ||||
| -rw-r--r-- | examples/stopwatch.aup | 2 | ||||
| -rw-r--r-- | examples/today.aup | 2 | ||||
| -rw-r--r-- | examples/todo.aup | 4 | ||||
| -rw-r--r-- | surfaces/screen.c | 7 | ||||
| -rw-r--r-- | tests/check.py | 58 |
6 files changed, 65 insertions, 11 deletions
diff --git a/docs/design/001-first-component.md b/docs/design/001-first-component.md index d3ba7e6..9e1ef80 100644 --- a/docs/design/001-first-component.md +++ b/docs/design/001-first-component.md @@ -62,6 +62,9 @@ Tab이 키 모드로 바꾸면 글자·숫자·Space가 `KeyA`·`Digit0`·`Space **값이 보이는 방식.** 값은 제 자리 안에서 제 글자로 보인다. 화면에 작용할 글자만 예외다(Pure `docs/design/015-boundary-meaning.md`가 정한 값의 뜻의 화면 쪽이다). +- 수는 Pure의 가장 짧은 글자로, bool은 `true`나 `false`로 보인다. 보간(`"{done}"`)과 같은 글자다. 다르게 보이고 + 싶은 앱은 조건식으로 글을 고른다(`if t.done { "완료" } else { "" }`). + - 제어 문자(C0)와 DEL은 제어 그림(␀…␟, ␡)으로, C1 제어는 �로, 줄과 문단의 구분자(U+2028, U+2029)는 로 보인다 (`vega_visible`). CLI, TUI, 픽셀, 웹 페이지가 모두 같다. 값은 제 줄을 끊지 못한다. - 터미널의 칸(TUI, CLI)에서는 뒤따르는 글줄을 뒤집을 제어(방향 임베딩·오버라이드·격리, U+202A–202E, U+2066–2069)도 diff --git a/examples/stopwatch.aup b/examples/stopwatch.aup index cd075b0..d5408a0 100644 --- a/examples/stopwatch.aup +++ b/examples/stopwatch.aup @@ -6,7 +6,7 @@ record Lap { at = 0 } -state running = 0 +state running = false state started = 0 state elapsed = 0 state laps: list of Lap diff --git a/examples/today.aup b/examples/today.aup index e5db53b..65e533f 100644 --- a/examples/today.aup +++ b/examples/today.aup @@ -5,7 +5,7 @@ use vega record Task { title: text - done = 0 + done = false } state tasks: list of Task diff --git a/examples/todo.aup b/examples/todo.aup index f1e3825..57c6954 100644 --- a/examples/todo.aup +++ b/examples/todo.aup @@ -4,8 +4,8 @@ use vega record Task { title: text - done = 0 - urgent = 0 + done = false + urgent = false } state tasks: list of Task diff --git a/surfaces/screen.c b/surfaces/screen.c index f079bd5..51181a5 100644 --- a/surfaces/screen.c +++ b/surfaces/screen.c @@ -163,10 +163,13 @@ bool vega_text(PureApp *app, uint32_t view, size_t row, char out[VEGA_TEXT], siz ++evaluations; *length = 0; out[0] = 0; - if (m->view_type[view] == PURE_VIEW_NUM) { + if (m->view_type[view] == PURE_VIEW_NUM || m->view_type[view] == PURE_VIEW_BOOL) { double value; if (!(column ? pure_app_cell(app, view, row, &value) : pure_app_view(app, view, &value))) return false; - *length = pure_format_number(value, out); + if (m->view_type[view] == PURE_VIEW_BOOL) { /* a bool is written true or false, as a string shows it */ + *length = value ? 4 : 5; + memcpy(out, value ? "true" : "false", *length); + } else *length = pure_format_number(value, out); out[*length] = 0; return true; } diff --git a/tests/check.py b/tests/check.py index 4f87d20..5b37646 100644 --- a/tests/check.py +++ b/tests/check.py @@ -95,7 +95,7 @@ class Todo: self.at = text return True if name == 'add': - self.tasks.append({'title': text, 'done': 0, 'urgent': 0}) + self.tasks.append({'title': text, 'done': False, 'urgent': False}) self.at = len(self.tasks) - 1 return True last = max(len(self.tasks) - 1, 0) @@ -103,8 +103,8 @@ class Todo: return False if name == 'up': self.at = max(self.at - 1, 0) elif name == 'down': self.at = min(self.at + 1, last) - elif name == 'toggle': self.tasks[self.at]['done'] = int(not self.tasks[self.at]['done']) - elif name == 'urgent': self.tasks[self.at]['urgent'] = int(not self.tasks[self.at]['urgent']) + elif name == 'toggle': self.tasks[self.at]['done'] = not self.tasks[self.at]['done'] + elif name == 'urgent': self.tasks[self.at]['urgent'] = not self.tasks[self.at]['urgent'] elif name == 'drop': del self.tasks[self.at] self.at = min(self.at, max(len(self.tasks) - 1, 0)) @@ -527,7 +527,7 @@ def split(vega, module, work, seeds, steps=200): if roll < 0.3: word = rng.choice(WORDS) script.append('text ' + (word.encode().hex() or '-')) - tasks.append({'title': word, 'done': 0}) + tasks.append({'title': word, 'done': False}) at = len(tasks) - 1 elif roll < 0.5: name, rows = rng.choice([('open', opened), ('done', closed)]) @@ -539,7 +539,7 @@ def split(vega, module, work, seeds, steps=200): script.append(f'key {key}') if key == 'ArrowUp': at = max(at - 1, 0) elif key == 'ArrowDown': at = min(at + 1, max(len(tasks) - 1, 0)) - elif tasks: tasks[at]['done'] = int(not tasks[at]['done']) + elif tasks: tasks[at]['done'] = not tasks[at]['done'] if rng.random() < 0.3: script.append('show') opened = [i for i, t in enumerate(tasks) if not t['done']] @@ -1898,6 +1898,53 @@ def screen_meaning(vega, aup, work): return {'values': len(SCREEN_TEXTS), 'surfaces': 4} +BOOL_APP = """use vega +record Row { + n = 0 +} +state lit = false +state rows: list of Row +input flip = key Space +input add = text +on flip.down { lit = !lit } +on add { rows.append(Row { n: add.chars }) } +view shown = lit +view sizes = each r in rows { + n = r.n + over = r.n > 2 +} +""" + + +def bools(vega, aup, work): + """A bool shows as true or false on every surface (the CLI, the TUI's + cells, speech and the web surface's JSON), as a string shows it: never + as 1 or 0.""" + source, module = work / 'bools.aup', work / 'bools.pmod' + source.write_text(BOOL_APP) + built = run(aup, 'build', source, '-o', module, env=dict(os.environ, AUP_PATH=str(ROOT / 'lib'))) + assert built.returncode == 0, built.stderr + script = 'show\nkey Space\ntext 61\ntext 61626364\nshow\n' # a has one character, abcd four + out = run(vega, 'cli', module, stdin=script).stdout.splitlines() + assert out == ['shown: false', 'sizes (0)', ' n over', 'shown: true', 'sizes (2)', ' n over', '> 1 false', + ' 4 true'], out + dump = run(vega, 'tui', module, '--dump', '30x8', stdin=script).stdout.splitlines() + assert all(line in dump for line in ['|shown false\tmuted', '|shown true\tmuted', '>> 1 false', '| 4 true']), dump + said = run(vega, 'say', module, stdin=script).stdout.splitlines() + assert all(line in said for line in ['shown: false.', 'shown: true.', 'Item 1 of 2: n 1, over false.']), said + surface = WebSurface(vega, module) + try: + surface.call('POST', '/key', 'Space') + for text in ('a', 'abcd'): surface.call('POST', '/text', text) + screen = json.loads(surface.call('GET', '/screen?rows=5')[1]) + finally: + surface.stop() + assert screen['fields'] == [{'name': 'shown', 'text': 'true'}], screen['fields'] + table = screen['parts'][0] + assert table['columns'] == ['n', 'over'] and [item['cells'] for item in table['items']] == [['1', 'false'], ['4', 'true']], table + return len(out) + len(dump) + len(said) + + def main(): parser = argparse.ArgumentParser() parser.add_argument('--vega', type=Path, required=True) @@ -1928,6 +1975,7 @@ def main(): report['board_rows_across_hosts'] = hosts(vega, args.serve.resolve(), modules['board'], work) report['hot_swap_lines'] = hot_swap(vega, aup, work) report['split_list_lines'] = split(vega, modules['today'], work, range(args.seeds)) + report['bool_lines'] = bools(vega, aup, work) report['painted_frames'], report['first_paint_bytes'], report['later_paint_bytes'] = \ painting(vega, modules['todo'], range(args.seeds), [(40, 12), (24, 9), (80, 30)]) report['web_screens'] = web(vega, modules['todo'], work, range(args.seeds)) |
