% File: latex.sl -*- mode: SLang -*-
%
% Copyright (c)
% 2007 Jörg Sommer <
[email protected]>
% $Id: latex_pst.sl 199 2007-08-23 23:28:52Z joerg $
%
% -*- This file is part of Jörg's LaTeX Mode (JLM) -*-
%
% Description: This file contains all functions related to PSTricks.
%
% License: This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License as
% published by the Free Software Foundation; either version 2 of
% the License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be
% useful, but WITHOUT ANY WARRANTY; without even the implied
% warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
% PURPOSE. See the GNU General Public License for more details.
%%%%%%%%%%
%
% A point in PSTricks
%
typedef struct {
x, y, mark
} Pst_Point_Type;
static define pst_point_as_string(pnt)
{
return "(" + string(pnt.x) + "," + string(pnt.y) + ")";
}
__add_string(Pst_Point_Type, &pst_point_as_string());
static define pst_new_point() % (x, y[, mark])
{
variable pnt = @Pst_Point_Type;
if (_NARGS > 2)
pnt.mark = ();
pnt.y = ();
pnt.x = ();
return pnt;
}
static define pst_add_points(a, b)
{
return pst_new_point(a.x + b.x, a.y + b.y);
}
__add_binary("+", Pst_Point_Type, &pst_add_points(), Pst_Point_Type,
Pst_Point_Type);
static define pst_point_min(pnt1, pnt2)
{
return pst_new_point( min([pnt1.x, pnt2.x]), min([pnt1.y, pnt2.y]) );
}
static define pst_point_max(pnt1, pnt2)
{
return pst_new_point( max([pnt1.x, pnt2.x]), max([pnt1.y, pnt2.y]) );
}
static define pst_looking_at_point()
{
% return re_looking_at("[ \t\n]*(');
return looking_at_char('(');
}
static define pst_skip_point()
{
return andelse {fsearch_char(')')} {right(1)};
}
static define pst_update_point(pnt, new_pnt)
{
if (pnt.mark == NULL)
throw UsageError, "pnt is not a real point";
push_spot();
EXIT_BLOCK
{
pop_spot();
}
goto_user_mark(pnt.mark);
% insert before delete to make a spot after the deleted string is left
% there
insert( pst_point_as_string(new_pnt) );
push_mark();
() = pst_skip_point();
del_region();
pnt.x = new_pnt.x;
pnt.y = new_pnt.y;
}
static define pst_read_point()
{
!if ( pst_looking_at_point() )
throw UsageError, "No at a point";
variable mark = create_user_mark();
() = right(1);
push_mark();
!if ( pst_skip_point() )
{
pop_mark(0);
goto_user_mark(mark);
throw DataError, "This doesn't look like a PSTricks point ($what_line,"$ +
string(what_column()) + ")";
}
variable x, y;
if ( sscanf(str_delete_chars(bufsubstr(), "\s"R), "%g,%g", &x, &y) != 2 )
{
goto_user_mark(mark);
throw DataError, "This doesn't look like a PSTricks point ($what_line,"$ +
string(what_column()) + ")";
}
return pst_new_point(x, y, mark);
}
private define pst_extract_points_from_region()
{
check_region(1);
EXIT_BLOCK
{
pop_spot();
}
variable end_mark = create_user_mark();
pop_mark(1);
variable point_list = list_new();
while (create_user_mark() < end_mark)
{
skip_chars("^\\{"R);
if ( is_commented() )
{
eol();
continue;
}
if ( looking_at("\\{") or looking_at("\\\\") )
{
() = right(2);
continue;
}
if ( looking_at_char('{') )
{
fsearch_matching_brace();
continue;
}
() = right(1);
push_mark();
skip_chars(TeX_Command_Chars);
!if ( is_list_element("rput,psframe,psline,pscircle,psbezier,psdot,psdots,psaxes",
bufsubstr(), ',') )
continue;
(,) = cmd_parse_args(1,0);
!if ( pst_looking_at_point() )
throw DataError, "Malformed pstricks command in line $what_line"$;
do
{
list_append(point_list, pst_read_point());
}
while ( pst_looking_at_point() );
}
return point_list;
}
%%%%%%%%%%
%
% PSTricks
%
static variable PST_Origin = pst_new_point(0,0);
static define pst_enlarge_pic(point)
{
push_spot();
EXIT_BLOCK
{
pop_spot();
}
boenv();
!if ( looking_at("\\begin{pspicture}") )
throw UsageError, "This is not a pspicture environment";
() = right(17);
if ( pst_looking_at_point() )
{
variable old_point = pst_read_point(), tmp_point;
if ( pst_looking_at_point() )
{
tmp_point = pst_point_min(old_point, point);
if (tmp_point.x < old_point.x or tmp_point.y < old_point.y)
{
if (tmp_point.x == PST_Origin.x and tmp_point.y == PST_Origin.y)
{
push_spot();
goto_user_mark(old_point.mark);
push_mark();
pst_skip_point();
del_region();
pop_spot();
}
else
pst_update_point(old_point, tmp_point);
}
old_point = pst_read_point();
}
else if (point.x < PST_Origin.x or point.y < PST_Origin.y)
{
push_spot();
goto_user_mark(old_point.mark);
insert( pst_point_as_string(pst_point_min(PST_Origin, point)) );
pop_spot();
}
tmp_point = pst_point_max(old_point, point);
if (old_point.x < tmp_point.x or old_point.y < tmp_point.y)
{
if (tmp_point.x == PST_Origin.x and tmp_point.y == PST_Origin.y)
{
push_spot();
goto_user_mark(old_point.mark);
push_mark();
pst_skip_point();
del_region();
pop_spot();
}
else
pst_update_point(old_point, tmp_point);
}
}
else
{
if (point.x < PST_Origin.x or point.y < PST_Origin.y)
insert( pst_point_as_string(pst_point_min(point, PST_Origin)) +
pst_point_as_string(pst_point_max(point, PST_Origin)) );
else if (point.x > PST_Origin.x or point.y > PST_Origin.y)
insert( pst_point_as_string(point) );
}
}
static define pst_update_pic_size()
{
push_spot();
EXIT_BLOCK
{
pop_spot();
}
boenv();
!if ( looking_at("\\begin{pspicture}") )
throw UsageError, "This is not a pspicture environment";
() = right(17);
while ( pst_looking_at_point() )
() = pst_skip_point();
push_mark();
eoenv();
variable min = PST_Origin, max = PST_Origin;
foreach ( pst_extract_points_from_region() )
{
dup;
min = pst_point_min((), min);
max = pst_point_max((), max);
}
pst_enlarge_pic(min);
pst_enlarge_pic(max);
}
static define pst_move_points()
{
variable offset;
try
offset = read_mini("Offset to move points; use X for (X,X) or (X,Y)",
"", "");
catch UserBreakError:
return;
variable x, y;
if ( andelse {sscanf(offset, "%g", &x) != 1}
{sscanf(offset, "(%g,%g)", &x, &y) != 2})
throw UsageError, "Invalid input for offset";
!if ( __is_initialized(&y) )
y = x;
offset = pst_new_point(x, y);
variable max = PST_Origin, min = PST_Origin, p;
foreach p ( pst_extract_points_from_region() )
{
variable new_p = p + offset;
min = pst_point_min(min, new_p);
max = pst_point_max(max, new_p);
pst_update_point(p, new_p);
}
pst_enlarge_pic(min);
pst_enlarge_pic(max);
}