+++ /dev/null
-(* $Id$
- * ----------------------------------------------------------------------
- *
- *)
-
-open Pxp_types
-open Pxp_document
-
-
-(**********************************************************************)
-(* The box class represents formatted text *)
-(**********************************************************************)
-
-class type formatted_text =
- object
- method output : int -> int -> out_channel -> unit
- (* output initial_indent indent ch:
- * 'initial_indent' is how far the first line should be indented;
- * 'indent' how far the rest. 'ch' is the channel on which the lines
- * are to be printed.
- *)
-
- method multiline : bool
- (* whether the box occupies multiple lines *)
-
- method width_of_last_line : int
- (* returns the width of the last line *)
- end
-;;
-
-
-type text =
- Text of string
- | Box of formatted_text
-;;
-
-
-let textwidth tl =
- let rec compute tl r =
- match tl with
- [] -> r
- | t :: tl' ->
- begin match t with
- Text s ->
- compute tl' (r + String.length s)
- | Box b ->
- if b # multiline then
- compute tl' (b # width_of_last_line)
- else
- compute tl' (r + b # width_of_last_line)
- end
- in
- compute (List.rev tl) 0
-;;
-
-
-class box the_initial_width the_width =
- object (self)
-
- (* The 'initial_width' is the width that is available on the first
- * line of output; the 'width' is the width that is available in the
- * rest.
- *)
-
- val initial_width = the_initial_width
- val width = the_width
-
- (* state: *)
-
- val mutable space_added = false
- val mutable linefeed_added = false
- val mutable is_first_line = true
- val mutable lines = []
- (* lines in reverse order (first line = last element) *)
- val mutable current_line = []
- (* not member of 'lines'; again reverse order *)
- val mutable current_indent = 0
-
- method add_space =
- if not space_added then begin
- space_added <- true;
- linefeed_added <- true;
- current_line <- Text " " :: current_line
- end
-
- method ignore_space =
- space_added <- true;
- linefeed_added <- true
-
- method add_linefeed =
- if not linefeed_added then begin
- linefeed_added <- true;
- if not space_added then
- current_line <- Text " " :: current_line
- end
-
- method ignore_linefeed =
- linefeed_added <- true
-
- method add_newline =
- lines <- current_line :: lines;
- current_line <- [];
- space_added <- true;
- linefeed_added <- true;
- is_first_line <- false;
- current_indent <- 0;
-
- method add_word s =
- (* first try to add 's' to 'current_line' *)
- let current_line' = Text s :: current_line in
- let current_width =
- if is_first_line then initial_width else width in
- if textwidth current_line' + current_indent <= current_width then begin
- (* ok, the line does not become too long *)
- current_line <- current_line';
- space_added <- false;
- linefeed_added <- false
- end
- else begin
- (* The line would be too long. *)
- lines <- current_line :: lines;
- current_line <- [Text s];
- space_added <- false;
- linefeed_added <- false;
- is_first_line <- false;
- current_indent <- 0;
- end
-
- method add_box b =
- current_line <- Box b :: current_line;
- space_added <- false;
- linefeed_added <- false;
-
-
- method width_of_last_line =
- textwidth current_line + current_indent
-
-
- method available_width =
- let current_width =
- if is_first_line then initial_width else width in
- current_width - textwidth current_line - current_indent
-
-
- method multiline =
- lines <> [] or
- (List.exists
- (function
- Text _ -> false
- | Box b -> b # multiline)
- current_line)
-
- method output initial_indent indent ch =
- let eff_lines =
- List.rev
- (current_line :: lines) in
- let rec out_lines cur_indent ll =
- match ll with
- [] -> ()
- | l :: ll' ->
- output_string ch (String.make cur_indent ' ');
- List.iter
- (function
- Text s ->
- output_string ch s
- | Box b ->
- b # output 0 indent ch
- )
- (List.rev l);
- if ll' <> [] then
- output_string ch "\n";
- out_lines indent ll'
- in
- out_lines initial_indent eff_lines
- end
-;;
-
-
-class listitem_box listmark indent totalwidth =
- let initial_newline = String.length listmark >= indent in
- object (self)
- inherit box totalwidth (totalwidth - indent) as super
-
- val extra_indent = indent
-
- initializer
- self # add_word listmark;
- if initial_newline then
- self # add_newline
- else begin
- current_line <- Text (String.make (indent - String.length listmark) ' ')
- :: current_line;
- space_added <- true;
- linefeed_added <- true;
- end
-
-
- method output initial_indent indent ch =
- super # output initial_indent (indent + extra_indent) ch
- end
-;;
-
-
-(**********************************************************************)
-(* Footnotes etc. *)
-(**********************************************************************)
-
-
-class type footnote_printer =
- object
- method footnote_to_box : store_type -> box -> unit
- end
-
-and store_type =
- object
- method alloc_footnote : footnote_printer -> int
- method print_footnotes : box -> unit
- end
-;;
-
-
-class store =
- object (self)
-
- val mutable footnotes = ( [] : (int * footnote_printer) list )
- val mutable next_footnote_number = 1
-
- method alloc_footnote n =
- let number = next_footnote_number in
- next_footnote_number <- number+1;
- footnotes <- footnotes @ [ number, n ];
- number
-
- method print_footnotes (b : box) =
- if footnotes <> [] then begin
- b # add_newline;
- b # add_newline;
- let w = b # available_width in
- b # add_word (String.make (w/3) '-');
- b # add_newline;
- b # add_newline;
- List.iter
- (fun (_,n) ->
- n # footnote_to_box (self : #store_type :> store_type) b)
- footnotes;
- b # add_newline;
- end
- end
-;;
-
-
-
-(**********************************************************************)
-(* The extension objects *)
-(**********************************************************************)
-
-
-class virtual shared =
- object (self)
-
- (* --- default_ext --- *)
-
- val mutable node = (None : shared node option)
-
- method clone = {< >}
- method node =
- match node with
- None ->
- assert false
- | Some n -> n
- method set_node n =
- node <- Some n
-
- (* --- virtual --- *)
-
- method virtual to_box : store -> box -> unit
- (* to_box store b:
- * formats the element using box 'b'
- *)
- end
-;;
-
-
-class only_data =
- object (self)
- inherit shared
-
- val white_space_re = Str.regexp "[ \t]+\\|\n"
-
- method to_box store b =
- let s = self # node # data in
- let splitted = Str.full_split white_space_re s in
- List.iter
- (function
- Str.Delim "\n" ->
- b # add_linefeed
- | Str.Delim _ ->
- b # add_space
- | Str.Text s ->
- b # add_word s)
- splitted
- end
-;;
-
-
-class no_markup =
- object (self)
- inherit shared
-
- method to_box store b =
- List.iter
- (fun n -> n # extension # to_box store b)
- (self # node # sub_nodes)
- end
-;;
-
-
-class readme =
- object (self)
- inherit shared
-
- method to_box store b =
- let title =
- match self # node # attribute "title" with
- Value s -> s
- | _ -> assert false
- in
- let w = b # available_width in
- let line = String.make (w-1) '*' in
- b # add_word line;
- b # add_newline;
- b # add_word title;
- b # add_newline;
- b # add_word line;
- b # add_newline;
- b # add_newline;
- (* process main content: *)
- List.iter
- (fun n -> n # extension # to_box store b)
- (self # node # sub_nodes);
- (* now process footnotes *)
- store # print_footnotes b;
- (* trailer *)
- b # add_newline;
- end
-;;
-
-
-class section the_tag =
- object (self)
- inherit shared
-
- val tag = the_tag
-
- method to_box store b =
- let sub_nodes = self # node # sub_nodes in
- match sub_nodes with
- title_node :: rest ->
- b # add_newline;
- let w = b # available_width in
- let line = String.make (w-1) tag in
- b # add_word line;
- b # add_newline;
- b # add_word (title_node # data);
- b # add_newline;
- b # add_word line;
- b # add_newline;
- List.iter
- (fun n ->
- n # extension # to_box store b)
- rest;
- | _ ->
- assert false
- end
-;;
-
-class sect1 = section '=';;
-class sect2 = section '-';;
-class sect3 = section ':';;
-
-
-class p =
- object (self)
- inherit shared
-
- method to_box store b =
- let within_list =
- match self # node # parent # node_type with
- T_element "li" -> true
- | T_element _ -> false
- | _ -> assert false
- in
- if not within_list then
- b # add_newline;
- let w = b # available_width in
- let b' = new box w w in
- b' # ignore_space;
- List.iter
- (fun n -> n # extension # to_box store b')
- (self # node # sub_nodes);
- b # add_box (b' :> formatted_text);
- b # add_newline;
- end
-;;
-
-
-class li =
- object (self)
- inherit shared
-
- method to_box store b =
- b # add_newline;
- let w = b # available_width in
- let b' = new listitem_box "-" 3 w in
- b' # ignore_space;
- List.iter
- (fun n -> n # extension # to_box store b')
- (self # node # sub_nodes);
- b # add_box (b' :> formatted_text);
- end
-;;
-
-
-class code =
- object (self)
- inherit shared
-
- method to_box store b =
- b # add_newline;
- let w = b # available_width in
- let b' = new box w w in
- b' # ignore_space;
- let data = self # node # data in
- (* convert tabs *)
- let l = String.length data in
- let rec add s i column =
- (* this is very ineffective but comprehensive: *)
- if i < l then
- match data.[i] with
- '\t' ->
- let n = 8 - (column mod 8) in
- add (s ^ String.make n ' ') (i+1) (column + n)
- | '\n' ->
- b' # add_word s;
- b' # add_newline;
- add "" (i+1) 0
- | c ->
- add (s ^ String.make 1 c) (i+1) (column + 1)
- else
- if s <> "" then begin
- b' # add_word s;
- b' # add_newline;
- end
- in
- add "" 0 0;
- b # add_box (b' :> formatted_text);
- b # add_newline;
- end
-;;
-
-
-class br =
- object (self)
- inherit shared
-
- method to_box store b =
- b # add_newline;
- end
-;;
-
-
-class footnote =
- object (self)
- inherit shared
-
- val mutable footnote_number = 0
-
- method to_box store b =
- let number =
- store # alloc_footnote (self : #shared :> footnote_printer) in
- footnote_number <- number;
- b # add_space;
- b # add_word ("[" ^ string_of_int number ^ "]");
-
- method footnote_to_box store b =
- let w = b # available_width in
- let n = "[" ^ string_of_int footnote_number ^ "]" in
- let b' = new listitem_box n 6 w in
- b' # ignore_space;
- List.iter
- (fun n -> n # extension # to_box store b')
- (self # node # sub_nodes);
- b # add_box (b' :> formatted_text);
- b # add_newline;
- b # add_newline;
-
- end
-;;
-
-
-class a =
- object (self)
- inherit shared
-
- val mutable footnote_number = 0
- val mutable a_href = ""
-
- method to_box store b =
- let href =
- match self # node # attribute "href" with
- Value v -> "see " ^ v
- | Valuelist _ -> assert false
- | Implied_value ->
- begin match self # node # attribute "readmeref" with
- Value v -> "see file " ^ v
- | Valuelist _ -> assert false
- | Implied_value ->
- ""
- end
- in
- a_href <- href;
- List.iter
- (fun n -> n # extension # to_box store b)
- (self # node # sub_nodes);
- if href <> "" then begin
- let number =
- store # alloc_footnote (self : #shared :> footnote_printer) in
- footnote_number <- number;
- b # add_space;
- b # add_word ("[" ^ string_of_int number ^ "]");
- end
-
- method footnote_to_box store b =
- if a_href <> "" then begin
- let w = b # available_width in
- let n = "[" ^ string_of_int footnote_number ^ "]" in
- let b' = new listitem_box n 6 w in
- b' # ignore_space;
- b' # add_word a_href;
- b # add_box (b' :> formatted_text);
- b # add_newline;
- b # add_newline;
- end
- end
-;;
-
-(**********************************************************************)
-
-open Pxp_yacc
-
-let tag_map =
- make_spec_from_alist
- ~data_exemplar:(new data_impl (new only_data))
- ~default_element_exemplar:(new element_impl (new no_markup))
- ~element_alist:
- [ "readme", (new element_impl (new readme));
- "sect1", (new element_impl (new sect1));
- "sect2", (new element_impl (new sect2));
- "sect3", (new element_impl (new sect3));
- "title", (new element_impl (new no_markup));
- "p", (new element_impl (new p));
- "br", (new element_impl (new br));
- "code", (new element_impl (new code));
- "em", (new element_impl (new no_markup));
- "ul", (new element_impl (new no_markup));
- "li", (new element_impl (new li));
- "footnote", (new element_impl (new footnote : #shared :> shared));
- "a", (new element_impl (new a : #shared :> shared));
- ]
- ()
-;;
-
-
-
-
-(* ======================================================================
- * History:
- *
- * $Log$
- * Revision 1.1 2000/11/17 09:57:31 lpadovan
- * Initial revision
- *
- * Revision 1.5 2000/08/22 14:34:25 gerd
- * Using make_spec_from_alist instead of make_spec_from_mapping.
- *
- * Revision 1.4 2000/08/18 21:15:25 gerd
- * Minor updates because of PXP API changes.
- *
- * Revision 1.3 2000/07/08 17:58:17 gerd
- * Updated because of PXP API changes.
- *
- * Revision 1.2 2000/06/04 20:25:38 gerd
- * Updates because of renamed PXP modules.
- *
- * Revision 1.1 1999/08/22 22:29:32 gerd
- * Initial revision.
- *
- *
- *)