From: John M. Adams
Subject: string printing within specified margins
Date: 
Message-ID: <xaoya2es6td.fsf@anarky.sogs.stsci.edu>
    Given a long string, 
    what is a natural way
    to print it within 
    certain margins, like
    this?

With all the power of format and pretty-printing, it seems like
there ought to be a way, but I'm not getting it.

Thanks alot.

From: Erik Naggum
Subject: Re: string printing within specified margins
Date: 
Message-ID: <3174309221400582@naggum.net>
* John M. Adams
|     Given a long string, 
|     what is a natural way
|     to print it within 
|     certain margins, like
|     this?
| 
| With all the power of format and pretty-printing, it seems like
| there ought to be a way, but I'm not getting it.

(let ((*print-miser-width* 0)
      (*print-right-margin* 20))
  (format t ··@<Given a long string, what is a natural way to print it within certain margins, like ······@:>"))
Given a long
string, what is a
natural way to
print it within
certain margins,
like this?
=> nil

  I haven't found (in five minutes) a good way to make this work for
  an argument string instead of a constant string.

#:Erik
-- 
  If this is not what you expected, please alter your expectations.
From: Duane Rettig
Subject: Re: string printing within specified margins
Date: 
Message-ID: <4r986s01u.fsf@beta.franz.com>
Erik Naggum <····@naggum.net> writes:

> * John M. Adams
> |     Given a long string, 
> |     what is a natural way
> |     to print it within 
> |     certain margins, like
> |     this?
> | 
> | With all the power of format and pretty-printing, it seems like
> | there ought to be a way, but I'm not getting it.
> 
> (let ((*print-miser-width* 0)
>       (*print-right-margin* 20))
>   (format t ··@<Given a long string, what is a natural way to print it within certain margins, like ······@:>"))
> Given a long
> string, what is a
> natural way to
> print it within
> certain margins,
> like this?
> => nil
> 
>   I haven't found (in five minutes) a good way to make this work for
>   an argument string instead of a constant string.

Well, this is a stretch, but:

USER(1): (setq string "Given a long string, what is a natural way to print it within certain margins, like this?")
"Given a long string, what is a natural way to print it within certain margins, like this?"
USER(2): (let ((*print-miser-width* 0)
               (*print-right-margin* 20))
           (format t "~?" (concatenate 'string ··@<" string ··@:>") nil))
Given a long
string, what is a
natural way to
print it within
certain margins,
like this?
NIL
USER(3): 

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: David Bakhash
Subject: Re: string printing within specified margins
Date: 
Message-ID: <c29g0ohfcsf.fsf@mint-square.mit.edu>
Duane Rettig <·····@franz.com> writes:

> Erik Naggum <····@naggum.net> writes:
> 
> > * John M. Adams
> > |     Given a long string, 
> > |     what is a natural way
> > |     to print it within 
> > |     certain margins, like
> > |     this?
> > | 
> > | With all the power of format and pretty-printing, it seems like
> > | there ought to be a way, but I'm not getting it.
> > 
> > (let ((*print-miser-width* 0)
> >       (*print-right-margin* 20))
> >   (format t ··@<Given a long string, what is a natural way to print it within certain margins, like ······@:>"))
> > Given a long
> > string, what is a
> > natural way to
> > print it within
> > certain margins,
> > like this?
> > => nil
> > 
> >   I haven't found (in five minutes) a good way to make this work for
> >   an argument string instead of a constant string.
> 
> Well, this is a stretch, but:
> 
> USER(1): (setq string "Given a long string, what is a natural way to print it within certain margins, like this?")
> "Given a long string, what is a natural way to print it within certain margins, like this?"
> USER(2): (let ((*print-miser-width* 0)
>                (*print-right-margin* 20))
>            (format t "~?" (concatenate 'string ··@<" string ··@:>") nil))
> Given a long
> string, what is a
> natural way to
> print it within
> certain margins,
> like this?
> NIL
> USER(3): 

Given that Duane probably knows exactly how ACL works, he probably could 
have solved this problem for ACL, and with the left margins also
settable, as the original poster cared to know.  I also havn't been able 
to figure out how to do this with #'FORMAT.  I'm happen to not be a
FORMAT wizard in any way.

Having used ACL quite a bit myself, I see that printing seems to always
go through the generic function #'STREAM-WRITE-CHAR.  This is kinda
interesting, since in the case above, if what's left is this issue of
getting our left margins, then we know we can accomplish this if we
could define a local after method to #'STREAM-WRITE-CHAR such that it
prints some whitespace after printing a newline character:

(defmethod stream-write-char :after (stream char)
  (when (member char '(#\newline #\return) :test #'char=)
    (format stream "<left margin>")))

now, of course in the case that was proposed by the original poster,
this was not supposed to happen globally, and so, ideally we'd want to
define the above :after method locally, as with FLET.  But since you
can't count on GENERIC-FLET being there, and I'm not sure that it ever
_was_ designed to work in the above scenario (see:

http://www.xanalys.com/software_tools/reference/HyperSpec/Issues/iss181-writeup.html 

for some background) I'm not too sure how this could be done right.  And 
then, of course you have portability to worry about.  Of course, you can 
do some hack where you only print the left margin when some global
variable is also non-nil and just set that in your program.

(defvar *print-left-margin* nil)

;; unchecked:
(defmethod stream-write-char :after (stream char)
  (when (and (member char '(#\newline #\return) :test #'char=)
	     *print-left-margin*)
    (format stream "~T" *print-left-margin*)))

If you're using ACL, then this solution will work.  Problem is that
you've just added a global generic function that's gonna get called
every single time a character is printed to _any_ stream.

If someone knows how to get the effect I'm looking for, i.e. with
something like GENERIC-FLET that works like FLET but for generic
functions, then I'd be interested.  Ideally, we want to define the
:after method above for the dynamic extent of its body forms, and
nothing more.  

dave
From: Tim Bradshaw
Subject: Re: string printing within specified margins
Date: 
Message-ID: <ey3snshoygt.fsf@cley.com>
* David Bakhash wrote:

> now, of course in the case that was proposed by the original poster,
> this was not supposed to happen globally, and so, ideally we'd want to
> define the above :after method locally, as with FLET.  But since you
> can't count on GENERIC-FLET being there, and I'm not sure that it ever
> _was_ designed to work in the above scenario (see:

> http://www.xanalys.com/software_tools/reference/HyperSpec/Issues/iss181-writeup.html 

> for some background) I'm not too sure how this could be done right.  And 
> then, of course you have portability to worry about.  Of course, you can 
> do some hack where you only print the left margin when some global
> variable is also non-nil and just set that in your program.

You want to have something like encapsulating stream -- a stream which
you can wrap round another one and for which almost all methods punt
to the encapsulated stream.  Then you can say something like:

 (let ((s (make-instance 'filling-stream :stream s :fill-column 76)))
   ... do things with s ...)

If you have some well-defined protocol which a stream needs to follow,
like Gray streams here, then you can use elaborate macrology to define
these encapsulating classes fairly mechanically.  Alternatively (and
better, I think) you can define by hand a root class of encapsulating
streams which simply punt all operations in the protocol to the
encapsulated stream, and then subclass it, perhaps using mixins to be
able to create streams which wrap just the operations you are
interested in.

You do end up consing an encapsulating stream every time you need to
locally modify some behaviour unless you have an implementation which
can stack-cons instances.  It's also still somewhat more heavyweight
than something like GENERIC-FLET could perhaps be, if it existed.

This is probably a design pattern, of course.

--tim
From: Duane Rettig
Subject: Re: string printing within specified margins
Date: 
Message-ID: <4zompj7jz.fsf@beta.franz.com>
David Bakhash <·····@alum.mit.edu> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > Erik Naggum <····@naggum.net> writes:
> > 
> > > * John M. Adams
> > > |     Given a long string, 
> > > |     what is a natural way
> > > |     to print it within 
> > > |     certain margins, like
> > > |     this?
> > 
> > USER(1): (setq string "Given a long string, what is a natural way to print it within certain margins, like this?")
> > "Given a long string, what is a natural way to print it within certain margins, like this?"
> > USER(2): (let ((*print-miser-width* 0)
> >                (*print-right-margin* 20))
> >            (format t "~?" (concatenate 'string ··@<" string ··@:>") nil))
> 
> Given that Duane probably knows exactly how ACL works, he probably could 
> have solved this problem for ACL, and with the left margins also
> settable, as the original poster cared to know.

Both Erik and I either ignored or didn't notice the left margin.  It's
trivial to do this using format, without using either Allegro CL specific
features or Gray streams:

USER(1): (setq string "Given a long string, what is a natural way to print it within certain margins, like this?")
"Given a long string, what is a natural way to print it within certain margins, like this?"
USER(2): (let ((*print-miser-width* 0)
(*print-right-margin* 24))
(format t "~?" (concatenate 'string ··@<    ~;" string ··@:>") nil))
    Given a long
    string, what is a
    natural way to
    print it within
    certain margins,
    like this?
NIL
USER(3): 

More general (i.e. parameterized) solutions should also be easy.

>  I also havn't been able 
> to figure out how to do this with #'FORMAT.  I'm happen to not be a
> FORMAT wizard in any way.

Neither am I, though I do have access to source.  Instead, I read the
chapter in the CL spec called "Tilde Less Than Sign: Logical Block".

> Having used ACL quite a bit myself, I see that printing seems to always
> go through the generic function #'STREAM-WRITE-CHAR.

This will no longer be true in Allegro CL 6.0 (though you could, using a
compatibility module, create a Gray stream specifically, where the generic
function is used).  An early version of the document describing the
new streams implementation is available at

http://www.franz.com/support/documentation/simple-stream.htm

This document is slightly out-of-date; changes have been made, both to the
design and documentation, based on user inputs form a previous posting on
comp.lang.lisp, .  The most recent documentation is currently only available
in the documentation set bundled in the product (which we are readying for
beta test very shortly).  The kinds of changes that are not in the above
documentation include the addition of stream encapsulation and clarification
of some of the concepts.  But the above document should be understandable
and should give you a feel for the direction we are headed.

>                This is kinda
> interesting, since in the case above, if what's left is this issue of
> getting our left margins, then we know we can accomplish this if we
> could define a local after method to #'STREAM-WRITE-CHAR such that it
> prints some whitespace after printing a newline character:
> 
   [ ... ]
> 
> If you're using ACL, then this solution will work.  Problem is that
> you've just added a global generic function that's gonna get called
> every single time a character is printed to _any_ stream.

Your proposal is possible, and others have done similar things, but
your conclusion is a strong argument for why such an approach should
not be used, and many who explore this design path come to conclude that
other means should be used instead.  In this particular situation the
answer is to use the already-available solution.

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: David Bakhash
Subject: Re: string printing within specified margins
Date: 
Message-ID: <c29bsz4gamt.fsf@mint-square.mit.edu>
Duane Rettig <·····@franz.com> writes:

> David Bakhash <·····@alum.mit.edu> writes:
> >  I also havn't been able 
> > to figure out how to do this with #'FORMAT.  I happen to not be a
> > FORMAT wizard in any way.
> 
> Neither am I, though I do have access to source.  Instead, I read the
> chapter in the CL spec called "Tilde Less Than Sign: Logical Block".

yeah.  thanks for figuring out how to use FORMAT to get that solution.
It's pretty useful.  

also, thanks for the link regarding the new streams implementation.
it'll be interesting to read how they're gonna change, and why.

dave
From: David Bakhash
Subject: Re: string printing within specified margins
Date: 
Message-ID: <c29punqqi1u.fsf@nerd-xing.mit.edu>
·······@stsci.edu (John M. Adams) writes:

>     Given a long string, 
>     what is a natural way
>     to print it within 
>     certain margins, like
>     this?
> 
> With all the power of format and pretty-printing, it seems like
> there ought to be a way, but I'm not getting it.

I think that the way to go is to use format to get a string , i.e.

(format nil ...)

and then loop over the characters, only breaking lines on whitespace.
You will need look-ahead of more than one chararacter to do it right,
but it's still relatively simple, I think.  It's just not a #'format
option, but you probably won't have too much trouble implementing it.

dave