Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

anybody mind if I just ... already long have been

116 views
Skip to first unread message

luser- -droog

unread,
Jan 29, 2015, 12:40:34 AM1/29/15
to
abusing this usenet forum s some kind of personal
postscript blog??

Assuming 'no',

I finally cleaned some this old program I call 'ibis'
last posted in 2011 in a bugridden form.
https://github.com/luser-dr00g/ibis.ps/blob/master/ibis.ps

So the first bit of drama was fixing the bug(s).
'Convenient!' I thought to myself, 'that I now have
a debugger to use on it.'
https://github.com/luser-dr00g/debug.ps/blob/master/db5.ps
Then I had to debugger the debug debugging the buggy ibis.
(...5xfast).

So back to 'ibis'. First it does some little convenience
routine which I had conveniently commented % Utiliy
"Utility"?? Thanks, past self. See that? That's a stupid.
Wise up! ya baloney.

Next, it encapsulates the "device" info, and the "text-setting"
api, and this crazy function called 'find' which is mostly a
wrapper for `search`.

% find takes 3 procedures a string and search-string
% and executes on_a and on_b upon the returned substrings if found
% or the not procedure if not found
/find { % {not} {on_b} {on_a} (aXb) (X) find -
search { % n b a (b) (X) (a)
4 1 roll pop % n b (a) a (b)
4 1 roll % n (b) b (a) a
5 -1 roll pop % (b) b (a) a
/exec cvx 5 3 roll % (a) a exec (b) b
/exec cvx 6 array astore cvx exec
%exec exec
}{ % n b a (a_b)
4 1 roll pop pop % (a_b) n
exec
} ifelse
} def
%{(n)= =}{(b)= =}{(a)= =} (pretextpost) (text) find
%(stack:)= pstack
%quit

The three lines at the top are new, based on my current
understanding. My past self had left the stack comments
(bravo, self) and the testing comments (again, good job,
past self). But had utterly failed to simply say what
the dang thing does.

Then it does some really crazy stuff to try to generalize
the behavior of built-in commands.

I should backtrack and preface this whole discussion by
saying that, in a way, this is the program that I truly
wanted to write when I first set out to learn the
postscript language initially. And the main reason I
got an "incomplete" in Physics 101. I tried to do all
my reports in pure postscript. I was also the editor
of the Honors College newsmagazine at the time, but
was wise enough not to convert the whole thing to
postscript, because I knew I was not mature enough as
a programmer to accomplish anything in a timely manner.
Sloppy as it was, the Pagemaker template was already
created. But over the course of my editorship, I tweaked
every dang thing from front to back, eventually designing
new cover art for each issue. (with some hacked versions
of Photoshop and stuff supplied by a Malaysian kid in the
dorms)

So 'ibis' is very dear to my heart. Even though I abandoned
it for, um, 4 years. It's also very new because I just
picked it up again, having almost completely forgotten
about it.

The built-in commands like 'italics' and 'bold', attempt
to encapsulate an on/off behavior that can be applied
automatically to keep the state in sync with the expectations
of the markup language. I'm not sure how well I've
succeeded so far. It saves the currentfont as its "undo"
action, so effects can be undone in a stack-wise manner,
but not out-of-order as I'd really like it to do.

This is more-or-less the basic execution framework to which
I'd like to add things like line-fitting and justifying
and columns and tables and kerning and stuff.

Questions/Comments/Chit-chat?

$ cat ibis.ps
%!
%(debug.ps/db5.ps)run %currentfile cvx debug

%/show { dup print (\n) print show } bind def

% mark k1 v1 .. kN vN dicttomark dict(N)
/dicttomark { counttomark dup dict begin 2 idiv { def } repeat pop currentdict end } def

/-= { 1 index load exch sub store } def

% Composite Index inc/dec -
% (n.b. userdict is a composite object)
/inc { 2 copy get 1 add put } def
/dec { 2 copy get 1 sub put } def

% Stack type is an array where element 0 contains the index of the top of the stack
% n stack array{n+1}:[0]=0
/stack { 1 add array dup 0 0 put } def
/top { dup 0 get get } def % S top a
/spop { dup top exch 0 dec } def % S spop a (S{n}->S'(n-1})
/spush { % S a spush - (S{n}->S'{n+1})
1 index 0 inc
1 index 0 get exch put
} def

% output device
/dev mark
/size [ clippath pathbbox ]
/bounds null
dicttomark def
/savebounds { dev /bounds [ x y X Y ] put } def
/restorebounds { dev /bounds get aload pop setbounds } def
/setbounds { % x y X Y setbounds -
/Y exch def /X exch def /y exch def /x exch def
} def
/setmargin { % pts setmargin -
dev /size get aload pop
4 index sub 4 1 roll 4 index sub 4 1 roll
4 index add 4 1 roll 4 index add 4 1 roll
setbounds pop savebounds
} def

/nextpage { showpage restorebounds } def

% text setting
/text mark
/eol { /Y lead -=
y Y lt { x Y moveto }
{ nextpage } ifelse }
/heol { eol }
/blank { eol }
/settext { show }
dicttomark def

% processing
% find takes 3 procedures a string and search-string
% and executes on_a and on_b upon the returned substrings if found
% or the not procedure if not found
/find { % {not} {on_b} {on_a} (aXb) (X) find -
search { % n b a (b) (X) (a)
4 1 roll pop % n b (a) a (b)
4 1 roll % n (b) b (a) a
5 -1 roll pop % (b) b (a) a
/exec cvx 5 3 roll % (a) a exec (b) b
/exec cvx 6 array astore cvx exec
%exec exec
}{ % n b a (a_b)
4 1 roll pop pop % (a_b) n
exec
} ifelse
} def
%{(n)= =}{(b)= =}{(a)= =} (pretextpost) (text) find
%(stack:)= pstack
%quit

%shift a 1-char string off of a larger string
/first { % (abc) first (bc) (a)
dup 1 1 index length 1 sub getinterval exch
0 1 getinterval
} def

% delimiter pairs
/pairs mark
([)(]) (<)(>) (\()(\)) ({)(}) (`)(') (:)(;)
dicttomark def

% ([) rhs (])
% (q) rhs (q)
/rhs { pairs exch 2 copy known { get }{ exch pop } ifelse } def

/nest 10 stack def
% {on_a} (]) deferal {[{on_a} (])] nest exch spush}
% create a save-it-for-later proc
% for the not-found clause of find
/deferal {
2 array astore
[ exch /nest cvx /exch cvx /spush cvx ] cvx
} def

% {on_a} ([a]b) delim (b)
/delim {
exch /settext cvx exch /exec cvx 3 array astore cvx exch
first rhs % on_a (a]b) (])
3 copy exch pop % on_a (a]b) (]) on_a (])
deferal % on_a (a]b) (]) not %not-clause
{} % on_a (a]b) (]) not on_b %on_b clause: leave string on stack
5 2 roll % not on_b on_a (a]b) (])
%(delim)= pstack()=
find
} def

% ([arg]rem) /name short (rem)
/short {
alt exch get % s d
dup /ini get exec % s d ?
exch /fin get % s ? {}
[ 3 1 roll /exec cvx ] cvx exch % undo s
(short)= pstack()=
delim
} def

% str execute -
/execute { token { exec process }{ BAD_COMMAND } ifelse } def

% the "at" sign indicates the start of an embedded command
/sigil <40> def

% scan string for embedded @commands
% and call settext for other text.
/process { % str process -
%(process:)= pstack()=
dup length 0 eq { pop blank }{
{settext} {execute} {settext} 4 3 roll
sigil find
} ifelse
} def

% call process on each line
%
/src null def
/buf 200 string def
/exitflag false def
/ibis { % file|string ibis -
dup type /stringtype eq { (r) file } if
dup type /filetype ne { NOT_A_FILE } if
/src exch def

pstack()=
{
src buf readline {process}{process exit}ifelse
heol
exitflag { exit } if
} loop

showpage
} def

% @@ define the at-sign as a command to print itself
sigil { sigil settext } def


%alterations
/alt 20 dict def

% name dict newalter -
%
% dict should contain 2 procs
% - ini ?
% ? fin -
% where init returns an object that should be
% passed to final
/newalter {
%install in alt dict
2 copy alt 3 1 roll put
%create short-form procedure
pop [ 1 index /short cvx ] cvx def
%create long-form
} def

%/i mark /ini {currentfont /Palatino-Italic 10 selectfont} /fin {setfont} dicttomark newalter

%/name /fontname fontsize fontproc -
/fontproc {
/currentfont cvx 3 1 roll /selectfont cvx 4 array astore cvx
mark exch /ini exch /fin {setfont} dicttomark newalter
} def

/r /Palatino-Roman 10 fontproc
/b /Palatino-Bold 10 fontproc
/i /Palatino-Italic 10 fontproc

/default {
text begin
72 setmargin
%/Palatino-Roman 10 selectfont
alt /r get /ini get exec pop
/lead 12 def
%eol
} def

/bye {pstack()= /exitflag true def} def

%/i load == quit
%stepon
%traceon

default
%currentfile /ibis load debug
currentfile ibis
Text is passed to the output.
Only ragged-right, explicit linebreaks for now.

There are various ways of executing a command to change
a section of text. All commands are introduced by the @@ character,
known internally as the "sigil".

The simple command @@ i for italics, can use the short form
with various sets of delimiters.

@@ i[italics] @i[italics]
@@ i(italics) @i(italics)
@@ i<italics> @i<italics>
@@ i{italics} @i{italics}
@@ i `italics' @i `italics'
@@ i :italics; @i :italics;

These last two require an extra space after the command name since
the backquote and colon are not postscript delimiters.

Incidentally, since the command name is scanned with 'token' and
executed with 'exec', it can even be a postscript procedure.
@{/oldfont currentfont def}
@@ {/Courier 11 selectfont}text in Courier
@{/Courier 11 selectfont}text in Courier
@{oldfont setfont}
Only "short-form" commands take a delimited argument.
The @@ {arbitrary ps code} commands are not "short-form",
and do not take an argument but apply directly to the current state.

Now with @b[bold].


@bye
(stack:)= pstack(---)= currentfile flushfile



jdaw1

unread,
Jan 29, 2015, 4:34:15 AM1/29/15
to
> some kind of personal postscript blog??

No objection.

Mark Carroll

unread,
Jan 29, 2015, 12:44:55 PM1/29/15
to
jdaw1 <jdawi...@gmail.com> writes:

>> some kind of personal postscript blog??
>
> No objection.

Indeed. You at least post relevant on-topic stuff!

-- Mark

luser- -droog

unread,
Jan 30, 2015, 1:38:36 AM1/30/15
to
On Wednesday, January 28, 2015 at 11:40:34 PM UTC-6, luser- -droog wrote:
> https://github.com/luser-dr00g/ibis.ps/blob/master/ibis.ps
> https://github.com/luser-dr00g/debug.ps/blob/master/db5.ps
[snip]>
The "long form", the existence of which might be deducible from the
above looks like

@enter[i] ... @leave[i]

and these should allow arbitrary interleaving like

@enter[i] it @enter[b] it-bold @leave[i] bold @leave[b]

So, it needs a very different view of fonts, I think.
I needs to deal with a family of faces as a unit with
roman, bold, italic, and bold-italic selected by
flags (booleans).

With an array of fonts

/font-fam [ -roman- -italic- -bold- -bold+italic- ] def

Then using integers 0 and 1 for the flags, I can index
with

font-fam bold 2 mul italic add get

Then I can just maintain the variables, and set the font
in /settext so its always current when used.

I suppose lots of things might need simple controllable
representations like this.

luser- -droog

unread,
Jan 30, 2015, 3:35:16 AM1/30/15
to
On Friday, January 30, 2015 at 12:38:36 AM UTC-6, luser- -droog wrote:
> On Wednesday, January 28, 2015 at 11:40:34 PM UTC-6, luser- -droog wrote:
> > https://github.com/luser-dr00g/ibis.ps/blob/master/ibis.ps
> > https://github.com/luser-dr00g/debug.ps/blob/master/db5.ps
> [snip]>
> With an array of fonts
>
> /font-fam [ -roman- -italic- -bold- -bold+italic- ] def
>

Dammit! There's no /Palatino-Bold-Italic

Rod Dorman

unread,
Jan 30, 2015, 3:45:42 PM1/30/15
to
In article <7988e366-4e43-44e4...@googlegroups.com>,
But there is a Palatino-BoldItalic

--
-- Rod --
rodd(at)polylogics(dot)com

luser- -droog

unread,
Jan 31, 2015, 3:18:40 AM1/31/15
to
Awesome! It works!

Yves Cloutier

unread,
Feb 1, 2015, 9:42:19 PM2/1/15
to
Hello Droog, think what you are doing is really great and in fact would work well with my own project.

I am doing a higher-level markup for typesetting books. Here is an example of inline formatting commands:

Some <bold<text>. Some <bold, size +3<text>. Some <raise 3<superscript> text.

This is only a small example of a much more complete markup language. I currently generate Groff code, which can then get converted to .ps. However I would like to be able to skip the groff middleman and be able to generate .ps directly from my markup.

I just bought a couple books on ps to see how much of a learning curse I have a head of me. I came on this group to look up things like how to do page layout, footnotes and other basic typesetting stuff...at least to get started.

But after seeing ibi, what I'm thinking is perhaps I could get my markup to generate ibis markup.

Anyhow, really interested in your work and where you are headed with this.

Regards,

yves

luser- -droog

unread,
Feb 2, 2015, 2:04:16 AM2/2/15
to
Excellent. Glad you're interested. The goals are to
copy the syntax and styles from scribe, and
as many internal algorithms as possible from tex.
So things like explicitly increasing the font size
will be *possible*, but it's intended to separate
the appearance from the content by defining styles.

But in some ways, my track record on the project is
not good. It took me 4 years to get bold and italic
working. :)

This answer of mine has links to lots of related work:
http://tex.stackexchange.com/questions/64296/can-the-postscript-language-be-used-to-fully-replace-tex/170051#170051

For something "ready to use", I'd recommend looking
at anastigmatix's pages, and the "tinydict",

While I hope ultimately to surpass both of them,
it's still early days.

luser- -droog

unread,
Feb 3, 2015, 6:27:12 AM2/3/15
to
On Monday, February 2, 2015 at 1:04:16 AM UTC-6, luser- -droog wrote:
> On Sunday, February 1, 2015 at 8:42:19 PM UTC-6, Yves Cloutier wrote:
> > On Saturday, January 31, 2015 at 3:18:40 AM UTC-5, luser- -droog wrote:
> > > On Friday, January 30, 2015 at 2:45:42 PM UTC-6, Rod Dorman wrote:
> > > > In article <7988e366-4e43-44e4...@googlegroups.com>,
> > > > luser- -droog <mij...@yahoo.com> wrote:
> > > > >On Friday, January 30, 2015 at 12:38:36 AM UTC-6, luser- -droog wrote:
> > > > >> On Wednesday, January 28, 2015 at 11:40:34 PM UTC-6, luser- -droog wrote:
> > > > >> > https://github.com/luser-dr00g/ibis.ps/blob/master/ibis.ps
> > > > >> > https://github.com/luser-dr00g/debug.ps/blob/master/db5.ps
> > > > >> [snip]>
>
> But in some ways, my track record on the project is
> not good. It took me 4 years to get bold and italic
> working. :)
>
> This answer of mine has links to lots of related work:
> http://tex.stackexchange.com/questions/64296/can-the-postscript-language-be-used-to-fully-replace-tex/170051#170051
>
> For something "ready to use", I'd recommend looking
> at anastigmatix's pages, and the "tinydict",
>
> While I hope ultimately to surpass both of them,
> it's still early days.

Added paragraph-filling, which breaks most of the layout I had attempted
in the example. I've also been reading more deeply in the scribe paper.
Wondering how closely I need to follow his distinction between "inheriting"
and "non-inheriting" environment parameters.

$ cat ibis.ps
%!
%(debug.ps/db5.ps)run %currentfile cvx debug

%optionally dump text to stdout while writing
%/show { dup print (\n) print show } bind def

% essentially the same as level-2 >> operator
% but it is used in an attempt at level-1 compatibility
% but primarily for historical reasons:
% in 2011, xpost did not have >>
%
% mark k1 v1 .. kN vN dicttomark dict(N)
/dicttomark { counttomark dup dict begin 2 idiv { def } repeat pop currentdict end } def


% Composite Index inc/dec -
% (n.b. userdict is a composite object)
/inc { 2 copy get 1 add put } def
/dec { 2 copy get 1 sub put } def

/-= { 1 index load exch sub store } def

% Stack type is an array where element 0 contains the index of the top of the stack
%
% n stack array{n+1}:[0]=0
/stack { 1 add array dup 0 0 put } def
/top { dup 0 get get } def % S top a
/spop { dup top exch 0 dec } def % S spop a (S{n}->S'(n-1})
/spush { % S a spush - (S{n}->S'{n+1})
dup type /stringtype eq { dup length string copy } if
1 index 0 inc
1 index 0 get exch put
} def
/sdrop { % S i sdrop - (S{i}->removed)
%(sdrop:)=
1 index 0 get % S i c
1 index sub %1 sub % S i c-i-1
%pstack()=
dup 0 gt {
{ % S i
2 copy 2 copy % S i S i S i
1 add get put % S' i
1 add % S i=i+1
} repeat % S' i
}{
pop
} ifelse
pop
0 dec % S'
} def
% a b c d e f 2 sdrop
% a c d e f 6-2=4 -1=3
% a c d e f
%/t { 6 a b c d e f } cvlit def t 2 sdrop t ==

% output device
/dev mark
/size [ clippath pathbbox ]
/bounds null
dicttomark def
/savebounds { dev /bounds [ x y X Y ] put } def
/restorebounds { dev /bounds get aload pop setbounds } def
/setbounds { % x y X Y setbounds -
/Y exch def /X exch def /y exch def /x exch def
} def
/setmargin { % pts setmargin -
dev /size get aload pop
4 index sub 4 1 roll 4 index sub 4 1 roll
4 index add 4 1 roll 4 index add 4 1 roll
setbounds pop savebounds
} def

/nextpage { showpage restorebounds eol } def

/currentline 50 stack def

% text setting
/text mark
/eol { /Y lead -=
y Y lt { x Y moveto }
{ nextpage } ifelse }
/heol { }
/blank { setline eol }
/fontchange true

/setline {
x Y
(setline:)= pstack()=
moveto
currentline first 0 get 0 exch getinterval
{
%pstack()=
aload pop setfont show
} forall
currentline 0 0 put
eol
}
/setword {
dup length 1 add string dup 3 1 roll copy pop
dup dup length 1 sub ( ) putinterval
currentpoint pop =
(setword:)= pstack()=
dup stringwidth pop dup currentpoint pop add X gt {
setline
} if
0 rmoveto
currentfont 2 array astore currentline exch spush
%currentline ==
%flush(%lineedit)(r)file pop
}
/settext {
fontchange {
fontfam tty 4 mul bold 2 mul add italic add get setfont
/fontchange false store
} if
%show
( ) { search exch setword not { exit } if } loop
}

/fontsize 10
/lead 12
/setfontfam {
text /fontfam [ % -roman- -italic- -bold- -bold-italic-
/Palatino-Roman findfont fontsize scalefont
/Palatino-Italic findfont fontsize scalefont
/Palatino-Bold findfont fontsize scalefont
/Palatino-BoldItalic findfont fontsize scalefont
/Courier findfont fontsize scalefont
/Courier-Oblique findfont fontsize scalefont
/Courier-Bold findfont fontsize scalefont
/Courier-BoldOblique findfont fontsize scalefont
] put
}
/italic 0
/bold 0
/tty 0

dicttomark def

% processing
% find takes 3 procedures, a string and search-string
exch /process cvx exch /exec cvx 3 array astore cvx exch
first rhs % on_a (a]b) (])
3 copy exch pop % on_a (a]b) (]) on_a (])
deferal % on_a (a]b) (]) not %not-clause
{} % on_a (a]b) (]) not on_b %on_b clause: leave string on stack
5 2 roll % not on_b on_a (a]b) (])
%(delim)= pstack()=
find
} def

% ([arg]rem) /name short (rem)
/short {
%(short)= pstack()=
alt exch get % s d
dup /ini get exec % s d ?
exch /fin get % s ? {}
[ 3 1 roll /exec cvx ] cvx exch % undo s
delim
} def

/pending 10 stack def
% (name) checkpending -
/checkpending {
%(checking pending stack)= pending ==
{
pending 0 get -1 1 { % (name) i
%pstack()=
pending 1 index get % (name) i []
0 get 2 index
%pstack()=
eq { % (name) i
%pstack()=
stop
} if
pop
} for
} stopped { % (name) i
pending 1 index get 1 get % (name) i fin-arg
3 2 roll alt exch get /fin get exec % i
pending exch sdrop
}{ Err:symbol-not-in-pending-stack } ifelse
} def

% ([name]rem) long (rem)
/long {
first rhs % (name]rem) (])
{Err:long-form-arg-cannot-span-lines}
{}
{
%pstack()=
dup length string copy
dup alt exch get /ini get exec
2 array astore pending exch
%pstack()=
spush
%pending ==
}
5 3 roll % {} {} {} (name]rem) (])
find
} def

% ([name]rem) long-end (rem)
/long-end {
first rhs % (name]rem) (])
{Err:long-form-arg-cannot-span-lines}
{}
{checkpending} %search pending stack and remove match
5 3 roll % {} {} {} (name]rem) (])
find
} def

% str execute -
/execute { token { exec process }{ BAD_COMMAND } ifelse } def

% the "at" sign indicates the start of an embedded command
/sigil <40> def

/command {
{settext} {execute} {process} 4 3 roll
sigil find
} def

% scan string for embedded @commands
% and call settext for other text.
/process { % str process -
%(process:)= pstack()=
dup length 0 eq {
pop
%blank
}{
nest 0 get 0 gt {
{command} {process} nest top aload pop % str {!} {B} {A} (X)
exch [ exch % str {!} {B} (X) [ {A}
nest exch /spop cvx exch /pop cvx exch %/process cvx exch
/exec cvx
] cvx exch % str {!} {B} {A}' (X)
5 4 roll exch % {!} {B} {A} str (X)
find
% {process}{process} nest top aload pop % {!} {B} {A} (X)
% exch [
% %{nest spop pop process {defered "on_a"} exec}
% exch nest exch /spop cvx exch /pop cvx exch /process cvx exch /exec cvx
% ] cvx exch % {!} {B} {A}' (X)
% 5 4 roll exch % {!} {B} {A} str (X)
% find
}{
command
} ifelse
} ifelse
} def

% call process on each line
%
/src null def
/buf 200 string def
/exitflag false def
/ibis { % file|string ibis -
dup type /stringtype eq { (r) file } if
dup type /filetype ne { NOT_A_FILE } if
/src exch def

%pstack()=
{
src buf readline {
dup length 0 eq { blank } if
process
heol
}{
%process
exit
}ifelse
heol
exitflag { exit } if
} loop

setline
showpage
} def

% @@ define the at-sign as a command to print itself
sigil { sigil settext } def


%alterations
/alt 20 dict def

% name dict newalter -
%
% dict should contain 2 procs
% - ini ?
% ? fin -
% where init returns an object that should be
% passed to final
/newalter {
%install in alt dict
2 copy alt 3 1 roll put
%create short-form procedure
pop [ 1 index /short cvx ] cvx def
} def

/updatefont { /fontchange true store } def

/r mark
/ini { bold 2 mul italic add /bold 0 store /italic 0 store updatefont }
/fin { dup 2 mod /italic exch store 2 idiv /bold exch store updatefont }
dicttomark newalter

/i mark
/ini { italic /italic 1 store updatefont }
/fin { /italic exch store updatefont }
dicttomark newalter

/b mark
/ini { bold /bold 1 store updatefont }
/fin { /bold exch store updatefont }
dicttomark newalter

/t mark
/ini { tty /tty 1 store updatefont }
/fin { /tty exch store updatefont }
dicttomark newalter

/Begin {
long
} def

/End {
long-end
} def

/default {
text begin
setfontfam
72 setmargin
%/Palatino-Roman 10 selectfont
%alt /r get /ini get exec pop
%/lead 12 def
%eol
} def

/bye {/exitflag true def} def

%print manual only if /manual is defined (eg. `gs -dmanual ibis.ps`)
%/manual where { pop }{ currentfile flushfile } ifelse

%/i load == quit
%stepon
%traceon

default
%currentfile /ibis load debug
currentfile ibis
Text is passed to the output.
Only ragged-right, explicit linebreaks for now.

There are various ways of executing a command to change
a section of text. All commands are introduced by the @@ character,
known internally as the "sigil".

The simple command @@ i for italics, can use the short form
with various sets of delimiters.

@@ i[italics] produces @{/tab currentpoint pop def}@i[italics]

@@ i(italics) @{tab currentpoint exch pop moveto}@i(italics)

@@ i<italics> @{tab currentpoint exch pop moveto}@i<italics>

@@ i{italics} @{tab currentpoint exch pop moveto}@i{italics}

@@ i `italics' @{tab currentpoint exch pop moveto}@i `italics'

@@ i :italics; @{tab currentpoint exch pop moveto}@i :italics;

These last two require an extra space after the command name since
the backquote and colon are not postscript delimiters.

Incidentally, since the command name is scanned with 'token' and
executed with 'exec', it can even be a postscript procedure.
@{/oldfont currentfont def}

@@ {/Courier 11 selectfont}text in Courier

@{/Courier 11 selectfont}text in Courier

@{oldfont setfont}
Only "short-form" commands take a delimited argument.
The @@ {arbitrary ps code} commands are not "short-form",
and do not take an argument but apply directly to the current state.
But they do receive the remaining portion of the line as a string,
so a custom command may consume data from the string and yield the
remainder to be printed (it should leave a string on the stack).

Now with @b[bold].

I finally remembered what "deferal" was all about. So let's
see if it works. It should allow bracketed commands to span
multiple lines. Like so @i[ This sentence should be all italics
despite spanning lines, in a line-oriented scanning routine. ]
And back to normal.

Long-form uses the same command names, but it is now the @i{argument}
to the @@ Begin{} or @@ End{} command.

@@ Begin{i}@Begin{i}Start italics.
@@ End{i}@End{i}End italics.

@t[ typewriter-text @i<oblique> ]

Haha! I just read in the scribe paper that @@ Begin() and @@ End()
sections should always be properly nested.
So I just wasted some effort getting this to work:

@@ Begin{i} italic @@ Begin{b} bold-italic @@ End{i} bold @@ End{b} normal
@Begin{i} italic @Begin{b} bold-italic @End{i} bold @End{b} normal

But it's probably best to nest things properly anyway.
This should be considered "backup" behavior.

@bye
%(stack:)= pstack(---)= currentfile flushfile



jdaw1

unread,
Feb 4, 2015, 4:48:55 AM2/4/15
to
FYI, I have a mark-up that could be a middle step for you. The one program I maintain, linked from http://www.jdawiseman.com/placemat.html , uses an idea called a compound string. A 'compound string' is any of:
* (A string)
* /GlyphName
* {code}
* [An array of compound strings]

The code is the interesting bit. It can change the font, move the current point, paint something, leave some compound strings on the stack, etc. E.g.,
{0 CurrentFontSize 0.375 mul rmoveto CurrentFontName CurrentFontSize 1.7 div selectfont}

You are welcome to pillage my code for useful bits.

luser- -droog

unread,
Feb 7, 2015, 5:11:19 AM2/7/15
to
I feel like we've had this conversation before. But I am definitely
looking at your code again for things to steal. Tx :)

IIRC it was centering text, the similar event I seem to remember.
A function to center the baseline at a specified point?
I'm definitely going to need to do that again. But now my lines
are arrays of [ (string) <<font>> ] pairs.

jdaw1

unread,
Feb 7, 2015, 5:39:24 AM2/7/15
to
Your markup allows font changes. But how would it allow a change of font size?

luser- -droog

unread,
Feb 7, 2015, 6:15:58 PM2/7/15
to
On Saturday, February 7, 2015 at 4:39:24 AM UTC-6, jdaw1 wrote:
> Your markup allows font changes. But how would it allow a change of font size?

Good question. There are some things I still need to figure out.
I think the line buffer data structure (`[ [(text)<<font>>] * ]`)
can work with changing sizes. But I need to add the /Leading in there
too, I think. The vertical space needed for a line should be the
max of the Leading of any text segment in the line.

BTW, my favorite book for this stuff is called "Production for the
Graphic Designer". It always describes font sizes as two numbers,
points/lead, like 9/11, 10/12.

In a later pass, I'll worry about collisions between ascenders and
descenders.

I don't know how best to specify the font size from the input language.
My first thought is two commands

@setfontsize{num} where num is the absolute size
@changefontsize{rel} where rel is a difference
relative to the current size

But then we'd need third command to specify the change
as a percentage. Maybe just @setfontsize and @currentfontsize
and need to do a little postscript arithmetic for a relative
change. Then any form of relative change can be realized.

Those names are kind of long, though. But, maybe that's good.
It will encourage using styles instead of arbitrary fontchanges
in running text.

So, that's what I'm thinking.

tlvp

unread,
Feb 8, 2015, 12:21:25 AM2/8/15
to
On Sat, 7 Feb 2015 15:15:57 -0800 (PST), luser- -droog wrote:

> @setfontsize{num} where num is the absolute size
> @changefontsize{rel} where rel is a difference
> relative to the current size
>
> But then we'd need third command to specify the change
> as a percentage.

Just as you have absolute and relative LineTo commands (lineto and rlineto)
so you might have absolute (differential) and proportional ChangeFontSize
commands (perhaps @changefontsize{diff} and @rchangefontsize{percent}?).

Cheers, -- tlvp
--
Avant de repondre, jeter la poubelle, SVP.

luser- -droog

unread,
Feb 8, 2015, 5:45:22 AM2/8/15
to
On Saturday, February 7, 2015 at 11:21:25 PM UTC-6, tlvp wrote:
> On Sat, 7 Feb 2015 15:15:57 -0800 (PST), luser- -droog wrote:
>
> > @setfontsize{num} where num is the absolute size
> > @changefontsize{rel} where rel is a difference
> > relative to the current size
> >
> > But then we'd need third command to specify the change
> > as a percentage.
>
> Just as you have absolute and relative LineTo commands (lineto and rlineto)
> so you might have absolute (differential) and proportional ChangeFontSize
> commands (perhaps @changefontsize{diff} and @rchangefontsize{percent}?).
>

Useful thoughts. Thanks. I've been focusing on the
other part of just making something that works.
So the current example looks like this:

An interest has developed in changing the font size. Currently,
this can be hacked with explicit postscript.
@{/fontsize 5 += /lead 3 += setfontfam /fontchange true store} Big text.
@{/fontsize 5 -= /lead 3 -= setfontfam /fontchange true store} back to normal.

But maybe it's inefficient to call setfontfam, which
calls findfont and scalefont for all 8 fonts.

The size of any given font is just its matrix, right?
So I could, I don't know, use that somehow. Store the
matrix separately? Does that help?

I can't use stringwidth easily without a scaled font
installed.

tlvp

unread,
Feb 9, 2015, 10:47:17 PM2/9/15
to
On Sun, 8 Feb 2015 02:45:21 -0800 (PST), luser- -droog wrote:

> Useful thoughts. Thanks.

YW. It's always handy to coin imperatives that are well motivated, hence
easy to remember :-) . Cheers, -- tlvp

luser- -droog

unread,
Feb 18, 2015, 3:02:33 AM2/18/15
to
I broke 1000 lines, and burned through my first wind, I think.
So, I thought I share since I can't think of anything more to
do to it at the moment.

I think I've committed a synecdoche and used the word "style"
at the wrong granularity. I'm not sure if it should refer to
a specific command, like `header` or a collection of these
commands, like `letter` | `manual` | `screenplay` | etc.

But the part I'm really proud of, I probably need to comment
better. I think all this abstract algebra is rubbing off an
I've made something like a "group" for style-changes.

So, I've got a basic object called an "alt dict" (and a dict
named "alt" to hold them, for an extra level of obscurity).
An alt dict contains two functions named /ini and /fin where
ini returns an object which is passed to fin. Typically, ini
will change some definition, but return the previous value,
so fin can "undo" the change by restoring the old value.

A "style" then, as I've implemented it, can compose any
number of alt dicts together to produce a new alt dict
which implements the composite behavior. The @code style
is very small and explicable.

/code { b t } addstyle

where b and t are 'bold' and 'typewriter' font changes.

The alt dict for code contains the ini and fin procedures
from the b and t dicts composed together into new procedures.

/code <<
/ini { [ {b-ini} exec {t-ini} exec ] }
/fin { aload pop {t-fin} exec {b-fin} exec }
>>

where {b-ini} designates the /ini from b, etc.

For the font size command, I've kept it real simple for now.

@font+{big @font+[bigger]} @font-(smaller @font-<very small>)

would be the explicit, short-form syntax. As hinted, it can
also be used in the long form.

@Begin{font+}Big text@End{font+}

or composed in a style, as in the 'heading' style:

/heading { eolbefore b i font+ eolafter } addstyle

I've tried to add comments liberally throughout, but I'm probably
not the best judge of which parts are confusing.

So, questions/comments/ideas for what to add next?

Hmm. It's too big for my xterm scrollback buffer, so it's
probably getting a little too long to post here. So I'll just
do the link.
https://github.com/luser-dr00g/ibis.ps
0 new messages