muforth/cf/cf2.mu4

( This file is part of muFORTH: http://pages.nimblemachines.com/muforth

  Copyright 2002-2008 David Frech. All rights reserved, and all wrongs
  reversed. (See the file COPYRIGHT for details.)

( draw the colorForth icons/characters)

comment %%
( Note: PROT_READ is 1)
: mmap-dev  ( #blocks - a)  open-file 1 rot Ki mmap ;  %%

 z" cf/color.com"
-- z" /home/david/Chuck/COLOR.COM.9sep"
-- z" /home/david/Chuck/colorForth.dist"
-- z" /tmp/cf"
-- 162 mmap-dev /dev/fd0
 r/o  open-file mmap-file swap nip constant |cf

: block  Ki  |cf + ;

: c@+  ( a - a+ byte)  dup 1+  swap c@ ;
: @+  dup cell+  swap @ ;
: w@+  c@+ ( hi)  8 <<  swap  c@+ ( lo)  rot + ;
: dot  "8000 and if  char # ^  then  bl ;
: .16  cr  16 for  dup dot  dup emit emit  2*  next  drop ;
: .24  cr  24 for  w@+ .16  next ;
: icon  ( n - a)  48 *  12 block + ;
-- : icons  ( n first)  icon  swap for  .24  next  drop ;

comment %%
: raw ;  ( from when I could change tty modes)
: cooked ; %%

: =  xor 0= ;
: done?  tty raw  key tty cooked  char q = ;
: icons  ( first)
   dup icon begin .24  over space . 1 u+ done? until  drop ;

: _chs  for  dup emit 1+  next cr ;
: .64  64 _chs ;
: .32  32 _chs ;
: chars  32 .32  .64 .64 .64 drop ;

( terminal ESC sequences)
: <esc  <#  char m hold ;
: esc>  char [ hold  ctrl [ hold  #> type ;

( colored and attributed text)
comment %%
: color  ctrl [ emit ( esc)  char [ emit  30 + u.  char m emit ;
: _color  drop space ; %%

: attrib  <esc  #s esc> ;
: color  ( foregd)  0 attrib  30 + attrib  space ;
( : bright  1 attrib ;)
: bright  char " emit ;  ( bright yellow and green hard to read on white bg)
: black    0 color ;
: red      1 color ;
: green    2 color ;
: yellow   3 color ;
: blue     4 color ;
: magenta  5 color ;
: cyan     6 color ;
: _white   7 color ; ( for white-on-black)

-- : white   _white ;
: white   black ;  ( for xterms and suchlike)
white

( printing source blocks)
variable case
: lc  z"  rtoeanismcylgfwdvpbhxuq0123456789j-k.z/;:!+@*,?"  case ! ;
: uc  z"  RTOEANISMCYLGFWDVPBHXUQ0123456789J-K.Z/;:!+@*,?"  case ! ;
: map  case @ + c@ ;
: .4  swap 4 << swap  28 >>  7 and ;
: .5  swap 5 << swap  28 >>  7 and  8 + ;
: .7  swap 7 << swap  26 >>  31 and 16 + ;
: unpack  dup  dup 0< if  2*  dup 0< if  .7 ^ then  .5 ^ then  .4 ;
: 1char  unpack map emit ;
: chars  begin  dup while  1char  repeat  drop ;
: .word  lc chars ;
: .WORD  uc chars ;
: .Word  uc 1char  .word ;

( Support for our bizarre little state-machine/co-routine/continuation gizmo)
variable 'co
( Note the dual nature of these two routines!)
: suspend  pop 'co ! ;       ( return from co-routine)
: resume       'co @ push ;  ( call to co-routine)

defer ->format

variable #used ( # of cells in this block)
: tally  1 #used +! ;  ( count it)
: ?tally  =if  tally  then ;  ( count it only if non-zero)

( numbers, with auto-radix)
variable auto-radix ( so we don't clobber muforth's)
: .d               (.)          type ;
: .h  bright  hex (u.) decimal  type ;
: .radix  auto-radix @ "10 and if .h ^ then .d ;
: .num        auto-radix !  suspend  tally  .radix  ->format ;
: .short  dup auto-radix !         5 >>  .radix ;

( kinds of words; "xW" names are from cf source - don't blame me!)
: ign         .word ; ( ignored - doesn't change color)
: rW   cr red .word ;
: wW   yellow .word ; ( "white")
: gW    green .word ;
: mW     cyan .word ; ( macro)
: text  white .word ;
: Text  white .Word ;
: TEXT  white .WORD ;
: nW   yellow .num ;
: gnW   green .num ;
: sW   yellow .short ;
: gsW   green .short ;
: var  cr magenta .word  suspend  tally  dup green .d green .h  ->format ;
                                ( show value in hex & dec)

-:
  suspend ?tally
  dup -16 and  swap  15 and  jump
   ign    wW    nW    rW
    gW   gnW   gsW    mW
    sW  text  Text  TEXT
   var   ign   ign   ign [  is ->format



( kinds of words; "xW" names are from cf source - don't blame me!)
( annotate with type info as well as color)
: .type
   0 <#  bl hold  char ] hold  hex # decimal char [ hold  bl hold #> type ;

: ign         .type .word ; ( ignored - doesn't change color)
: rW   cr red .type .word ;
: wW   yellow .type .word ; ( "white")
: gW    green .type .word ;
: mW     cyan .type .word ; ( macro)
: text  white .type .word ;
: Text  white .type .Word ;
: TEXT  white .type .WORD ;
: nW   yellow .type .num ;
: gnW   green .type .num ;
: sW   yellow .type .short ;
: gsW   green .type .short ;
: var  cr magenta .type .word
   suspend  tally  dup green .d green .h  ->format ;
                        ( show value in hex & dec)

-:
  suspend ?tally
  dup -16 and  swap  15 and  dup  jump
   ign    wW    nW    rW
    gW   gnW   gsW    mW
    sW  text  Text  TEXT
   var   ign   ign   ign [  is ->format


( kinds of words; "xW" names are from cf source - don't blame me!)
( annotate with type info but no color - suitable for reading back in and
  converting back to colorforth source.)

variable _type
: 0type  bl _type ! ;
: .type
  space  _type @  over _type !  xor if  _type @ emit  space  then ;

: red  char :  .type ;
: green  char ]  .type ;
: yellow  char [  .type ;
: magenta  char @  .type ;
: cyan  char \ .type ;
: white  char ( .type ;

( kinds of words; "xW" names are from cf source - don't blame me!)
: ign         .word ; ( ignored - doesn't change color)
: rW   cr red .word ;
: wW   yellow .word ; ( "white")
: gW    green .word ;
: mW     cyan .word ; ( macro)
: text  white .word ;
: Text  white .Word ;
: TEXT  white .WORD ;
: nW   yellow .num ;
: gnW   green .num ;
: sW   yellow .short ;
: gsW   green .short ;
: var  cr magenta .word  suspend  tally  dup green .d green .h  ->format ;
                                ( show value in hex & dec)

-:
  suspend ?tally
  dup -16 and  swap  15 and  jump
   ign    wW    nW    rW
    gW   gnW   gsW    mW
    sW  text  Text  TEXT
   var   ign   ign   ign [  is ->format  ( resolve forward ref)


( We'd like to do "256 for ... next" but since two kinds of words - full-
  length numbers and variables - use an extra cell, it doesn't work. They
  read an extra cell each, and we read into the next block. In other words,
  instead of doing 256 @+'s we do 256+vars+nums.

  We could fix this by going to a more complicated arrangement - essentially
  a state machine, where every type returns a next state. This way normal
  ["single-cell"] words would return the normal "format" state; variables
  and nums would return the state that would complete them. Then we could
  put the fetching at the top-level and properly do "256 for @+ foo next".

  That would be good. If a little strange and hard to read. But that's what
  this file does!)

: .block  0 #used ! 0type  ->format  block  256 for  @+ resume  next  drop ;
: header  cr cr  ." -*- Block " . ." -*-" cr ;
: footer  cr cr  ." ("  #used @  dup (.) type  ." /256 : "
    100 256 */ (.) type ." % full)" ;
: sh  decimal  dup header  .block  ( white)  footer ;
: shs  ( n)  begin  dup sh 1+  done? until ;