home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / plbin.zip / pl / library / tty.pl < prev    next >
Text File  |  1992-05-26  |  7KB  |  272 lines

  1. /*  tty.pl,v 1.1.1.1 1992/05/26 11:51:38 jan Exp
  2.  
  3.     Copyright (c) 1990 Jan Wielemaker. All rights reserved.
  4.     jan@swi.psy.uva.nl
  5.  
  6.     Purpose: Simple terminal support
  7. */
  8.  
  9. :- module(tty,
  10.     [ tty_clear/0
  11.     , tty_flash/0
  12.     , tty_size/2
  13.     , menu/3
  14.     ]).
  15.  
  16. :- use_module(library(ctypes), [is_digit/1, to_lower/2]).
  17.  
  18. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  19.                    TERMINAL OPERATIONS
  20.  
  21. This library package defines some common  operations on terminals.  It
  22. is based on the Unix termcap facility  to perform terminal independant
  23. I/O on video displays.  The package consists of three sections:
  24.  
  25.   1) Predicates to perform simple operations on terminals
  26.   2) Extenstions to format/2 to include cursor position and clearing
  27.      sections of the screen.
  28.   3) A generic predicate to build simple menus.
  29.  
  30.                   BUGS
  31.  
  32. The stream  information  on the   terminal related  streams    is  not
  33. maintained by these predicates.
  34. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35.  
  36. %    tty_size(-Width, -Height)
  37. %    Get the size of the terminal in characters.
  38.  
  39. tty_size(Width, Height) :-
  40.     tty_get_capability(co, number, Width),
  41.     tty_get_capability(li, number, Height).
  42.  
  43. %    tty_clear/0
  44. %    Clear the display.
  45.  
  46. tty_clear :-
  47.     string_action(cl).
  48.  
  49. %    tty_flash/0
  50. %    Give visual signal if possible, otherwise beep.
  51.  
  52. tty_flash :-
  53.     tty_get_capability(vb, string, Vb), !,
  54.     tty_put(Vb, 1).
  55. tty_flash :-
  56.     put(7).
  57.  
  58. %    string_action(+Name)
  59. %    Send string from the termcap library with specified name.
  60.  
  61. string_action(Name) :-
  62.     tty_get_capability(Name, string, String),
  63.     tty_put(String, 1).
  64.  
  65. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  66.                  FORMAT
  67.  
  68. The functions below add some extras to the format facilities.  This to
  69. simplify screen management.  It adds ~T to the set of format characters.
  70. The argument to ~T is a (list of) tty control commands.  The ~l command
  71. is defined to clear to the end of the line before generating a newline.
  72.  
  73. Example:
  74.  
  75. ?- format('~T~3l', home),
  76.    format('    1) Hello World~l'),
  77.    format('    2) Exit~2l'),
  78.    format('    Your choice? ~T', [clear_display, flush]),
  79.    get_single_char(X).
  80. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  81.  
  82. :- format_predicate('T', tty_action(_Arg, _What)).
  83. :- format_predicate('l', tty_nl(_Args)).
  84.  
  85. tty_action(_, What) :-
  86.     tty_action(What).
  87.  
  88. tty_action([]) :- !.
  89. tty_action([A|B]) :- !,
  90.     tty_action(A),
  91.     tty_action(B).
  92. tty_action(goto(X,Y)) :- !,
  93.     tty_goto(X, Y).
  94. tty_action(home) :- !,
  95.     tty_goto(0, 0).
  96. tty_action(flush) :- !,
  97.     ttyflush.
  98. tty_action(center(Text)) :- !,
  99.     tty_size(W, _),
  100.     format('~t~a~t~*|', [Text, W]).
  101. tty_action(back(N)) :- !,
  102.     between(1, N, _),
  103.         put(8),
  104.     fail ; true.
  105. tty_action(Long) :-
  106.     abbreviation(Long, Short), !,
  107.     string_action(Short).
  108. tty_action(Short) :-
  109.     string_action(Short).
  110.  
  111. abbreviation(clear,        cl).        % clear and home
  112. abbreviation(clear_line,    ce).        % clear-to-end-of-line
  113. abbreviation(clear_display,    cd).        % clear-to-end-of-display
  114.  
  115. tty_nl(default) :- !,
  116.     tty_nl(1).
  117. tty_nl(N) :-
  118.     tty_get_capability(ce, string, Ce),
  119.     between(1, N, _),
  120.         tty_put(Ce, 1),        
  121.         nl,
  122.     fail ; true.
  123.  
  124. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  125.                      MENU
  126.  
  127. The  package below is  a simple package  to  show (short)  menus.  The
  128. entry point is the predicate menu/3, which is described below.
  129.  
  130. menu(+Title, +Options, -Choice)
  131.     Show a menu.  The display is cleared, the title is centered at
  132.     the top, the options are displayed and finally the user actions
  133.     are parsed and the user's choice is returned.
  134.  
  135.     The screen looks like this:
  136.  
  137.             --------------------------------------------
  138.         |                                          |
  139.         |                  Title               |
  140.             |                       |
  141.         |   1) Option One                          |
  142.         |   2) Option Two               |
  143.         |   3) Quit                   |
  144.         |                       |
  145.         |   Your Choice? *               |
  146.         |                       |
  147.  
  148.     The user selects an item by pressing the number of the item, or
  149.     the first letter of the option. If more then one option match,
  150.     the common prefix of the matching options is given and the user
  151.     is expected to type the next character.  On illegal input the
  152.     screen is flashed (or a beep is given if the terminal can't flash
  153.     the screen).
  154.  
  155.     Text fields (the title and option texts) are either plain atoms
  156.     or terms Fmt/Args.  In the latter case the argument is transformed
  157.     into an atom using sformat/3.
  158.  
  159.     The specification of an option is a term PrologName:UserName.
  160.     PrologName is an atom, which is returned as choice if the user
  161.     selects this menu item.  UserName is processed as a text field
  162.     (see above) and displayed.  The entries are numbered automatically.
  163.  
  164.     The example above could be defined as:
  165.  
  166.     get_action(Choice) :-
  167.         menu('Title',
  168.             [ option_1 : 'Option One'
  169.             , option_2 : 'Option Two'
  170.             , quit     : 'Quit'
  171.             ], Choice).
  172. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  173.  
  174. menu(Title, List, Choice) :-
  175.     show_title(Title),
  176.     build_menu(List),
  177.     get_answer(List, Choice).
  178.  
  179. show_title(Title) :-
  180.     to_text(Title, T),
  181.     format('~T~l~T~2l', [home, center(T)]).
  182.  
  183. build_menu(List) :-
  184.     build_menu(List, 1),
  185.     format('~2n      Your choice? ~T', clear_display).
  186.  
  187. build_menu([], _).
  188. build_menu([_:H|T], N) :-
  189.     to_text(H, TH),
  190.     format('~t~d~6|) ~a~l', [N, TH]),
  191.     succ(N, NN),
  192.     build_menu(T, NN).
  193.  
  194. to_text(Fmt/Args, Text) :- !,
  195.     sformat(Text, Fmt, Args).
  196. to_text(Text, Text).
  197.  
  198. get_answer(List, Choice) :-
  199.     flag('$menu_feedback', _, 0),
  200.     get_answer(List, "", Choice).
  201.  
  202. get_answer(List, Prefix, Choice) :-
  203.     get_single_char(A),
  204.     process_answer(A, List, Prefix, NewPrefix, Ch, Ok),
  205.     (   Ok == yes
  206.     ->  Ch = Choice
  207.     ;   get_answer(List, NewPrefix, Choice)
  208.     ).
  209.  
  210. process_answer(127, _, _, "", _, no) :- !,
  211.     feedback('').
  212. process_answer(D, List, _, _, Choice, yes) :-
  213.     is_digit(D),
  214.     name(N, [D]),
  215.     nth1(N, List, Choice:Name), !,
  216.     feedback(Name).
  217. process_answer(N, _, _, "", _, no) :-
  218.     is_digit(N), !,
  219.     feedback(''),
  220.     tty_flash.
  221. process_answer(C, List, Prefix, NewPrefix, Choice, Ok) :-
  222.     append(Prefix, [C], NPrefix),
  223.     matching(List, NPrefix, Matching),
  224.     (   Matching == []
  225.     ->  tty_flash,
  226.         NewPrefix = Prefix,
  227.         Ok = no
  228.     ;   Matching = [Choice:Name]
  229.     ->  Ok = yes,
  230.         feedback(Name)
  231.     ;   common_prefix(Matching, NewPrefix),
  232.         feedback(NewPrefix),
  233.         Ok = no
  234.     ).
  235.  
  236. matching([], _, []).
  237. matching([H|T], Prefix, [H|R]) :-
  238.     prefix(Prefix, H), !,
  239.     matching(T, Prefix, R).
  240. matching([_|T], Prefix, R) :-
  241.     matching(T, Prefix, R).
  242.  
  243. prefix(Prefix, _:Name) :-
  244.     name(Name, Chars),
  245.     common_prefix_strings(Prefix, Chars, Prefix), !.
  246.  
  247. common_prefix([_:Name|T], Prefix) :-
  248.     name(Name, Chars),
  249.     common_prefix(T, Chars, Prefix).
  250.  
  251. common_prefix([], Prefix, Prefix).
  252. common_prefix([_:Name|T], Sofar, Prefix) :-
  253.     name(Name, Chars),
  254.     common_prefix_strings(Chars, Sofar, NewSofar),
  255.     common_prefix(T, NewSofar, Prefix).
  256.  
  257. common_prefix_strings([H1|T1], [H2|T2], [H1|R]) :-
  258.     to_lower(H1, Lower),
  259.     to_lower(H2, Lower), !,
  260.     common_prefix_strings(T1, T2, R).
  261. common_prefix_strings(_, _, []).
  262.  
  263. feedback(Text) :-
  264.     atomic(Text), !,
  265.     atom_length(Text, New),
  266.     flag('$menu_feedback', Old, New),
  267.     format('~T~a~T', [back(Old), Text, clear_line]).
  268. feedback(Text) :-
  269.     length(Text, New),
  270.     flag('$menu_feedback', Old, New),
  271.     format('~T~s~T', [back(Old), Text, clear_line]).
  272.