EN /HU | Belépés

Commodore 64

Egy rubbs-boardot Commodore 64 is hívhat. A session.petscii! PETSCII-re állítja a vonalat (40×25, a C64 színei és billentyűi), miközben a felette lévő kód továbbra is UTF-8-at és ANSI-t ír; a BBS::Terminal megkérdezi a hívót, milyen géppel jött; a kétarcú board pedig ugyanazon a porton ad modern és C64-es arcot. Ez az oldal mindhármat bemutatja, a Feediát és az Alexandria BBS-t kidolgozott példaként használva, és leírja, hogyan kerül vonalra egy valódi vagy emulált C64. A BBS::Petscii a 0.15.0, a BBS::Terminal a 0.16.0 óta van meg.

Hogyan hív egy C64

A Commodore 64-nek nincs hálózati portja. Egy terminálprogrammal és egy modemmel éri el a telnetes boardot:

Elem Amit a hívók használnak
Terminálprogram CCGMS (CCGMS Future), StrikeTerm, vagy PC-n a SyncTERM C64 módban. PETSCII módban kell lennie (ASCII-fordítás nélkül), a kisbetűs karakterkészlettel.
Modem WiFi-modem (Zimodem, WiModem232 és társaik) a user porton vagy egy SwiftLink/Turbo232 cartridge mögött, SwiftLinken jellemzően 38400 baud, RTS/CTS. ATDT host:port-tal tárcsázzák, pl. ATDT teletypegames.org:2323.

Amit ebből a board lát:

  • Sima TCP, telnet nélkül. A WiFi-modem általában nyers TCP-kapcsolatot nyit. A C64 nem válaszol a board telnet-egyeztetésére, és ablakméretet (NAWS) sem jelent. Az egyeztetés bájtjai néhány kósza karakterként érkeznek meg a C64-re az első képernyő előtt, ez ártalmatlan.
  • PETSCII-bájtok mindkét irányban. A betűk az ASCII-hoz képest fel vannak cserélve, a színek és a kurzormozgások egybájtos vezérlőkódok, a RETURN egy magányos CR.
  • 40×25, és a C64 a 40. oszlop után magától sort tör.

Ezért tippel a rubbs C64-re, ha nem jön ablakméret, és ezért alakít át a PETSCII-vonal mindent egyes bájtokká escape-szekvenciák helyett.

Tesztelés VICE-szal

A VICE emulátor (x64sc) eljátssza a C64-et, a SwiftLinket és a modemvonalat: a VICE RS-232 eszköze közvetlenül egy TCP-hoszthoz kapcsolódik (a +rsdev1ip232 nyers TCP-t jelent, IP232-protokoll nélkül), terminálprogramnak pedig egy lemezképről induló CCGMS szolgál.

SH
# A C64 with a SwiftLink at $DE00 (NMI), its line connected to a board over TCP,
# CCGMS autostarted from a disk image; CCGMS's saved config sets the SwiftLink to 38400.
x64sc -silent +cart \
  -acia1 -acia1base 0xDE00 -acia1irq 1 -acia1mode 1 -myaciadev 0 \
  -rsdev1 127.0.0.1:2323 -rsdev1baud 38400 +rsdev1ip232 \
  -autostart ccgms.d64

Az -rsdev1-gyel a kapcsolat már a CCGMS indulásakor nyitva van, így nem kell ATDT; a board felteszi az első kérdését, és a RETURN elfogadja a tippet (C64). A bájtokat emulátor nélkül is ellenőrizheted: kapcsolódj egy kis szkripttel, ne küldj NAWS-t, és nézd meg, mi jön vissza (lásd a példát a BBS::Terminal résznél).

A PETSCII-vonal

session.petscii! és session.petscii?

Metódus Mit csinál
session.petscii! Mostantól a session egy C64-gyel beszél. A term_cols / term_rows értéket 40×25-re állítja, végleg kikapcsolja az egérjelentést (az enable_mouse ezután nem csinál semmit), nyersen elküldi a LOWERCASE, LOCK_CASE és CLEAR kódot (kisbetűs karakterkészlet, lezárt C= + Shift, üres képernyő), és egy BBS::Petscii::Encoder-t tesz a write elé. Másodszori hívásra nem csinál semmit.
session.petscii? true, miután a petscii! lefutott.

A petscii! után:

  • minden session.write az Encoderen megy át, így egy Flow, egy FakeOS, egy Application vagy egy door továbbra is UTF-8 szöveget ír ANSI-színekkel és kurzormozgással;
  • a readkey és a readline a C64 billentyűit dekódolja (lásd A C64 billentyűi lent);
  • a kliens NAWS-jelentése már nem változtat a méreten: a vonal 40×25 marad.

Egy 40 oszlopra rajzolt Flow, FakeOS vagy door változtatás nélkül fut C64-en; egy 80 oszlopra rajzolt tördelődik.

RUBY
require 'bbs'

BBS.configure do |c|
  c.flow = BBS::Flow.define do
    call do |_ctx, runner|
      session = runner.session
      session.petscii!
      session.write "\e[1;33mREADY.\e[0m\r\n"
      session.write "#{session.term_cols}x#{session.term_rows}, petscii: #{session.petscii?}\r\n"
      nil
    end
  end
end

BBS.start

A BBS::Petscii konstansai

Képernyő- és vezérlőkódok

A konstansok a PETSCII-kódok egykarakteres UTF-8 stringként (a C0/C1 kódpontok), így közvetlenül beírhatók egy stringbe: a "#{BBS::Petscii::YELLOW}READY." sárga a C64-en.

Konstans Kód Jelentés
COLS, ROWS 40, 25 A C64 szöveges képernyője.
CLEAR 0x93 Képernyőtörlés, kurzor a bal felső sarokba.
HOME 0x13 Kurzor a bal felső sarokba.
UP, DOWN, LEFT, RIGHT 0x91, 0x11, 0x9d, 0x1d Kurzormozgás.
RVS_ON, RVS_OFF 0x12, 0x92 Inverz be és ki. A RETURN is kikapcsolja az inverzet.
DEL 0x14 Törlés (backspace) a C64-en.
BELL 0x07 Csengő.
LOWERCASE, UPPERCASE 0x0e, 0x8e Váltás a kisbetűs (szöveges) vagy a nagybetűs (grafikus) karakterkészletre.
LOCK_CASE 0x08 Lezárja a karakterkészletet, így a C= + Shift már nem vált. Ez az ASCII backspace-e, és az Encoder a 0x08-at kurzor-balra alakítja: nyersen küldd (a petscii! így tesz).
CONTROLS tömb A vezérlőbájtok, amelyeket az Encoder változatlanul továbbad a C64-nek.
DEFAULT LIGHT_GREY A sima szöveg színe (\e[0m).

Színek

A C64-nek 16 szövegszíne van. Mindegyik írható közvetlenül, a legtöbb ANSI-ból is elérhető.

Konstans Kód Az ANSI, ami ezt adja
WHITE 0x05 \e[1;37m, \e[97m
RED 0x1c \e[31m
GREEN 0x1e \e[32m
BLUE 0x1f \e[34m
ORANGE 0x81 \e[33m (sötétsárga)
BLACK 0x90 (nincs: írd a konstanst)
BROWN 0x95 (nincs: írd a konstanst)
LIGHT_RED 0x96 \e[1;31m, \e[91m
DARK_GREY 0x97 \e[30m, \e[1;30m, \e[90m (a fekete sötétszürke: egy fekete-szürke door is olvasható maradjon a C64 fekete képernyőjén)
GREY 0x98 \e[2m, \e[2;37m (halvány)
LIGHT_GREEN 0x99 \e[1;32m, \e[92m
LIGHT_BLUE 0x9a \e[1;34m, \e[94m
LIGHT_GREY 0x9b \e[37m, \e[0m (az alapértelmezett)
PURPLE 0x9c \e[35m, \e[1;35m
YELLOW 0x9e \e[1;33m, \e[93m
CYAN 0x9f \e[36m, \e[1;36m

A COLORS mind a 16-ot felsorolja; az ANSI_DARK és az ANSI_BRIGHT az ANSI-leképezés két sora (0–7. index = fekete, piros, zöld, sárga, kék, magenta, cián, fehér). A félkövér (1) a világos sort választja. A háttérszínek (40–47) és a 256 színű / truecolor kódok (38;5;n, 38;2;r;g;b, 48;…) elvesznek: a C64-terminál hátterét a terminálprogram adja.

Az Encoder: mi lesz abból, amit írsz

A BBS::Petscii::Encoder#encode(data) egy stringet PETSCII-bájtokká alakít (bináris string). A session hívásonként egy Encodert tart, mert az Encodernek állapota van: a kurzor oszlopa, az aktuális szín, az inverz mód, és a két írás közé eső, félbevágott escape-szekvencia.

Bemenet Kimenet a C64-en
A–Z / a–z PETSCII-módra felcserélve: A → 0xc1, a → 0x41, így a kisbetűs készletben helyes kis- és nagybetűként jelennek meg.
Számjegyek, szóköz, !"#$%&'()*+,-./:;<=>?@[] Változatlanul.
Keretrajzoló ─│┌┐└┘├┤┬┴┼ (szimpla, dupla, vastag, lekerekített) A C64 vonalas karakterei. A kisbetűs karakterkészletben nincs lekerekített sarok, ott a ╭╮╰╯ szögletes ┌┐└┘-ként látszik; a nagybetűs (grafikus) készletben megvan (Petscii::ROUNDED_CORNERS, a Petscii::Canvas rajzolja).
█ Inverz szóköz. A ▀ ▐ inverz félblokk, a ▄ ▌ ▁ ▔ a C64 saját karaktere; a ░▒▓ egy sakktábla-minta, a ▖▗▘▝▚ a C64 negyedblokkjai.
£ ← ↑ ✓ A C64 saját £, ←, ↑ és pipa karaktere.
\ { } ~ ^ _ \| és ` | /, (, ), -, ↑, aláhúzás-karakter, függőleges vonal, '.
Tipográfia – — ‘ ’ “ ” … · • ● ◄ ► → × ° A legközelebbi ASCII: -, ', ", ..., ., *, <, >, x, o.
Ékezetes betűk á é ő ű Ä A betű ékezet nélkül (Unicode NFKD, a jelek elhagyva): á → a, Ő → O. ß → ss, π → pi.
Minden más (€, emoji, CJK) ?.
\r\n Egy RETURN (0x0d).
Magában álló \n Egy RETURN.
Magában álló \r Vissza ugyanannak a sornak az elejére (RETURN + kurzor fel).
\t Két szóköz.
\b (0x08) Kurzor balra.
\f (0x0c), \e[2J CLR.
\e[H, \e[ROW;COLH, \e[…f HOME, majd annyi DOWN és RIGHT.
\e[nA … \e[nD n × UP, DOWN, RIGHT, LEFT.
\e[nG RETURN, UP, majd n−1 RIGHT (ugyanannak a sornak az n. oszlopa).
\e[…m Szín és inverz (7 / 27), lásd a színtáblát.
Egyéb escape-szekvenciák (\e[K, \e[?25l, \e(B, …) Elvesznek, akkor is, ha egy írás kettévágja őket.
PETSCII-vezérlőkódok (a konstansok) Átmennek.
Egyéb C0/C1 bájtok, DEL (0x7f) Elvesznek.

A 40 oszlopos tördelés. Az Encoder számolja az oszlopokat. Egy pontosan 40 karakteres sornál a C64 magától sort tör; az utána jövő \r\n-t ilyenkor lenyeli, így nem keletkezik alatta üres sor.

Az érvénytelen UTF-8 kódolás előtt ?-re cserélődik.

Valódi bájtok, ruby -Ilib-bel a rubbs 1.0.0-n:

RUBY
require 'bbs'

enc = BBS::Petscii::Encoder.new
hex = ->(s) { s.bytes.map { |b| format('%02x', b) }.join(' ') }

puts hex.(enc.encode("Hello, World!\r\n"))
# c8 45 4c 4c 4f 2c 20 d7 4f 52 4c 44 21 0d
puts hex.(enc.encode("\e[1;33mREADY.\e[0m\r\n"))
# 9e d2 c5 c1 c4 d9 2e 9b 0d          (sárga, READY., világosszürke)
puts hex.(enc.encode("┌──┐\r\n│ok│\r\n└──┘\r\n"))
# b0 c0 c0 ae 0d dd 4f 4b dd 0d ad c0 c0 bd 0d
puts hex.(enc.encode("Árvíztűrő — 3…\r\n"))
# c1 52 56 49 5a 54 55 52 4f 20 2d 20 33 2e 2e 2e 0d
puts hex.(enc.encode("\e[2J\e[3;5Hx"))
# 93 13 11 11 1d 1d 1d 1d 58          (CLR, HOME, 2 x DOWN, 4 x RIGHT, x)
puts hex.(enc.encode("€ ☺"))
# 3f 20 3f
puts hex.(BBS::Petscii::Encoder.new.encode('a' * 40 + "\r\nb"))
# 41 negyvenszer, majd 42: a teli sor után nincs RETURN

e2 = BBS::Petscii::Encoder.new
puts hex.(e2.encode("\e[1;3")) + ' | ' + hex.(e2.encode("2mGo"))
#  | 99 c7 4f                          (a szekvencia a második írásban fejeződik be: világoszöld)

BBS::Petscii.bytes és BBS::Petscii.key

Metódus Mit csinál
BBS::Petscii.bytes(codes) Egy PETSCII-kódpontokból (pl. a konstansokból) álló string bájtjai, bináris stringként. Ezzel küldhetsz PETSCII-t az Encoder megkerülésével.
BBS::Petscii.key(byte) Egy C64-ről jött bájt billentyűként, ahogy a readkey adja vissza: Symbol, egykarakteres String, vagy nil, ha a bájt nem billentyű. PETSCII-vonalon a readkey és a readline ezt használja. A billentyűbájtok egyetlen táblában vannak, a Petscii::KEYS-ben (bájt → billentyű); a régi KEY_* konstansok az 1.0-ban megszűntek.
RUBY
BBS::Petscii.bytes("#{BBS::Petscii::LOWERCASE}#{BBS::Petscii::LOCK_CASE}#{BBS::Petscii::CLEAR}")
# => "\x0E\b\x93"   (0e 08 93: what petscii! sends first)

[0x41, 0xc1, 0x0d, 0x14, 0x03, 0x5f, 0x85, 0x8c, 0x5c, 0xa0, 0x93].map { |b| BBS::Petscii.key(b) }
# => ["a", "A", :enter, :backspace, :escape, :escape, :f1, :f8, "£", " ", nil]

Átkapcsolt sessionön nyers PETSCII-t (az Encoder kihagyásával) a socketre írva küldhetsz: session.line.write(BBS::Petscii.bytes(BBS::Petscii::LOCK_CASE)).

A C64 billentyűi

PETSCII-vonalon a readkey ezeket adja:

C64-billentyű Bájt readkey
Betű 0x41–0x5a kisbetűs String ("a")
Shift + betű 0xc1–0xda (vagy 0x61–0x7a) nagybetűs String ("A")
Számjegyek, szóköz, írásjelek 0x20–0x40, [, ] az adott karakter
£ 0x5c "£"
↑ 0x5e "^"
Shift + szóköz 0xa0 " "
RETURN 0x0d :enter
INST/DEL 0x14 :backspace
Kurzor le / fel 0x11 / 0x91 :down / :up
Kurzor jobbra / balra 0x1d / 0x9d :right / :left
CLR/HOME 0x13 :home
RUN/STOP 0x03 :escape
← (bal felső billentyű) 0x5f :escape
F1 … F8 0x85, 0x89, 0x86, 0x8a, 0x87, 0x8b, 0x88, 0x8c :f1 … :f8
Minden más (színbillentyűk, CLR, …) kimarad

C64-en nincs :tab, nincs :ctrl_…, és nincs egér. Egy mindkét gépen működő board a RETURN-re, a kurzorbillentyűkre, a betűkre és a számjegyekre építsen, és a :escape-et vegye „vissza”-nak (a RUN/STOP és a ← is ezt adja).

A readline(mask:) PETSCII-vonalon ugyanezeket a billentyűket fogadja, PETSCII-ben visszhangoz (vagy a maszkot), és az INST/DEL egy teljes karaktert töröl. RETURN-re UTF-8 stringként adja vissza a sort.

BBS::Terminal: milyen gép hív

A kétarcú boardnak az első képernyője előtt tudnia kell, hogy ANSI-t vagy PETSCII-t beszéljen. A BBS::Terminal (lib/bbs/terminal.rb) ez az első kérdés, közösen minden C64-es arcú boardnak.

TXT
MY BOARD

1 - MODERN (ANSI/XTERM, 256 COLORS)
2 - COMMODORE 64 (PETSCII, 40 COLUMNS)

YOUR TERMINAL [2]:
  • Sima ASCII, nagybetűkkel. Egy ANSI-terminál és egy C64 bármelyik karakterkészlettel olvashatóan írja ki (a kisbetűs készletben a nagybetűk kisbetűként látszanak). Minden sor megnevezi, mi megy a vonalon.
  • Az alapértelmezés a tipp, szögletes zárójelben.
  • Egy billentyű csak kijelöl, a RETURN véglegesít. A soros módú telnet a számjegyet és a RETURN-t együtt küldi, és a vonalon maradt RETURN az első képernyőn kötne ki. Megváltozott választásnál a prompt új sorban újra megjelenik (a két gép máshogy lép vissza egy karaktert). A Backspace (vagy a C64 DEL-je, ami a vonal átkapcsolása előtt :ctrl_t-ként érkezik) törli a választást.
  • Ha nem jön válasz 60 másodpercig, a választás, vagy ha nincs, a tipp érvényes.
Konstans Érték Jelentés
Terminal::SETTLE 1.5 Ennyi másodpercig vár a guess a telnet-válaszokra.
Terminal::WAIT 60 Ennyi másodpercig vár a kérdés billentyűre, mielőtt az alapértelmezést veszi.
Terminal::FACES hash Arconként: a számjegy, a felirat és a kijelölő billentyűk.
Arc Számjegy Kijelölő billentyűk
:modern 1 1, a, A, m, M
:petscii 2 2, c, C, p, P

Terminal.guess(session)

RUBY
BBS::Terminal.guess(session)   # => :modern or :petscii

Meghívja a session.settle(timeout: 1.5)-öt: megvárja a kliens ablakméretét, és eldobja, amit közben gépel. A 40 oszlopnál szélesebb jelentett ablak :modern; a 40 vagy kevesebb oszlop, vagy ha semmilyen jelentés nem jön (a WiFi-modem mögötti C64 sima TCP-t beszél), :petscii.

Terminal.flow(title:, modern:, petscii:)

RUBY
BBS::Terminal.flow(title: 'My Board', modern: MODERN_FLOW, petscii: PETSCII_FLOW)   # => a BBS::Flow

Az egész első lépés egy Flow-ként, a config.flow-ba téve:

  1. felteszi a kérdést (a Terminal::Question az 1.0 óta privát: kérdezni csak a Terminal.flow-val lehet); megszakadt vonalnál véget ér a hívás;
  2. :petscii-nél meghívja a session.petscii!-et; :modern-nél a session.enable_mouse-t, de csak ha a BBS.config.mouse be van kapcsolva (a 0.16.1 óta);
  3. lefuttatja az adott arc Flow-ját ugyanazzal a contexttel (ctx[:session_id] és minden, ami előtte bekerült).

Az egér kapcsolása. Az egérjelentés egy escape-szekvenciával indul (\e[?1002h\e[?1006h), ami a C64-en szemét lenne. Ezért a kétarcú board config.mouse = true-t állít (a modern arc egeret akar) és config.mouse_on_connect = false-t (ne kapcsolja be a kérdés előtt); a Terminal.flow a modern választás után kapcsolja be.

RUBY
BBS.configure do |config|
  config.mouse            = true
  config.mouse_on_connect = false   # the mouse's escape sequence is garbage on a C64
  config.flow = BBS::Terminal.flow(title: 'My Board', modern: MODERN, petscii: PETSCII)
end

Amit a vonal visz (egy NAWS nélkül kapcsolódó szkript, majd RETURN):

TEXT
board → caller   ff fb 03 ff fb 01 ff fd 03 ff fd 1f          telnet: WILL SGA, WILL ECHO, DO SGA, DO NAWS
                 ...1.5 s, no NAWS from the caller...
board → caller   "\r\n\r\nMY BOARD\r\n\r\n1 - MODERN ...\r\n2 - COMMODORE 64 ...\r\n\r\nYOUR TERMINAL [2]: "
caller → board   0d                                           RETURN takes the guess
board → caller   32 0d 0a                                     "2", new line
board → caller   0e 08 93                                     petscii!: LOWERCASE, LOCK_CASE, CLEAR
                 ...the C64 face, in PETSCII...

A kétarcú board

Egy port, két arc: a hívó válaszol a Terminal kérdésére, és vagy

  • modern arcot kap — általában egy Application-t: ablakok, menüsor, egér, 80 vagy több oszlop, 256 szín; vagy
  • C64-es arcot — egy 40×25-ös PETSCII-képernyőt, ahogy a C64-es boardokon volt: inverz címsor, RETURN-re váró szövegoldalak, számozott listák, egybillentyűs menük.

A két arc a domain-kódon (adatok, service-ek) osztozik, a UI-ból semmin. A házi felépítés, ahogy a Feedia BBS, az Alexandria BBS és a Teletype BBS használja:

TEXT
bbs.rb                   BBS.configure + BBS::Terminal.flow(modern:, petscii:)
lib/domain/…             the data: feeds, Wikipedia, …   (no UI)
lib/ui/modern.rb         UI::Modern.flow(...)   → a BBS::Flow that runs an Application
lib/ui/petscii.rb        UI::Petscii.flow(...)  → a BBS::Flow with one call step
lib/ui/petscii/screen.rb UI::Petscii::Screen    → the 40×25 screen helpers

Feedia: a bekötés

bbs/feedia-bbs/bbs.rb (egy RSS-olvasó):

RUBY
require 'bbs'
require_relative 'lib/domain/feeds'
require_relative 'lib/domain/inbox'
require_relative 'lib/ui/modern'
require_relative 'lib/ui/petscii'

feeds = Feeds.load(ENV.fetch('FEEDIA_FEEDS', File.join(__dir__, 'config/feeds.yml')))
inbox = Inbox.new(path: ENV.fetch('FEEDIA_INBOX', File.join(__dir__, 'data/inbox.jsonl')),
                  webhook: ENV.fetch('FEEDIA_DISCORD_WEBHOOK', ''))

BBS.configure do |config|
  config.mouse            = true
  config.mouse_on_connect = false
  config.idle_seconds     = 600

  config.flow = BBS::Terminal.flow(title: 'Feedia', modern: UI::Modern.flow(feeds, inbox),
                                   petscii: UI::Petscii.flow(feeds, inbox))
end

BBS.start

Az Alexandria BBS (bbs/alexandria-bbs/bbs.rb, Wikipédia telnetvonalon) ugyanez, a feeds és az inbox helyett Wikipedia.new(...)-val és title: 'Alexandria BBS'-szel.

A PETSCII-arc: BBS::Petscii::Screen

A PETSCII-arc nem Application-t használ: sorokat ír, ahogy egy C64-es board tette. Egy ilyen board képernyője a rubbs része, a BBS::Petscii::Screen (0.29 óta); minden board a lib/ui/petscii/screen.rb-ben leszármaztat belőle, ha saját metódusok kellenek. Az ötletei:

Színek ANSI-ként. A képernyő ANSI-színeket ír, amelyeket a PETSCII-vonal a C64 színeivé alakít. A rubbs szélességszámoló segédei (a FrameBuffer.wrap_ansi, az egyetlen sortördelő, és a clip_ansi) ismerik az ANSI-t, a PETSCII-vezérlőkódokat viszont szövegnek számolnák, így ANSI-val a tördelés helyes marad. A BBS::Petscii::Colors C64-es nevet ad a színeknek: WH YE CY LG GR DG LB BL GN RD PU OR, az inverz be- és kikapcsolása RV/RO. Ezek az egyetlen paletta, a BBS::Ansi színeinek C64-es nevei (a YE a BBS::Ansi::BRIGHT_YELLOW, az LG a BBS::Ansi::GREY, a szöveg színe).

RUBY
module UI
  module Petscii
    BBS::Petscii::Colors.install(self)   # bare WH, YE, LG … in every class nested here

    class Screen < BBS::Petscii::Screen
      def banner(text) = puts(" #{YE}#{text}#{LG}")   # the board's own methods
    end
  end
end

A metódusai, mindegyik egy C64-es boardos szokás (alapból 40×25; a Screen.new(session, cols: 80, rows: 24) modern terminált is kiszolgál):

Metódus Mit csinál
cls Törli a képernyőt: C64-en CLR, modern terminálon ANSI.
title(text, right = '') Üres képernyő egy inverz cián címsor alatt, balra a text, jobbra a right (egy darabszám, egy nyelv), 39 oszlop szélesen.
say(text, color: LG) 38 oszlopra tördelt szöveg, egy szóközzel beljebb. A szín kulcsszó: say('Posted.', color: GN).
rule(color: DG) Vízszintes vonal, 39 oszlop.
key(timeout:) readkey, bontáskor IOError-t dob (így a call lépés csendben ér véget).
choose(prompt, keys, back: 'q') Egybillentyűs kérdés: a keys (kisbetűk) egyikére vár, a RUN/STOP és a ← a back-et adja, a billentyűt nagybetűvel visszhangozza.
ask(prompt, text:, mask:, max:) Egy BBS::Field-be gépelt sor, levágott szélekkel.
edit(text = '', title:, single_line: false, max: nil) A teljes képernyős BBS::Editor a képernyő méretében: mentéskor a szöveg, kilépéskor nil.
pause(text = 'return: back') Bármely billentyűre vár.
page(heading, lines, right:, wait:, numbers:) Képernyőnként (20 sor) mutatja a sorokat a címsor alatt; RETURN-re jön a következő, a q vagy a RUN/STOP korábban kilép; numbers: true mellett a címsorban ott a 2/5.
pick(heading, items, empty:, right:, commands:) { label } Számozott BBS::Selector.list a címsor alatt: kurzorral vagy a számmal választ, aztán RETURN; q, ← vagy RUN/STOP esetén nil.
menu(items, back:) Egy BBS::Selector a kurzornál.
actions(*pairs) Billentyűk egy sorban, kurzoros menüként: screen.actions(%w[r read], %w[q back]).
plain(text) C64-en BBS::Petscii.plain(text): a tipográfiai jelek és az ékezetek ASCII-vé válnak, így a sor ott törik, ahol számolták.

A képernyő minden menüje BBS::Selector, az alapszíneivel, a BBS::Selector::COLORS-szal (a text key bar heading about hint szerepek, a paletta C64-es neveivel). Ha egy board más láblécet szeretne, ebbe fésüli bele a sajátját: BBS::Selector::COLORS.merge(hint: "#{CY}#{RV}").

A 0.x-ről az 1.0-ra egy C64-es arc három helyen változik: a say(text, GN) és a rule(DG) helyett say(text, color: GN) és rule(color: DG) kell; az editor(max, title) helyett edit(title: title, max: max).to_s (kilépéskor nil-t ad); a Petscii::Screen::MENU pedig megszűnt, ezért a colors: MENU elhagyható, a MENU.merge(…) helyére BBS::Selector::COLORS.merge(…) kerül. A Petscii::Screen.plain helyett BBS::Petscii.plain van. A teljes lista a gem UPGRADING.md-jében.

Az arc flow-ja egyetlen call lépés, amely az egész hívást viszi, és egy második, amely elköszön; az elköszönés elkapja a bontási hibákat, mert egy menü közben bontó hívó ne hagyjon backtrace-t maga után:

RUBY
def self.flow(feeds, inbox)
  BBS::Flow.define do
    call do |ctx, runner|
      Reader.new(feeds, inbox, Screen.new(runner.session), ctx).run
      nil
    end
    call do |_ctx, runner|
      C64.goodbye(Screen.new(runner.session))
      nil
    rescue IOError, Errno::EPIPE, Errno::ECONNRESET
      nil
    end
  end
end

A Reader maga a board: egy fejléc, egy F/S/W/Q menü, a feedek a pick-en át, egy elem a page-en át (a Markdownja BBS::Markdown.to_lines(body, width: 38, theme: {...})-val, a képernyő színeiben). Az Alexandria Proxy-ja ugyanilyen felépítésű: egy prompt, amely címet vár, a találatok a pick-en, egy szócikk szakaszai a page-en át.

Rajzolás 40 oszlopra. A logók inverz szóközökből állnak (RV + szóközök + RO), ezek mindkét gépen ugyanúgy látszanak; a keretrajzoló karakterek és a █ is rendben vannak, az Encoder leképezi őket. A képernyő a címsort és a vonalakat 39, a szöveget 38 oszlopon tartja; a pontosan 40 karakteres sor is működik, mert az Encoder lenyeli a C64 saját sortörése utáni RETURN-t.

Egy teljes kétarcú board

Egy kicsi, futtatható board: hírek, modern terminálon egy Application, C64-en a rubbs BBS::Petscii::Screen-je.

RUBY
require 'bbs'

NEWS = [
  ['Board opens', 'The board is open for callers from today. Call often, and tell your friends.'],
  ['PETSCII face', 'A Commodore 64 gets the same news on 40 columns, in PETSCII.']
].freeze

# The modern face: an Application with a mouse.
MODERN_APP = BBS::Application.define do
  theme BBS::Theme.synchronet
  body do
    NEWS.each_with_index do |(title, text), i|
      add BBS::Widgets::Label.new(text: "#{title}: #{text}", style_key: :text,
                                  bounds: BBS::Widget::Rect.new(3, 3 + i, 74, 1))
    end
  end
  status_hint('F10', 'Log off') { :halt }
end

MODERN = BBS::Flow.define do
  app MODERN_APP
end

# The PETSCII face: a 40x25 screen, the news as a numbered cursor menu.
PETSCII = BBS::Flow.define do
  call do |_ctx, runner|
    screen = BBS::Petscii::Screen.new(runner.session)
    while (item = screen.pick('my board', NEWS, right: 'q: log off', &:first))
      title, text = item
      screen.title(title)
      screen.say(text)
      screen.pause
    end
    nil
  end
end

BBS.configure do |config|
  config.mouse            = true
  config.mouse_on_connect = false
  config.idle_seconds     = 600
  config.flow = BBS::Terminal.flow(title: 'My Board', modern: MODERN, petscii: PETSCII)
end

BBS.start

A C64 oldalán a RETURN utáni első képernyő így kezdődik (rubbs 1.0):

TEXT
0e 08 93            petscii!: lowercase set, case locked, clear
93 9f 12 20 4d 59 20 42 4f 41 52 44 20 … 51 3a 20 4c 4f 47 20 4f 46 46 20 92 9b
                    CLEAR, cyan, RVS ON, " my board … q: log off ", RVS OFF, light grey
9f 12 20 31 20 c2 4f 41 52 44 20 4f 50 45 4e 53 20 … 92 9b 0d
                    the lit item: cyan, RVS ON, " 1 Board opens", RVS OFF
9e 20 32 20 9b d0 c5 d4 d3 c3 c9 c9 20 46 41 43 45 … 0d
                    yellow " 2 ", light grey "PETSCII face"

A PETSCII-arc más módjai

  • 40 oszlopra rajzolt Flow. Az Impostor BBS ugyanazt a BBS::Flow-t futtatja mindkét arcon, a PETSCII-arcon a screens/petscii/ 40 oszlopra rajzolt ERB-képernyőivel: Impostor::Petscii.flow(sessions: store).
  • FakeOS. Egy 40 oszlopba férő képernyőjű BBS::FakeOS változtatás nélkül fut PETSCII-vonalon.
  • Door. Egy 40 oszlopra rajzolt door C64-es arcról is működik; egy BBS::Gateway a PETSCII-hívót továbbadja egy másik boardnak, és mivel nem jelent ablakméretet, a túloldali kétarcú board C64-re tippel (lásd Doorok).

Lásd még