M_attr Module

NAME

M_attr(3f) - [M_attr::INTRO] control text attributes on terminals
(LICENSE:MIT)

SYNOPSIS

  use M_attr, only : attr, attr_mode, attr_update

  use M_attr, only : alert ! generate standard messages

DESCRIPTION

M_attr(3f) is a Fortran module that uses common ANSI escape sequences
to control terminal text attributes.

     use M_attr
     write(*,*)attr('<red>Red Text!</red> <green>Green Text!</green>')
     end

It is designed to use three simple procedures to

 + Specify attributes using simple HTML-like syntax
 + allow the sequences to be suppressed when desired
 + permit the  user program to completely customize the keywords.
   The user can add, delete and replace the sequences associated with
   a keyword without changing the code.

One advantage of the approach of using formatting directives which
are replaced with in-band escape sequences is that it is easy to turn
off when running batch.

Another important capability is that programs can be run in "raw" mode
and create a simple text file with the formatting directives in it
that can then be read back in by a simple filter program that strips
it back to plain text( see app/plain.f90), or displays it to a screen
in color(see app/light.f90) or perhaps converts it to another format.

So this approach makes it trivial to read specially-formatted data
from a file like a message catalog (perhaps with various versions in
different languages) and colorize it or display it as plain text

By making each line self-contained (by default) lines can be filtered
by external utilities and still display correctly.

ACCESS

Via git(1):

    git clone https://github.com/urbanjost/M_attr.git
    cd M_attr/src
    # change Makefile if not using one of the listed compilers
    make clean; make gfortran    # for gfortran
    make clean; make ifort       # for ifort
    make clean; make nvfortran   # for nvfortran

This will compile the M_attr module and example programs.

Alternatively, via fpm (see https://github.com/fortran-lang/fpm):

     git clone https://github.com/urbanjost/M_attr.git

or just list it as a dependency in your fpm.toml project file.

     [dependencies]
     M_attr = { git = "https://github.com/urbanjost/M_attr.git" }

LIMITATIONS

o colors are not nestable. o keywords are case-sensitive, o ANSI escape sequences are not universally supported by all terminal emulators; and normally should be suppressed when not going to a tty device. Therefore, you should use M_system::system_istty(3f) or the common Fortran extension ISATTY() to set the default to “plain” instead of “color” when the output file is not a conforming terminal. On basic MSWindows console windows, it is best to use Windows 10+ and/or the Linux mode; you may have to enable ANSI escape sequence mode on MSWindows. It does work as-is with CygWin and MinGW and Putty windows and mintty(1) as tested.

EXAMPLE

Sample program

 program demo_M_attr
 use M_attr, only : attr, attr_mode, attr_update, alert
 implicit none
 character(len=256) :: line
 character(len=*),parameter :: f='( &
  &"   <bo><w><G> GREAT: </G></w>&
  &The new value <Y><b>",f8.4,1x,"</b></Y> is in range"&
  &)'
 real :: value

    write(*,'(a)')&
    &attr('   <r><W><bo> ERROR: </W>red text on a white background</y>')

    value=3.4567
    write(line,fmt=f) value
    write(*,'(a)')attr(trim(line))

    ! write same string as plain text
    write(*,*)
    call attr_mode(manner='plain')
    write(*,'(a)')attr(trim(line))

    call attr_mode(manner='color')
    ! use pre-defined or user defined strings
    write(*,*)
    write(*,'(a)')attr('<ERROR> Woe is nigh.')
    write(*,'(a)')attr('<WARNING> The night is young.')
    write(*,'(a)')attr('<INFO> It is Monday')

    call alert('<ERROR>', 'Woe is nigh.')
    call alert('<WARNING>', 'The night is young.')
    call alert('<INFO>', 'It is Monday')

    ! create a custom mnemonic
    call attr_update('MYERROR',attr(&
    ' <R><e> E<w>-<e>R<w>-<e>R<w>-<e>O<w>-<e>R: </e></R></bo>'&
    ))
    write(*,*)
    write(*,'(a)')attr('<MYERROR> my custom message style')

 end program demo_M_attr

AUTHOR

John S. Urban, 2021

LICENSE

MIT

SEE ALSO

attr(3f), attr_mode(3f), attr_update(3f)

Related information:

 terminfo(3c), termlib(3c), tput(1), reset(1), clear(1),
 console_codes(4), ECMA-48,
 https://en.wikipedia.org/wiki/ANSI_escape_code


Variables

Type Visibility Attributes Name Initial
character(len=*), public, parameter :: bg_black = CODE_START//BG//BLACK//CODE_END
character(len=*), public, parameter :: bg_blue = CODE_START//BG//BLUE//CODE_END
character(len=*), public, parameter :: bg_cyan = CODE_START//BG//CYAN//CODE_END
character(len=*), public, parameter :: bg_default = CODE_START//BG//DEFAULT//CODE_END
character(len=*), public, parameter :: bg_ebony = CODE_START//BG//BLACK//CODE_END
character(len=*), public, parameter :: bg_green = CODE_START//BG//GREEN//CODE_END
character(len=*), public, parameter :: bg_magenta = CODE_START//BG//MAGENTA//CODE_END
character(len=*), public, parameter :: bg_red = CODE_START//BG//RED//CODE_END
character(len=*), public, parameter :: bg_white = CODE_START//BG//WHITE//CODE_END
character(len=*), public, parameter :: bg_yellow = CODE_START//BG//YELLOW//CODE_END
character(len=*), public, parameter :: bold = CODE_START//ON//AT_BOLD//CODE_END
character(len=*), public, parameter :: clear = HOME_DISPLAY//CLEAR_DISPLAY
character(len=*), public, parameter :: fg_black = CODE_START//FG//BLACK//CODE_END
character(len=*), public, parameter :: fg_blue = CODE_START//FG//BLUE//CODE_END
character(len=*), public, parameter :: fg_cyan = CODE_START//FG//CYAN//CODE_END
character(len=*), public, parameter :: fg_default = CODE_START//FG//DEFAULT//CODE_END
character(len=*), public, parameter :: fg_ebony = CODE_START//FG//BLACK//CODE_END
character(len=*), public, parameter :: fg_green = CODE_START//FG//GREEN//CODE_END
character(len=*), public, parameter :: fg_magenta = CODE_START//FG//MAGENTA//CODE_END
character(len=*), public, parameter :: fg_red = CODE_START//FG//RED//CODE_END
character(len=*), public, parameter :: fg_white = CODE_START//FG//WHITE//CODE_END
character(len=*), public, parameter :: fg_yellow = CODE_START//FG//YELLOW//CODE_END
character(len=*), public, parameter :: inverse = CODE_START//ON//AT_INVERSE//CODE_END
character(len=*), public, parameter :: italic = CODE_START//ON//AT_ITALIC//CODE_END
character(len=*), public, parameter :: reset = CODE_RESET
character(len=*), public, parameter :: unbold = CODE_START//'22'//CODE_END
character(len=*), public, parameter :: underline = CODE_START//ON//AT_UNDERLINE//CODE_END
character(len=*), public, parameter :: uninverse = CODE_START//OFF//AT_INVERSE//CODE_END
character(len=*), public, parameter :: unitalic = CODE_START//OFF//AT_ITALIC//CODE_END
character(len=*), public, parameter :: ununderline = CODE_START//OFF//AT_UNDERLINE//CODE_END

Interfaces

public interface advice

  • public subroutine alert(type, message, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj)

    !>

    NAME

    alert(3f) - [M_attr] print messages using a standard format including
    time and program name
    (LICENSE:MIT)
    

    SYNOPSIS

     subroutine alert(message,&
     g0,g1,g2,g3,g4,g5,g6,g7,g8,g9,ga,gb,gc,gd,ge,gf,gg,gh,gi,gj)
    
        character(len=*),intent(in),optional :: type
        character(len=*),intent(in),optional :: message
        class(*),intent(in),optional :: g0,g1,g2,g3,g4,g5,g6,g7,g8,g9, &
                                      & ga,gb,gc,gd,ge,gf,gg,gh,gi,gj
    

    DESCRIPTION

    Display a message prefixed with a timestamp and the name
    of the calling program when the TYPE is specified as any
    of 'error','warn', or 'info'.
    
    It also allows the keywords
    <ARG0>,<TZ>,<YE>,<MO>,<DA>,<HR>,<MI>,<SE>,<MS> to be used in the
    message (which is passed to ATTR(3f)).
    
    Note that time stamp keywords will only be updated when using ALERT(3f)
    and will only be displayed in color mode!
    

    OPTIONS

    TYPE     if present and one of 'warn','message','info', or 'debug'
             a predefined message is written to stderr of the form
    
              : <HR>:<MI>:<SE>.<MS> : (<ARG0>) : TYPE -> message
    
    MESSAGE  the user-supplied message to display via a call to ATTR(3f)
    
    g[0-9a-j]   optional values to print after the message. May
                be of type INTEGER, LOGICAL, REAL, DOUBLEPRECISION,
                COMPLEX, or CHARACTER.
    
    if no parameters are supplied the macros are updated but no output
    is generated.
    

    EXAMPLE

    Sample program
    
     program demo_alert
     use M_attr, only : alert, attr, attr_mode
     implicit none
     real X
      call attr_mode(manner='plain')
      call attr_mode(manner='color')
      call alert("error",&
                "Say you didn't!")
      call alert("warn", &
                "I wouldn't if I were you, Will Robinson.")
      call alert("info", &
                "I fixed that for you, but it was a bad idea.")
      call alert("debug", &
                "Who knows what is happening now?.")
      call alert("???    ",  "not today you don't")
      ! call to just update the macros
      call alert()
      ! conventional call to ATTR(3f) using the ALERT(3f)-defined macros
      write(*,*)attr(&
              '<bo>The year was <g><YE></g>, the month was <g><MO></g>')
      ! optional arguments
      X=211.3
      call alert('error',&
              'allowed range of X is 0 <lt> X <lt> 100, X=<r>',X)
      ! up to twenty values are allowed of intrinsic type
      call alert('info','values are<g>',10,234.567,&
              cmplx(11.0,22.0),123.456d0,'</g>today')
     end program demo_alert
    

    Results:

     00:38:30: (prg) : error    -> Say you didn't!
     00:38:30: (prg) : warning  -> I wouldn't if I were you, ...
                                   Will Robinson.
     00:38:30: (prg) : info     -> I fixed that for you,  ...
                                   but it was a bad idea.
     00:38:30: (prg) : debug    -> Who knows what is happening now?. ...
     00:38:30: (prg) : ???      -> not today you don't
     00:38:30: (prg) : error    -> allowed range of X is 0  X  100, ...
                                   X= 211.300003
     00:38:30: (prg) : info     -> values are 10 234.567001 ...
                                   (11.0000000,22.0000000) ...
                                   123.45600000000000 today
    

    AUTHOR

    John S. Urban, 2021
    

    LICENSE

    MIT
    

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in), optional :: type
    character(len=*), intent(in), optional :: message
    class(*), intent(in), optional :: g0
    class(*), intent(in), optional :: g1
    class(*), intent(in), optional :: g2
    class(*), intent(in), optional :: g3
    class(*), intent(in), optional :: g4
    class(*), intent(in), optional :: g5
    class(*), intent(in), optional :: g6
    class(*), intent(in), optional :: g7
    class(*), intent(in), optional :: g8
    class(*), intent(in), optional :: g9
    class(*), intent(in), optional :: ga
    class(*), intent(in), optional :: gb
    class(*), intent(in), optional :: gc
    class(*), intent(in), optional :: gd
    class(*), intent(in), optional :: ge
    class(*), intent(in), optional :: gf
    class(*), intent(in), optional :: gg
    class(*), intent(in), optional :: gh
    class(*), intent(in), optional :: gi
    class(*), intent(in), optional :: gj

public interface attr

  • private function attr_scalar(string, reset) result(expanded)

    NAME

    attr(3f) - [M_attr] substitute escape sequences for HTML-like syntax
               in strings
    (LICENSE:MIT)
    

    SYNOPSIS

      function attr(string,reset) result (expanded)
    
        ! scalar
        character(len=*),intent(in)  :: string
        logical,intent(in),optional  :: reset
        character(len=:),allocatable :: expanded
        ! or array
        character(len=*),intent(in)  :: string(:)
        logical,intent(in),optional  :: reset
        character(len=:),allocatable :: expanded(:)
        integer,intent(in),optional  :: chars
    

    DESCRIPTION

    Use HTML-like syntax to add attributes to terminal output such as
    color on devices that recognize ANSI escape sequences.
    

    OPTIONS

    string        input string  of form
    
                    "<attribute_name>string</attribute_name> ...".
    
                   where the current attributes are color names,
                   bold, italic, underline, ...
    
    reset          By default, a sequence to clear all text attributes
                   is sent at the end of each returned line if an escape
                   character appears in the output string. This can be
                   turned off by setting RESET to .false. .
    
                   Note if turning off the reset attributes may be
                   continued across lines, but if each line is not
                   self-contained attributes may not display properly
                   when filtered with commands such as grep(1).
    
    chars          For arrays, a reset will be placed after the Nth
                   displayable column count in order to make it easier
                   to generate consistent right borders for non-default
                   background colors for a text block.
    

    KEYWORDS

    primary default keywords
    
      colors:
        r,         red,       R,  RED
        g,         green,     G,  GREEN
        b,         blue,      B,  BLUE
        m,         magenta,   M,  MAGENTA
        c,         cyan,      C,  CYAN
        y,         yellow,    Y,  YELLOW
        e,         ebony,     E,  EBONY
        w,         white,     W,  WHITE
    
      attributes:
        it,        italic
        bo,        bold
        un,        underline
    
      basic control characters:
       nul
       bel  (0x07, ^G) beeps;
       bs   (0x08, ^H) backspaces one column (but not past the beginning of
                       the line);
       ht   (0x09, ^I) goes to the next tab stop or to the end of the line if
                       there is no earlier tab stop;
       lf   (0x0A, ^J),
       vt   (0x0B, ^K)
       ff   (0x0C, ^L) all give a linefeed, and if LF/NL (new-line mode) is
                       set also a carriage return
       cr   (0x0D, ^M) gives a carriage return;
       so   (0x0E, ^N) activates the G1 character set;
       si   (0x0F, ^O) activates the G0 character set;
       can  (0x18, ^X) and SUB (0x1A, ^Z) interrupt escape sequences;
       sub
       esc  (0x1B, ^[) starts an escape sequence;
       del  (0x7F) is ignored;
    
      other:
        clear
        default
        reset
        gt
        lt
        save,DECSC     Save  current state (cursor coordinates, attributes,
                       character sets pointed at by G0, G1).
        restore,DECRC  Restore state most recently saved by ESC 7.
        CSI            "Control Sequence Introducer"(0x9B) is equivalent to
                       "ESC [".
    
      dual-value (one for color, one for mono):
    
        write(*,*)attr('<ERROR>an error message')
        write(*,*)attr('<WARNING>a warning message')
        write(*,*)attr('<INFO>an informational message')
    
    By default, if the color mnemonics (ie. the keywords) are uppercase
    they change the background color. If lowercase, the foreground color.
    When preceded by a "/" character the attribute is returned to the
    default.
    
    The "default" keyword is typically used explicitly when reset=.false,
    and sets all text attributes to their initial defaults.
    

    LIMITATIONS

    o colors are not nestable, keywords are case-sensitive,
    o not all terminals obey the sequences. On Windows, it is best if
      you use Windows 10+ and/or the Linux mode; although it has worked
      with all CygWin and MinGW and Putty windows and mintty.
    o you should use "<gt>" and "<lt>" instead of ">" and "<" in a string
      processed by attr(3f) instead of in any plain text output so that
      the raw mode will create correct input for the attr(3f) function
      if read back in.
    

    EXAMPLE

    Sample program
    
     program demo_attr
     use M_attr, only : attr, attr_mode, attr_update
        call printstuff('defaults')
    
        call attr_mode(manner='plain')
        call printstuff('plain:')
    
        call printstuff('raw')
    
        call attr_mode(manner='color')
        call printstuff('')
    
        write(*,'(a)') attr('TEST ADDING A CUSTOM SEQUENCE:')
        call attr_update('blink',char(27)//'[5m')
        call attr_update('/blink',char(27)//'[25m')
        write(*,'(a)') attr('<blink>Items for Friday</blink>')
    
     contains
     subroutine printstuff(label)
     character(len=*),intent(in)  :: label
     character(len=:),allocatable :: array(:)
       call attr_mode(manner=label)
    
       array=[character(len=60) ::    &
        'TEST MANNER='//label,                      &
        '<r>RED</r>,<g>GREEN</g>,<b>BLUE</b>',      &
        '<c>CYAN</c>,<m>MAGENTA</g>,<y>YELLOW</y>', &
        '<w>WHITE</w> and <e>EBONY</e>']
       write(*,'(a)') attr(array)
    
       write(*,'(a)') attr('Adding <bo>bold</bo>')
       write(*,'(a)') attr('<bo><r>RED</r>,<g>GREEN</g>,<b>BLUE</b></bo>')
       write(*,'(a)') attr('<bo><c>CYAN</c>,<m>MAGENTA</g>,<y>YELLOW</y></bo>')
       write(*,'(a)') attr('<bo><w>WHITE</w> and <e>EBONY</e></bo>')
    
       write(*,'(a)') attr('Adding <ul>underline</ul>')
       write(*,'(a)') attr(&
        &'<bo><ul><r>RED</r>,<g>GREEN</g>,<b>BLUE</b></ul></bo>')
       write(*,'(a)') attr(&
        &'<bo><ul><c>CYAN</c>,<m>MAGENTA</g>,<y>YELLOW</y></ul></bo>')
       write(*,'(a)') attr('<bo><ul><w>WHITE</w> and <e>EBONY</e></ul></bo>')
    
       write(*,'(a)') attr('Adding <ul>italic</ul>')
       write(*,'(a)') attr(&
        &'<bo><ul><it><r>RED</r>,<g>GREEN</g>,<b>BLUE</b></it></ul></bo>')
       write(*,'(a)') attr(&
        &'<bo><ul><it><c>CYAN</c>,<m>MAGENTA</g>,<y>YELLOW</it></y></ul></bo>')
       write(*,'(a)') attr('<bo><ul><it><w>WHITE</w> and <e>EBONY</e></ul></bo>')
    
       write(*,'(a)') attr('Adding <in>inverse</in>')
       write(*,'(a)') attr('<in><bo><ul><it><r>RED</r>,<g>GREEN</g>,&
        &<b>BLUE</b></it></ul></bo></in>')
       write(*,'(a)') attr('<in><bo><ul><it><c>CYAN</c>,<m>MAGENTA</g>,&
        &<y>YELLOW</it></y></ul></bo></in>')
       write(*,'(a)') attr(&
        &'<in><bo><ul><it><w>WHITE</w> and <e>EBONY</e></ul></bo></in>')
     end subroutine printstuff
     end program demo_attr
    

    AUTHOR

    John S. Urban, 2021
    

    LICENSE

    MIT
    

    SEE ALSO

    attr_mode(3f), attr_update(3f)
    

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in) :: string
    logical, intent(in), optional :: reset

    Return Value character(len=:), allocatable

  • private function attr_matrix(strings, reset, chars) result(expanded)

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in) :: strings(:)
    logical, intent(in), optional :: reset
    integer, intent(in), optional :: chars

    Return Value character(len=:), allocatable, (:)

  • private function attr_scalar_width(string, reset, chars) result(expanded)

    Arguments

    Type IntentOptional Attributes Name
    character(len=*), intent(in) :: string
    logical, intent(in), optional :: reset
    integer, intent(in) :: chars

    Return Value character(len=:), allocatable


Subroutines

public subroutine alert(type, message, g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj)

!>

Read more…

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in), optional :: type
character(len=*), intent(in), optional :: message
class(*), intent(in), optional :: g0
class(*), intent(in), optional :: g1
class(*), intent(in), optional :: g2
class(*), intent(in), optional :: g3
class(*), intent(in), optional :: g4
class(*), intent(in), optional :: g5
class(*), intent(in), optional :: g6
class(*), intent(in), optional :: g7
class(*), intent(in), optional :: g8
class(*), intent(in), optional :: g9
class(*), intent(in), optional :: ga
class(*), intent(in), optional :: gb
class(*), intent(in), optional :: gc
class(*), intent(in), optional :: gd
class(*), intent(in), optional :: ge
class(*), intent(in), optional :: gf
class(*), intent(in), optional :: gg
class(*), intent(in), optional :: gh
class(*), intent(in), optional :: gi
class(*), intent(in), optional :: gj

public subroutine attr_mode(manner)

!>

Read more…

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: manner

public subroutine attr_update(key, valin, mono_valin)

!>

Read more…

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: key
character(len=*), intent(in), optional :: valin
character(len=*), intent(in), optional :: mono_valin