Files
Sprinter-SDCC/examples/mdview/PLAN_866.md
T
snark13 737c974400 Add mdview markdown viewer, reorganize tests/examples and libc layout
- Split tests/ (libc feature tests) and examples/ (real apps); shared
  app.mk in repo root, was examples/example.mk
- libc/io/* split into libc/{conio,env,errno,file,mouse,string,sys,
  time,video}/ — clearer module boundaries
- New examples/mdview/: markdown viewer (Phases 1-5 + light nested
  lists). Headers (H1-H4), HR, ulist/olist/quote with nesting via
  leading spaces, fenced code blocks, inline emphasis (bold/italic/
  underscore/code), wrap/unwrap mode with soft wrap (F2), horizontal
  pan (← →) with '>' truncation indicator
- libc additions: scroll() in conio (ESTEX SCROLL), strlwr/strupr,
  gets() test
- Makefile updates across tests/ for the new shared app.mk path

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-04 22:23:36 +03:00

22 KiB
Raw Blame History

« ­: ⥪áâ®¢ë© Markdown viewer ¤«ï Sprinter (examples/mdview)

Context

’¥á⮢ ï ªà㯭 ï § ¤ ç  - ¯à®¢¥à¨âì ­ èã libc ­  ­¥âਢ¨ «ì­®¬ interactive-¯à¨«®¦¥­¨¨ (¯®«­®íªà ­­ë© UI, ä ©«®¢ë© I/O, ¯ àá¥à).  à ««¥«ì­® ¤ áâ å®à®è¨© showcase ¯« âä®à¬ë ¨ ¯®¬®¦¥â ¢ëâ é¨âì ­¥¤®¤¥«ª¨ ¢ conio/io. Š®­¥ç­ ï 楫ì: viewer ¤«ï .md ä ©«®¢ á ¯®¤á¢¥âª®© ᨭ⠪á¨á , ­ ¢¨£ æ¨¥© ¯® ⥪áâã ¨ ¯®áâà ­¨ç­ë¬ áªà®««¨­£®¬.

Ž£à ­¨ç¥­¨ï v1 (§ ä¨ªá¨à®¢ ­ë ¯®«ì§®¢ â¥«¥¬):

  • POSIX file API (open/read/lseek/close); FILE*/fread/fgets - ­¥ ¨á¯®«ì§®¢ âì
  • Œ ªá¨¬ã¬ 16 KB ­  ®¤¨­ ä ©« (®¤­  EMM-áâà ­¨æ ); ¬­®£®áâà ­¨ç­ë© ०¨¬ - ¢ v2
  • ®¤á¢¥âª  ç¥à¥§ 梥â: **à §¬¥à § £®«®¢ª ** > 梥â èà¨äâ ; bold/italic > 梥â ä®­  (¬®­®è¨à¨­­ë© ä®­â ¡¥§ ¦¨à­®£®/ªãàᨢ­®£® ­ ç¥àâ ­¨ï)

€àå¨â¥ªâãà 

 áª« ¤ª  íªà ­  (80x32, ⥪áâ mode 0x03)

Row 0:   ³ mdview.md    L 1-30 / 142   21%       ³   < status bar (BG=blue, FG=white)
Row 1:   ³                                       ³
...      ³   document viewport (30 rows)         ³
Row 30:  ³                                       ³
Row 31:  ³ F1 Help                       F10 Exit³   < menu bar (BG=blue, FG=cyan)
  • Viewport = 30 áâப x 80 á⮫¡æ®¢.
  • Status / menu ७¤¥àïâáï ç¥à¥§ wrchar() (¡¥§  ¢â®-áªà®«« ), viewport - ç¥à¥§ LOCATE + ¯®á¨¬¢®«ì­ë© wrchar() (⮦¥ ¡¥§  ¢â®-áªà®«« , áâ ¢¨â ¨ char ¨ attr §  ®¤¨­ call).

 ¬ïâì

Memory mode: small - DSS ®â¢®¤¨â ¯®¤ ­ è ®¡à § ¤¢  ¡ ­ª  (W1 + W2) = 32 KB á㬬 à­® (CODE ¢ W1, DATA + STACK + HEAP ¢ W2). ⮣® ¤®«¦­® 墠â¨âì çâ®¡ë … § ¢®¤¨âì __banked ä㭪樨. W3 ®áâ ñâáï ¯®«­®áâìî ᢮¡®¤­ë¬ ¤«ï ¬ ¯¯¨­£  ¡®«ìè¨å ¡ãä¥à®¢:

W0 (0x0000-0x3FFF):  ESTEX   (system, untouchable)
W1 (0x4000-0x7FFF):  CODE                              (small mode page 1)
W2 (0x8000-0xBFFF):  DATA + STACK + HEAP               (small mode page 2)
W3 (0xC000-0xFFFF):  paged window - ¯¥à¥ª«îç ¥âáï ¬¥¦¤ã EMM-áâà ­¨æ ¬¨:
                       ÃÄÄ file page:  ¨á室­ë© ⥪áâ .md ä ©«  (16 KB)
                       ÀÄÄ cache page: ªíè ®âä®à¬ â¨à®¢ ­­ëå áâப  (Phase 3+)

®ç¥¬ã small + W3:

  • 32 KB ­  ª®¤+¤ ­­ë¥ á ¡®«ì訬 § ¯ á®¬ > ­¥â ¡ ­ª¨­£ 
  • W3 - áâ ­¤ àâ­ë© paged window, ¯®¤ ­¥£® ã ­ á 㦥 ¥áâì bank_io_w3 API
  • v2-à áè¨à¥­¨¥ (multi-page ä ©«ë >16 KB): ¯à®áâ® mem_alloc_pages(N) ¨ ¯¥à¥ª«î祭¨¥ áâà ­¨æ ¢ W3 ç¥à¥§ sprinter_page_w3()

‘â â¨ª¨ (¢ W2):

  • line_offset[MAX_LINES] - uint16_t ᬥ饭¨¥ ª ¦¤®© áâப¨ ¢ ä ©«®¢®© áâà ­¨æ¥ (4 KB ­  2048 áâப)
  • cache_tag[CACHE_N] - uint16_t ⥣ á«®â  (200 ¡ ©â ­  100 ᫮⮢, ¯®ï¢«ï¥âáï ¢ Phase 3)
  • filename[64], top_line, total_lines, file_size, file_blk, cache_blk - ¥¤¨­¨æë ¡ ©â

FILE_BUF: ((char*)0xC000) - 䨪á¨à®¢ ­­ ï  ¤à¥á æ¨ï ¢ W3 ¯®á«¥ ¬ ¯¯¨­£  ­ã¦­®© áâà ­¨æë.

®â®ª ¤ ­­ëå

main > open() > read() chunks 1KB > write to W1 (mapped EMM page) > close()
     > index_lines()  (®¤­® ᪠­¨à®¢ ­¨¥, § ¯®«­ï¥â line_offset[])
     > render_viewport()  +  main loop { getkey(); handle(); render_status(); render_viewport() }

’®­ª®áâì á read(): ESTEX READ § ¯¨á뢠¥â ¯® dst-㪠§ â¥«î ¢  ¤à¥á­®¬ ¯à®áâà ­á⢥ ¢ë§ë¢ î饣®. ®áª®«ìªã ¬ë ¬ ¯¯¨¬ EMM-áâà ­¨æã ¢ W3 (0xC000) „Ž ¢ë§®¢  read(), 㪠§ â¥«ì 0xC000+offset ¢ «¨¤¥­. …᫨ ¢ëïá­¨âáï çâ® BIOS âண ¥â W3 ¢® ¢à¥¬ï read (£à ä¨ç¥áª¨© ¢¨¤¥®¡ãä¥à ¯® 㬮«ç ­¨î ¢ W3 ¯à¨ £à ä¨ç¥áª¨å ०¨¬ å, ­® ¢ ⥪á⮢®¬ - ¤®«¦¥­ ¡ëâì ᢮¡®¤¥­) - fallback: ç¨â âì ¢ 1 KB ¡ãä¥à ¢ W2 ¨ ª®¯¨à®¢ âì ¢ W3 ç¥à¥§ bank_write_w3().


¥ «¨§ æ¨ï - ¯®íâ ¯­ ï

Phase 1 - Plain text viewer (MVP)

—â® à ¡®â ¥â:

  • ‡ £à㧪  ä ©«  (open/read/close) ¢ W1-áâà ­¨æã
  • ˆ­¤¥ªá æ¨ï áâப (LF / CRLF à §¤¥«¨â¥«¨)
  • Status bar: ¨¬ï ä ©« , L N-M / Total, ¯à®æ¥­â áªà®««¨­£ 
  • Menu bar: F1 Help F10 Exit
  •  ¢¨£ æ¨ï: ^/v (1 áâப ), PgUp/PgDn (30 áâப), Home/End (­ ç «®/ª®­¥æ), Esc/F10 (¢ë室), F1 (help screen)
  • Ž¡à¥§ª  áâப ¤«¨­­¥¥ 80 ᨬ¢®«®¢ (¡¥§ word-wrap)
  • –¢¥â : ⥪áâ ¡¥«ë© ­  çñà­®¬; status/menu - ¡¥«ë© ­  ᨭ¥¬

Šà¨â¨ç­ë¥ ä ©«ë:

  • examples/mdview/mdview.c - main, key loop, rendering, indexing (one-file MVP)
  • examples/mdview/Makefile
  • examples/mdview/SAMPLE.MD - â¥áâ®¢ë© markdown ä ©«

Phase 2 - Headers ¨ £®à¨§®­â «ì­ ï «¨­¨ï

MD ä¨ç¨:

  • # H1 > ïમ-¦ñ«âë© (COLOR_YELLOW = 14) ­  çñà­®¬
  • ## H2 > ïમ-£®«ã¡®© (COLOR_LBLUE = 11)
  • ### H3 > ïમ-§¥«ñ­ë© (COLOR_LGREEN = 10)
  • #### H4+ > á¥àë© (COLOR_GREY = 8)
  • --- / *** ­  ®â¤¥«ì­®© áâப¥ > «¨­¨ï 0xC4 (£®à¨§®­â «ì­ ï à ¬ª  ASCII) ¢® ¢áî è¨à¨­ã

Phase 3 - Inline emphasis

 àá¥à inline (per-line, runs ¢ ®¤­ã áâபã):

  • **bold** > ATTR_TEXT_BOLD
  • *italic* > ATTR_TEXT_ITALIC
  • _underscore_ > ATTR_TEXT_UNDERSORE
  • `code` > ATTR_TEXT_CODE
  • Œ àª¥àë **/*/_/` … ७¤¥àïâáï (áꥤ îâáï)

State machine: ®¤¨­  ªâ¨¢­ë© áâ¨«ì ®¤­®¢à¥¬¥­­® (¡¥§ ¢«®¦¥­­®áâ¨); ª®­ä«¨ªâãî騩 ¬ àª¥à ¯à¨ ç㦮¬  ªâ¨¢­®¬ á⨫¥ ã室¨â «¨â¥à «®¬. ‘®áâ®ï­¨¥ á¡à á뢠¥âáï ­  ª ¦¤®© áâப¥.

Šíè ®âä®à¬ â¨à®¢ ­­ëå áâப - ®â«®¦¥­ ¢ á ¬ë© ª®­¥æ, á¬. "Phase ?: ®¯â¨¬¨§ æ¨¨". ‘ª®à®á⨠⥪ã饣® ­ ¨¢­®£® ७¤¥à  墠⠥⠭  80x30 = 2400 wrchar / ª ¤à; PgUp/PgDn ¢¨§ã «ì­® ¬£­®¢¥­¥­.

Phase 4 - Block elements

  • Œ àª¨à®¢ ­­ë¥ ᯨ᪨: - foo, * foo, + foo > ¯à¥ä¨ªá ù (0x07) + ¯à®¡¥«; 梥⠬ àª¥à  ïàç¥ ®á­®¢­®£®
  • 㬥஢ ­­ë¥ ᯨ᪨: 1. foo, 2. foo > ª ª ¥áâì (ç¨á«® ®áâ ¢«ï¥¬)
  • Blockquote: áâப¨ á > > ¯à¥ä¨ªá ³ (0xB3) á¥à®£® 梥â , ®áâ «ì­®© ⥪áâ á«¥£ª  ¯à¨£«ãèñ­­ë©
  • Fenced code blocks: ``` ®âªà뢠¥â/§ ªà뢠¥â ¡«®ª; ¢á¥ áâப¨ ¬¥¦¤ã - bg=á¥àë©, ¬®­®è¨à¨­­® (¡¥§ inline-¯ àᨭ£ )
  • Indented code blocks (4+ ¯à®¡¥«®¢):  ­ «®£¨ç­® fenced, ­® ¡¥§ ®£® ¬ àª¥à 

Light nested lists (v1 - ॠ«¨§®¢ ­®):

  • classify_line() ¯à®¯ã᪠¥â leading spaces ¯¥à¥¤ ulist/olist/quote ¬ àª¥à®¬, ¢®§¢à é ¥â content_off ¯®á«¥ ¬ àª¥à  > content_off - p_start = indent + marker ¡¨â ¢ visible col.
  • render_line() à¨áã¥â leading-spaces ¢ ATTR_TEXT, ¯®â®¬ ¬ àª¥à ­  ᤢ¨­ã⮩ ¯®§¨æ¨¨ (col = indent). Marker ¢áñ ¥éñ 䨪á¨à®¢ ­ ¯à¨ £®à¨§®­â «ì­®¬ pan'¥.
  • HR / header / fence delim ®áâ îâáï áâண® col-0 (CommonMark à §à¥è ¥â ¤® 3 ¢¥¤ãé¨å ¯à®¡¥«®¢ ¤«ï ­¨å - ã¯à®á⨫¨).
  • Tab-indent > ­¥ à á¯®§­ ñâáï ª ª nesting (⮫쪮 spaces).

Phase 4-full - ¯®«­ ï ¯®¤¤¥à¦ª  ¢«®¦¥­­®á⨠(deferred):

  • Tab-indent: áç¨â âì tab = 4 ¯à®¡¥«  ¤«ï ®¯à¥¤¥«¥­¨ï ã஢­ï.
  • Quote nesting (> > foo): ª ¦¤ë© > ¯®¤àï¤ = +1 ã஢¥­ì, ª ¦¤ë© à¨áã¥âáï ®â¤¥«ì­ë¬ ³ ¢ ATTR_QUOTE_MARKER (¢¨§ã «ì­ ï "«¥áâ­¨æ " á«¥¢ ).
  • Hanging indent ¢ wrap-continuation: ª®£¤  - some very long bullet text that wraps... - continuation seg ¤®«¦¥­ ­ ç¨­ âìáï ®â content-col (¯®á«¥ ¬ àª¥à ),   ­¥ ®â col 0. ‘¥©ç á continuation ¨¤ñâ ®â col 0 (v1 simplification). ’ॡã¥â åà ­¨âì marker_width per «®£¨ç¥áª ï áâப  (8 ¡¨â) ¨«¨ re-classify first seg ¯à¨ ७¤¥à¥ continuation.
  • Lazy continuation: áâப¨ ¡¥§ ¬ àª¥à , ­® á ¯à ¢¨«ì­ë¬ indent ¯®¤ ¯à¥¤ë¤ã騬 bullet'®¬, ¤®«¦­ë áç¨â âìáï ¯à®¤®«¦¥­¨¥¬ ⮣® bullet'  (¢¨§ã «ì­® - ®¡é¨© attr).
  • Strict CommonMark indent rules: ¢«®¦¥­­ë© ¯ã­ªâ ¤®«¦¥­ ¡ëâì ­  indent ? content_col த¨â¥«ï, ¨­ ç¥ áç¨â ¥âáï breakout. 㦥­ ¬¨­¨-stack  ªâ¨¢­ëå ᯨ᪮¢ ¯à¨ ¨­¤¥ªá æ¨¨.

Phase 5 - Wrap / Unwrap ¤«¨­­ëå áâப

„¥ä®«â: wrap on. F2 ¯¥à¥ª«îç ¥â; ¢ ¬¥­î-¡ à¥ ¯®¤¯¨áì ®âà ¦ ¥â ¤¥©á⢨¥ ("Unwrap" ª®£¤  wrap ¢ª«îçñ­, "Wrap" ª®£¤  ¢ëª«î祭).

v1 - ॠ«¨§®¢ ­®:

  • ޤ¨­ ¬ áᨢ line_offset[2048] åà ­¨â ‚ˆ„ˆŒ›… ᥣ¬¥­âë (  ­¥ «®£¨ç¥áª¨¥ áâப¨); ¡¨âë 0..13 - ¡ ©â®¢®¥ ᬥ饭¨¥, ¡¨â 15 - CONT-ä« £ continuation.
  • Wrap-०¨¬: soft wrap ­  ¯®á«¥¤­¥¬ ¯à®¡¥«¥ ? 80; hard fallback ¥á«¨ ¯à®¡¥«  ­¥â.
  • Œ àª¥àë í¬ä §¨á  (**/*/_/`) ¨ header-¯à¥ä¨ªáë (#/##/...) ­¥ ãç¨â뢠îâáï ¢ visible-col ¯à¨ ¯®¨áª¥ â®çª¨ ¯¥à¥­®á .
  • "‘¯¥æ¨ «ì­ë¥" «®£¨ç¥áª¨¥ áâப¨ ­¥ wrap' îâáï ¢®®¡é¥ (®¤­  seg-§ ¯¨áì ­  «®£¨ç¥áªãî áâபã): fence delim, table row (header/separator/body), HR.
  • F2 toggle á®åà ­ï¥â ¢¨§ã «ì­ãî ¯®§¨æ¨î ç¥à¥§ top_offset ¢ FILE_BUF.
  • Bitmaps (in_code/in_table/is_tab_hdr) ¯¥à¥áâà ¨¢ îâáï ¢¬¥á⥠á ᥣ¬¥­â ¬¨, ¨­¤¥ªá¨àãîâáï seg-¨­¤¥ªá®¬, ¡¨âë áâ ¢ïâáï ⮫쪮 ­  ¯¥à¢®¬ seg'¥ «®£¨ç¥áª®© áâப¨.
  • Continuation-ᥣ¬¥­âë ७¤¥àïâáï ¢ á⨫¥ "v1: ¯«®áª®" - plain text, ­¨ª ª¨å markdown-ª« áá¨ä¨ª æ¨©; padding ¤® ª®­æ  áâப¨ ATTR_TEXT.

v1.5 - ®â«®¦¥­® ¤«ï ¯®«­®© ª à⨭ë wrap:

  • Hanging indent: continuation ®â ulist/olist/quote ¤®«¦¥­ ¢ëà ¢­¨¢ âìáï ¯®¤ content,   ­¥ ®â col 0. ’ॡã¥â åà ­¨âì marker_width per «®£¨ç¥áª ï áâப  ˆ‹ˆ re-classify ¯¥à¢®£® seg'  ¯à¨ ७¤¥à¥ continuation.
  •  á«¥¤®¢ ­¨¥ base_attr: continuation ®â header'  ¤®«¦¥­ á®åà ­ïâì æ¢¥â; continuation ®â code body - ä®­ ATTR_TEXT_CODE. ’ॡã¥â åà ­¨âì 1 ¡ ©â base_attr per seg ˆ‹ˆ lookup ¯¥à¢®£® seg' .
  • Inline emphasis ç¥à¥§ £à ­¨æã: í¬ä §¨á, ®âªàëâë© ¢ ¯¥à¢®¬ seg'¥ ¨ ­¥ § ªàëâë©, ¤®«¦¥­ ¯à®¤®«¦ âìáï ¢® ¢â®à®¬. ’ॡã¥â åà ­¨âì emph state per seg (3 ¡¨â ).
  • Compact way: ¤®¡ ¢¨âì ¯ à ««¥«ì­ë© ¬ áᨢ seg_meta[MAX_SEGS] ¯® 1 ¡ ©âã
    • ¯ ªã¥â marker_width (4 ¡¨â ) + emph_state (3 ¡¨â ) + base_attr_idx (4 ¡¨â  ¨§ â ¡«¨æë > ­ã¦¥­ 2-¡ ©â®¢ë© seg_meta).
  • Hpan ¤«ï ¤«¨­­ëå áâப: ¥á«¨ wrap ¢ëª«î祭, ¤®¡ ¢¨âì </> ¤«ï £®à¨§®­â «ì­®£® áªà®««  >80 cols. ޡ鍩 ¬¥å ­¨§¬ á tables (Phase 6). …€‹ˆ‡Ž‚€Ž (light) - viewport_x + ¯®«­ë© re-render ­  ª ¦¤®¥ </>.
  • “᪮७¨¥ hpan ç¥à¥§ ESTEX WINCOPY/WINREST (deferred): ᥩç á pan ¤¥« ¥â ¯®«­ë© render_viewport() = 30 áâப x 80 wrchar. Œ®¦­® ᪮¯¨à®¢ âì áãé¥áâ¢ãî饥 ᮤ¥à¦¨¬®¥ viewport'  ­  N cols ¢«¥¢®/¢¯à ¢® ç¥à¥§ win-copy, ¯®â®¬ ७¤¥à¨âì ⮫쪮 㧪ãî ¯®«®áã á¯à ¢ /á«¥¢  (HPAN_STEP cols x 30 rows ~ 240 wrchar ¢¬¥áâ® 2400). ESTEX SCROLL £®à¨§®­â «ì ­¥ ¯®¤¤¥à¦¨¢ ¥â - ­ã¦­  ¨¬¥­­® WINCOPY-®¯¥à æ¨ï ¨«¨ rdchar/wrchar loop. €ªâ¨¢¨à®¢ âì ª®£¤  ®éãâ¨âáï â®à¬®§; ᥩç á ­  ⨯®¢®¬ markdown'¥ ­¥ § ¬¥â­®.

v2 - ®â¤¥«ì­ ï ä¨ç , ¬¨¬® wrap:

  • Toggle ¯®¤á¢¥âª¨ 楫¨ª®¬ (F3?)
  • Search ¯® ⥪áâã (Ctrl+F / F4)
  • Links [text](url) > ᨭ¨© ¯®¤çñભãâë© text, url ¯àïç¥âáï
  • Images ![alt](path) > [IMG: alt]

Phase 7 - Links ¨ ¯®¨áª (post-v1)

  • [text](url) > ®âà¨á®¢ âì ⮫쪮 text á ïમ-ᨭ¨¬ FG (¢¨§ã «ì­® ¯®¤çñભã⮥)
  • ![alt](path) > [IMG: alt] ¢ ᪮¡ª å
  • Search ¯® ⥪áâã (F3 / Ctrl+F): ¨­ªà¥¬¥­â «ì­ë©, ¯®¤á¢¥âª  ᮢ¯ ¤¥­¨©

Phase 8 - F8 Raw / Render toggle

¥à¥ª«îç â¥«ì ०¨¬  ®â®¡à ¦¥­¨ï: ¯à¨ ¢ª«îçñ­­®¬ Raw ¯®ª §ë¢ ¥âáï ¨á室­ë© ⥪áâ ä ©«  ª ª ¥áâì - ¢á¥ markdown-¬ àª¥àë (#, **, _, `, |, >, -, etc.) ७¤¥àïâáï «¨â¥à « ¬¨ á ATTR_TEXT, ¡¥§ ª« áá¨ä¨ª æ¨¨. ®«¥§­® ª®£¤ :

  • ­ã¦­® 㢨¤¥âì â®ç­ãî à §¬¥âªã (®â« ¦¨¢ ­¨¥ .md, áªà¨­è®âë, ª®¯¨à®¢ ­¨¥)
  • markdown-ª« áá¨ä¨ª â®à ®è¨¡áï ¨ å®ç¥âáï 㢨¤¥âì ®à¨£¨­ «
  • å®ç¥âáï ¡ëáâà® áà ¢­¨âì "¤®/¯®á«¥" ७¤¥à 

®¢¥¤¥­¨¥:

  • F8 ¯¥à¥ª«îç ¥â render_mode (1=render, 0=raw); ¬¥­î ¯®ª §ë¢ ¥â ®¡à â­®¥ ¤¥©á⢨¥ ("Raw" ª®£¤  ᥩç á render, "Render" ª®£¤  ᥩç á raw) - ⮩ ¦¥ «®£¨ª®© çâ® F2/Wrap/Unwrap.
  • Raw ०¨¬¥: render_line() ¨¤ñâ ¯® ª®à®âª®¬ã ¯ã⨠- ­¨ª ª®£® classify_line, is_fence_delim, is_code_body, inline-í¬ä §¨á ; ¯à®áâ® ¡ ©â®¢ë© ¤ ¬¯ FILE_BUF ®â seg-offset ¤® next-seg/EOL á tab-expansion ¨ ATTR_TEXT.
  •  §¤¥«ì­® ®â F2: ®¡  ०¨¬  ­¥§ ¢¨á¨¬ë (¬®¦­® Raw+Wrap, Raw+Truncate, Render+Wrap, Render+Truncate). Wrap-«®£¨ª  ¢ index_lines à ¡®â ¥â ¢ ®¡®¨å á«ãç ïå ®¤¨­ ª®¢® (®¯¨à ¥âáï ­  ¢¨§ã «ì­ë¥ ª®«®­ª¨ ­¥§ ¢¨á¨¬® ®â à áªà áª¨).
  • ‘â âãá-¡ à: ¤®¡ ¢¨âì ¨­¤¨ª â®à [R] / [V] (Raw / View) ¨«¨ ⥪á⮬ RAW à冷¬ á ¨¬¥­¥¬ ä ©« .

Œ¨­¨¬ «ì­ ï ॠ«¨§ æ¨ï:

  • ޤ¨­ ­®¢ë© static uint8_t render_mode = 1;
  • render_line(): ­  á ¬®¬ ¢¥àåã if (!render_mode) { ? raw render ? return; }
  • render_menu(): ¤®¡ ¢¨âì ïà«ëª F8 à冷¬ á F2.
  • £« ¢­®¬ 横«¥: case KEY_F8: toggle_render(); break;
  • toggle_render() ®â«¨ç ¥âáï ®â toggle_wrap() ⥬, çâ® … ¯¥à¥áâà ¨¢ ¥â line_offset[] (wrap-ᥣ¬¥­â æ¨ï ­¥ ¬¥­ï¥âáï), ⮫쪮 ¯¥à¥à¥­¤¥à¨â íªà ­.

API-­®¢¨­ª¨ ¢ libc (¬¨­¨¬ «ì­ë¥)

getkey() - extended key reader (¢ libc)

’¥ªã騩 getch() â¥àï¥â scan code à áè¨à¥­­ëå ª« ¢¨è (¢®§¢à é ¥â ⮫쪮 E=ASCII). „®¡ ¢«ï¥¬ áà §ã ¢ libc/conio/conio.c ­®¢ãî äã­ªæ¨î à冷¬ á getch():

// Returns scan in high byte, ASCII in low byte.
// Extended keys (arrows, F-keys, PgUp/PgDn, Home/End): ASCII=0, scan code ¢ high byte.
// Plain keys: ASCII ¢ low byte; high byte ᮤ¥à¦¨â positional scan (¡¨â 7 = Ctrl/Alt/Shift modifier).
uint16_t getkey(void) __naked {
    __asm
        ld   c, #0x30   ; ESTEX WAITKEY
        rst  #0x10      ; A=ASCII, D=scan, E=ASCII
        ld   e, a       ; ensure E=ASCII even if E clobbered
        ret             ; SDCC __sdcccall(1): ¢®§¢à â uint16_t ¢ DE (D=scan, E=ASCII)
    __endasm;
}

„®¯®«­¨â¥«ì­® - ¢ libc/include/conio.h ¯à®¯¨á âì ¯à®â®â¨¯ ¨ ª®­áâ ­âë scan-ª®¤®¢:

uint16_t getkey(void);

/* Scan codes for getkey() high byte when ASCII=0 (extended keys). */
#define KEY_F1     0x0E
#define KEY_F2     0x0F
#define KEY_F3     0x10
#define KEY_F4     0x11
#define KEY_F5     0x12
#define KEY_F6     0x13
#define KEY_F7     0x14
#define KEY_F8     0x15
#define KEY_F9     0x16
#define KEY_F10    0x17
#define KEY_F11    0x18
#define KEY_F12    0x19
#define KEY_END    0x24
#define KEY_DOWN   0x25
#define KEY_PGDN   0x26
#define KEY_LEFT   0x27
#define KEY_RIGHT  0x29
#define KEY_HOME   0x2A
#define KEY_UP     0x2B
#define KEY_PGUP   0x2C
#define KEY_INS    0x23
#define KEY_DEL    0x22

‘ª ­-ª®¤ë (¨§ docs/converted/ProgrammerManual.txt:2143-2323):

Š« ¢¨è  scan Š« ¢¨è  scan
F1 0x0E Up 0x2B
F10 0x17 Down 0x25
F11 0x18 Left 0x27
F12 0x19 Right 0x29
PgUp 0x2C
PgDn 0x26
Home 0x2A
End 0x24

—â® ¯¥à¥¨á¯®«ì§ã¥¬ ¨§ áãé¥áâ¢ãî饩 libc

  • open/read/lseek/close - libc/io/{open,read,lseek}.c (POSIX wrappers)
  • mem_alloc_pages/mem_free_block/mem_get_page - libc/mem/mem_alloc.c
  • sprinter_page_w3() - inline __sfr write ¢ libc/include/sprinter.h:113
  • bank_read_w3/bank_write_w3 - libc/mem/bank_io_w3.c (¤«ï fallback ¨«¨ v2 multi-page)
  • wrchar(x, y, ch, attr) - libc/conio/conio.c:476 (¡¥§ auto-scroll, ¨¤¥ «ì­® ¤«ï viewport)
  • clrscr_attr(attr) - libc/conio/conio.c:395
  • gotoxy/wherex/wherey - libc/conio/conio.c:412-462 (¥á«¨ ­ã¦­®)
  • kbhit() - libc/conio/conio.c:22 (¤«ï non-blocking ®¯à®á , ®¯æ¨®­ «ì­®)
  • dec16/dec8 - libc/stdio/dec_print.c (¤«ï status bar: ⥪ãé ï áâப  / total / %)
  • COLOR(fg, bg) ¬ ªà®á - libc/include/conio.h:152
  • –¢¥â®¢ë¥ ª®­áâ ­âë COLOR_* - libc/include/conio.h:145
  • strlen/memcpy/memset - z80.lib (… ¯¥à¥¯¨á뢠âì)

‘âàãªâãà  ¨á室­¨ª®¢

examples/mdview/
ÃÄÄ Makefile                # áâ ­¤ àâ­ë© pattern (á¬. examples/cat/Makefile)
ÃÄÄ mdview.c                # Phase 1: ¢áñ ¢ ®¤­®¬ ä ©«¥ (main, keys, indexing, render)
ÃÄÄ SAMPLE.MD               # â¥áâ®¢ë© markdown
ÀÄÄ README.md               # ®¯¨á ­¨¥ ¨ controls

®á«¥ Phase 3 à áª¨¤ âì ¯® ¬®¤ã«ï¬ (¥á«¨ á㬬 à­ë© à §¬¥à > ~6KB):

mdview.c       - main loop, status/menu bars, key dispatch
mdrender.c     - line rendering with MD inline parser
mdindex.c      - file load + line indexing

‘¡®àª 

PROJ ?= ../..
SPRINTER_CC := $(PROJ)/bin/sprinter-cc
mdview.exe: mdview.c
	$(SPRINTER_CC) --memory small -o $@ mdview.c

--memory small: ª®¤+¤ ­­ë¥ ¢ W2 (DSS ¤ ñ⠭㦭®¥ ç¨á«® áâà ­¨æ); ä ©« - ®â¤¥«ì­ ï EMM-áâà ­¨æ  ¢ W3.


‘âàãªâãà  mdview.c (Phase 1, í᪨§)

#include <stdint.h>
#include <stdio.h>
#include <conio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sprinter.h>
#include <sprinter_mem.h>

#define VIEW_TOP    1
#define VIEW_BOT    30        // inclusive
#define VIEW_H      30
#define SCREEN_W    80
#define MAX_LINES   2048
#define FILE_BUF    ((char*)0xC000)   /* W3 - EMM page mapped here */
#define TAB_STOP    4

#define ATTR_TEXT   COLOR(COLOR_WHITE, COLOR_BLACK)
#define ATTR_BAR    COLOR(COLOR_WHITE, COLOR_BLUE)
#define ATTR_MENU_K COLOR(COLOR_YELLOW, COLOR_BLUE)
#define ATTR_MENU_T COLOR(COLOR_WHITE, COLOR_BLUE)

static uint16_t line_off[MAX_LINES];
static uint16_t n_lines;
static uint16_t top_line;
static uint16_t file_size;
static uint8_t  file_blk;
static char     filename[64];

static int load_file(const char *path);     // open, alloc EMM page, map W3, read, close
static void index_lines(void);              // scan FILE_BUF, fill line_off[]
static void render_status(void);            // row 0
static void render_menu(void);              // row 31
static void render_line(uint16_t idx, uint8_t row);  // one line @ row
static void render_viewport(void);          // VIEW_H lines starting from top_line
static void scroll_up(uint16_t n);
static void scroll_down(uint16_t n);
static void help_screen(void);              // F1

int main(int argc, char **argv) {
    if (argc < 2) { puts("Usage: mdview <file.md>"); return 1; }
    if (load_file(argv[1]) < 0) { puts("load error"); return 1; }
    index_lines();
    clrscr_attr(ATTR_TEXT);
    render_menu();
    render_status();
    render_viewport();
    for (;;) {
        uint16_t k = getkey();
        uint8_t  ascii = k & 0xFF;
        uint8_t  scan  = (k >> 8) & 0x7F;  // strip mod bit
        if (ascii) {
            if (ascii == 0x1B) break;         // Esc > exit
            continue;
        }
        switch (scan) {
            case KEY_F10:  goto exit;
            case KEY_F1:   help_screen();             break;
            case KEY_UP:   scroll_up(1);              break;
            case KEY_DOWN: scroll_down(1);            break;
            case KEY_PGUP: scroll_up(VIEW_H);         break;
            case KEY_PGDN: scroll_down(VIEW_H);       break;
            case KEY_HOME: top_line = 0;
                           render_viewport();         break;
            case KEY_END:  /* clamp to last viewport */ break;
        }
        render_status();
    }
exit:
    mem_free_block(file_blk);
    clrscr_attr(ATTR_TEXT);
    return 0;
}

Verification

Phase 1

  1. ®¤£®â®¢¨âì SAMPLE.MD ~5 KB (§ £®«®¢ª¨,  ¡§ æë, ᯨ᪨) - ७¤¥à¨âìáï ¡ã¤¥â plain.
  2. cd examples/mdview && make
  3. python make_disk.py mdview.exe SAMPLE.MD > mc.img && ./run_mame.sh
  4. ஢¥à¨âì:
    • Status bar ¯®ª §ë¢ ¥â SAMPLE.MD L 1-30 / N X%
    • Menu bar ¢­¨§ã
    • ^/v: 1 áâப 
    • PgUp/PgDn: 30 áâப, ª®à४⭮¥ clamp ­  £à ­¨æ å
    • Home: top_line=0
    • End: top_line = total_lines - VIEW_H
    • F1: ¯®ª §ë¢ ¥â help, «î¡ ï ª« ¢¨è  ¢®§¢à é ¥â
    • F10 / Esc: ¢ë室, íªà ­ ®ç¨é¥­
  5. Edge cases: ¯ãá⮩ ä ©«, ä ©« ¨§ ®¤­®© áâப¨, ä ©« á ®ç¥­ì ¤«¨­­®© áâப®© (>80), CRLF ¨ LF mixed.

Phase 2-4

 áè¨àïâì SAMPLE.MD á ä¨ç ¬¨ ¯® ¬¥à¥ ¤®¡ ¢«¥­¨ï, ¢¨§ã «ì­® ¢¥à¨ä¨æ¨à®¢ âì ¢ MAME. ‘ªà¨­è®â-áà ¢­¥­¨¥ ®¯æ¨®­ «ì­®.

¥£à¥áᨨ

  • ¨ª ª¨å ¨§¬¥­¥­¨© ¢ libc ­  Phase 1 ªà®¬¥ (¯®â¥­æ¨ «ì­®) ¤®¡ ¢«¥­¨ï getkey() ¢ libc/conio/conio.c - ¥á«¨ â ª, ¯à®£­ âì examples/conio2 ¨ examples/filetest ç⮡ë ã¡¥¤¨âìáï çâ® ­¨ç¥£® ­¥ á«®¬ «®áì.

¥è¥­¨ï ¯® ­¥®¤­®§­ ç­®áâï¬

  1. Word-wrap vs truncate: v1 = truncate (¯à®áâ®). v2 - F2 toggle wrap.
  2. ƒ®à¨§®­â «ì­ë© áªà®««¨­£: v1 - ­¥â; v2 - </> ᤢ¨£ viewport ¯® á⮫¡æ ¬.
  3. Tab handling: ¯à¥®¡à §®¢ ­¨¥ ¯à¨ ७¤¥à¥, tabstop = 4 (áâ ­¤ àâ MD). Žà¨£¨­ « ¢ W3 ­¥ âண ¥¬.
  4. UTF-8: ७¤¥à¨¬ ¡ ©âë ª ª ¥áâì. …᫨ ä ©« ¢ CP866 - ®âà¨áã¥âáï ª¨à¨««¨æ¥© ç¥à¥§ á¨á⥬­ë© ä®­â. UTF-8 - ¯®ª  ­¥ ¯®¤¤¥à¦¨¢ ¥¬ (¢¨§ã «ì­® ¡ã¤¥â ª è  ­  ­¥-ASCII ᨬ¢®« å; ¤¥â¥ªâ ¨ ¯à¥¤ã¯à¥¦¤¥­¨¥ - ¢ v2).

Phase 6 - ®«­ë© layout â ¡«¨æ (deferred)

‘¥©ç á (Phase 4-tables) â ¡«¨æë à¨áãîâáï "¤¥ª®à â¨¢­®" - ¯ ©¯ë ¨ â¨à¥ § ¬¥­ïîâáï ­  box-drawing chars, ­® è¨à¨­ë ª®«®­®ª ¡¥àãâáï ª ª ¥áâì ¨§ ¨á室­¨ª . –¥«ì Phase 6 - ¯¥à¥áç¨â âì â ¡«¨æã ¢ ­®à¬ «¨§®¢ ­­ë© ¢¨¤:

  • Pre-scan â ¡«¨æë: ¯à®©â¨ ¢á¥ áâப¨ ®¤­®£® table-¡«®ª , ­ ©â¨ ¬ ªá¨¬ «ì­ãî è¨à¨­ã ª ¦¤®© ª®«®­ª¨ (á ãçñ⮬ áꥤ¥­­ëå inline-¬ àª¥à®¢ - ¢¨§ã «ì­ë© à §¬¥à, ­¥ ¡ ©â®¢ë©).
  • Re-emit ¢ ¡ãä¥à¥: ¯à¨ § £à㧪¥ ä ©«  (¨«¨ ¯à¨ ¯¥à¢®© ¢áâà¥ç¥ â ¡«¨æë) ¯¥à¥¯¨á âì áâப¨ ¢ FILE_BUF â ª, çâ®¡ë ¢á¥ ï祩ª¨ ®¤­®© ª®«®­ª¨ ¨¬¥«¨ ®¤¨­ ª®¢ãî è¨à¨­ã; ¤®¡ ¢¨âì top/bottom à ¬ª¨ (ÚÄÂÄ¿ / ÀÄÁÄÙ) ª ª ᨭâ¥â¨ç¥áª¨¥ áâப¨. â® ¯®§¢®«¨â á®åà ­¨âì 1:1 ᮮ⢥âá⢨¥ "«®£¨ç¥áª ï áâப  > ®¤­  viewport row" ¡¥§ ᯥ樠«ì­®© «®£¨ª¨ ¯à¨ ७¤¥à¥.
  •  ¬ïâì: re-emit ¬®¦¥â “‚…‹ˆ—ˆ’œ ä ©« §  áçñâ padding ¨ ¤®¯.à ¬®ª. …᫨ ¡ãä¥à ¡«¨§®ª ª 16KB - ®â१ âì â ¡«¨æã ¨ ¯®¬¥â¨âì ¥ñ overflow'®¬.
  • ƒ®à¨§®­â «ì­ë© áªà®««¨­£: ¥á«¨ ¨â®£®¢ ï è¨à¨­  â ¡«¨æë (¨«¨ «î¡®© áâப¨) > SCREEN_W = 80 - ¤®¡ ¢¨âì </> ¤«ï horizontal pan. â® ¡ã¤¥â ®¡é¨© ¬¥å ­¨§¬ ¤«ï ¤«¨­­ëå áâப (á¬. â ª¦¥ wrap mode), ­¥ ⮫쪮 â ¡«¨æ.
  • ‚ëà ¢­¨¢ ­¨¥ ¨§ separator-row: :- > left, -: > right, :-: > center; ãç¨â뢠âì ¯à¨ padding'¥ ᮤ¥à¦¨¬®£® ï祩ª¨.
  • ˜ £¨ ॠ«¨§ æ¨¨:
    1. Walking pass ¯® 䥭ᠬ/â ¡«¨æ ¬ ¯àאַ ¢ index_lines() - ᮡà âì extents ¢á¥å â ¡«¨æ.
    2. „«ï ª ¦¤®© â ¡«¨æë - ®¯à¥¤¥«¨âì è¨à¨­ë ª®«®­®ª.
    3. ¥è¥­¨¥: rewrite-in-buffer (¯à®é¥ ¤«ï ७¤¥à , ­® ¬ãâ¨àã¥â ¨á室­¨ª) vs render-time layout (cleaner, ­® âॡã¥â ®â¤¥«ì­®© áâàãªâãàë ®¯¨á ­¨ï layout'  ­  ª ¦¤ãî â ¡«¨æã).
    4. Hpan: ®¡é¨© viewport_x_offset ¤«ï ¢á¥£® íªà ­ , ¨«¨ ®â¤¥«ì­ë© "è¨à®ª¨© ०¨¬" ⮫쪮 ¢­ãâਠ⠡«¨æ.

¥ ¡«®ª¨àãîé ï ä¨ç . ‡ ¯ã᪠âì ª®£¤  áâ ­¥â ¯®­ï⥭ ⨯®¢®© ¨áâ®ç­¨ª markdown-ä ©«®¢ (㧪¨¥ ç¨â «ª¨ > ¤®áâ â®ç­® ⥪ã饣® ¤¥ª®à â®à ; è¨à®ª¨¥ README á ¡®«ì訬¨ â ¡«¨æ ¬¨ > ­ã¦¥­ ¯®«­ë© layout).


Phase ? - Šíè ७¤¥à¥­­ëå áâப (low priority)

Žâ«®¦¥­®: ⥪ãé ï ᪮à®áâì ¡®«¥¥ 祬 ¤®áâ â®ç­ . €ªâ¨¢¨à®¢ âì ¥á«¨ ¯®ï¢¨âáï áæ¥­ à¨©, £¤¥ ¢¨¤­  § ¤¥à¦ª  PgUp/PgDn (­ ¯à¨¬¥à, ¯à¨ âï¦ñ«®¬ inline-¯ àá¥à¥ v2 á UTF-8 / linkifier / â ¡«¨æ ¬¨).

Šíè ®âä®à¬ â¨à®¢ ­­ëå áâப (W3, ®â¤¥«ì­ ï EMM-áâà ­¨æ ):

Cache layout (16 KB EMM page, ¢á¥£® 16000 ¡ ©â ¨á¯®«ì§ã¥âáï):
  slot 0:   80 chars + 80 attrs  = 160 bytes  @ offset 0
  ...
  slot 99:  80 chars + 80 attrs  = 160 bytes  @ offset 15840

Cache tags (W2 static): uint16_t cache_tag[100] = 200 bytes
  cache_tag[i] = line_id, ¨«¨ 0xFFFF = invalid

‘âà â¥£¨ï - direct map (no LRU): slot = line_id % 100. Š®««¨§¨ï > ¢ëâ¥á­¥­¨¥.

Batched viewport render: 2 page-swap'  ­  ‚…‘œ viewport (cache > file > cache), ­¥ 60 ª ª ¯à¨ ­ ¨¢­®© ॠ«¨§ æ¨¨.

ਠᡮથ: cache_blk = mem_alloc_pages(1) ¯®á«¥ file_blk; mem_free_block ­  exit.


—â® ®â«®¦¥­® ¢ v2

  • ” ©«ë >16 KB: ¬­®£®áâà ­¨ç­®¥ åà ­¥­¨¥ ç¥à¥§ mem_alloc_pages(N), «¥­¨¢ ï § £à㧪  áâà ­¨æ ¢ W3 ¯à¨ ¤®áâ㯥.
  • Search (Find / Find next) - F3 / F4.
  • Toggle highlight on/off - F2.
  • Word wrap.
  • Image alt-text rendering.
  • Tables.