Skip to content

Commit

Permalink
Extend StreamFormatting to seperate linewrap and indenting
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisJefferson committed Jan 11, 2024
1 parent a698f21 commit 3db2723
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 73 deletions.
7 changes: 2 additions & 5 deletions lib/custom_streams.gi
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,8 @@ InstallMethod( PrintFormattingStatus, "output text custom",
##
InstallMethod( SetPrintFormattingStatus, "output text custom",
[IsOutputTextCustomRep and IsOutputTextStream,
IsBool],
IsObject],
function( str, stat)
if stat = fail then
Error("Print formatting status must be true or false");
else
CheckValidPrintFormattingStatus(stat);

Check warning on line 348 in lib/custom_streams.gi

View check run for this annotation

Codecov / codecov/patch

lib/custom_streams.gi#L348

Added line #L348 was not covered by tests
str!.formatting := stat;
fi;
end);
37 changes: 23 additions & 14 deletions lib/streams.gd
Original file line number Diff line number Diff line change
Expand Up @@ -959,24 +959,31 @@ DeclareGlobalFunction( "InputOutputLocalProcess" );
## and harmless if it to passed as input to ⪆,
## but may be unhelpful if the output is to be passed as input to another
## program.
## It is possible to turn off this behaviour for a stream using the
## <Ref Oper="SetPrintFormattingStatus"/> operation, and to test whether it
## is on or off using <Ref Oper="PrintFormattingStatus"/>.
## It is possible to control this behaviour for a stream using the
## <Ref Oper="SetPrintFormattingStatus"/> operation, and to query it
## using <Ref Oper="PrintFormattingStatus"/>.
## <P/>
## The formatting status is stored in a record with two members,
## <A>linewrap</A> and <A>indent</A>, which control if GAP wraps lines,
## or indents, respectively. These two both take a boolean.
## <P/>
## For backwards compatability, all functions which control print formatting
## will also take a boolean, which sets <A>linewrap</A> and <A>indent</A> to
## the given boolean value.
## <P/>
## <Ref Oper="SetPrintFormattingStatus"/> sets whether output sent to the
## output stream <A>stream</A> via <Ref Func="PrintTo"/>,
## <Ref Func="AppendTo"/>, etc.
## will be formatted with line breaks and
## indentation. If the second argument <A>newstatus</A> is <K>true</K>
## then output will be so formatted, and if <K>false</K> then it will not.
## If the stream is not a text stream, only <K>false</K> is allowed.
## indentation. The second argument <A>newstatus</A> is a record or boolean,
## as described above.
## If the stream is not a text stream, both <A>linewrap</A> and <A>indent</A>
## can only be set to <K>false</K>.
## <P/>
## <Ref Oper="PrintFormattingStatus"/> returns <K>true</K> if output sent to
## the output text stream <A>stream</A> via <Ref Func="PrintTo"/>,
## <Ref Func="AppendTo"/>, etc.
## will be formatted with line breaks and
## indentation, and <K>false</K> otherwise.
## For non-text streams, it returns <K>false</K>.
## <Ref Oper="PrintFormattingStatus"/> returns a record containing the
## current value of <A>linewrap</A> and <A>indent</A> for the output text
## stream <A>stream</A>. For non-text streams, these values area always
## both <K>false</K>.
## If as argument <A>stream</A> the string <C>"*stdout*"</C> is given, these
## functions refer to the formatting status of the standard output (so usually
## the user's terminal screen).<P/>
Expand All @@ -997,7 +1004,7 @@ DeclareGlobalFunction( "InputOutputLocalProcess" );
## gap> Print(s,"\n");
## [ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
## 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113 ]
## gap> SetPrintFormattingStatus(str, false);
## gap> SetPrintFormattingStatus(str, rec(indent:=false,linewrap:=false));
## gap> PrintTo(str,Primes{[1..30]});
## gap> s;
## "[ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,\
Expand All @@ -1015,7 +1022,7 @@ DeclareGlobalFunction( "InputOutputLocalProcess" );
## </ManSection>
## <#/GAPDoc>
##
DeclareOperation( "SetPrintFormattingStatus", [IsOutputStream, IsBool] );
DeclareOperation( "SetPrintFormattingStatus", [IsOutputStream, IsObject] );
DeclareOperation( "PrintFormattingStatus", [IsOutputStream] );


Expand Down Expand Up @@ -1259,3 +1266,5 @@ DeclareGlobalFunction( "InputFromUser" );
## <#/GAPDoc>
##
DeclareGlobalFunction( "OpenExternal" );

DeclareGlobalFunction( "CheckValidPrintFormattingStatus");
49 changes: 31 additions & 18 deletions lib/streams.gi
Original file line number Diff line number Diff line change
Expand Up @@ -929,13 +929,10 @@ InstallMethod( PrintFormattingStatus, "output text string",
##
InstallMethod( SetPrintFormattingStatus, "output text string",
[IsOutputTextStringRep and IsOutputTextStream,
IsBool],
IsObject],
function( str, stat)
if stat = fail then
Error("Print formatting status must be true or false");
else
CheckValidPrintFormattingStatus(stat);
str![2] := stat;
fi;
end);


Expand Down Expand Up @@ -1130,13 +1127,10 @@ InstallMethod( PrintFormattingStatus, "output text file",
##
InstallMethod( SetPrintFormattingStatus, "output text file",
[IsOutputTextFileRep and IsOutputTextStream,
IsBool],
IsObject],
function( str, stat)
if stat = fail then
Error("Print formatting status must be true or false");
else
CheckValidPrintFormattingStatus(stat);
str![3] := stat;
fi;
end);

## formatting status for stdout or current output
Expand All @@ -1151,7 +1145,7 @@ function(str)
fi;
end);

InstallOtherMethod( SetPrintFormattingStatus, "for stdout", [IsString, IsBool],
InstallOtherMethod( SetPrintFormattingStatus, "for stdout", [IsString, IsObject],
function(str, status)
if str = "*stdout*" then
SET_PRINT_FORMATTING_STDOUT(status);
Expand Down Expand Up @@ -1255,9 +1249,7 @@ InstallMethod( SetPrintFormattingStatus, "output text none",
[IsOutputTextNoneRep and IsOutputTextNone,
IsBool],
function( str, stat)
if stat = fail then
Error("Print formatting status must be true or false");
fi;
CheckValidPrintFormattingStatus(stat);
end);


Expand Down Expand Up @@ -1676,14 +1668,35 @@ InstallMethod( SetPrintFormattingStatus, "for non-text output stream",
TryNextMethod();
fi;

if stat = true then
Error("non-text streams support onlyPrint formatting status false");
elif stat = fail then
Error("Print formatting status must be true or false");
CheckValidPrintFormattingStatus(stat);
if stat = true or
( IsRecord(stat) and (stat.linewrap or stat.indent) ) then
Error("non-text streams do not support print formatting");

Check warning on line 1674 in lib/streams.gi

View check run for this annotation

Codecov / codecov/patch

lib/streams.gi#L1674

Added line #L1674 was not covered by tests
fi;
end);


InstallGlobalFunction( "CheckValidPrintFormattingStatus",
function(fs)
local r;
if IsBool(fs) then
if fs = fail then
Error("Formatting status cannot be 'fail'");
fi;
elif IsRecord(fs) then
if Set(RecNames(fs)) <> ["indent", "linewrap"] then
Error("Formatting status records must contain exactly two components, named 'indent' and 'linewrap'");
fi;
for r in ["indent","linewrap"] do
if not fs.(r) in [false, true] then
Error(Concatenation(r, " must be 'true' or 'false' in formatting status record"));
fi;
od;
else
Error("Formatting status must be a boolean or a record");
fi;
end);

#############################################################################
##
#M FileDescriptorOfStream( <iostream-by-pty> )
Expand Down
88 changes: 63 additions & 25 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@
#include "lists.h"
#include "modules.h"
#include "plist.h"
#include "precord.h"
#include "read.h"
#include "records.h"
#include "scanner.h"
#include "stringobj.h"
#include "symbols.h"
Expand Down Expand Up @@ -115,8 +117,8 @@ struct IOModuleState {

Int NoSplitLine;

BOOL PrintFormattingForStdout;
BOOL PrintFormattingForErrout;
StreamFormat PrintFormattingForStdout;
StreamFormat PrintFormattingForErrout;
};

// for debugging from GDB / lldb, we mark this as extern inline
Expand Down Expand Up @@ -851,7 +853,7 @@ UInt OpenOutput(TypOutputFile * output, const Char * filename, BOOL append)
else if (streq(filename, "*errout*"))
output->format = IO()->PrintFormattingForErrout;
else
output->format = TRUE;
output->format = MakeStreamFormat(TRUE, TRUE);
output->indent = 0;

// variables related to line splitting, very bad place to split
Expand Down Expand Up @@ -886,7 +888,8 @@ UInt OpenOutputStream(TypOutputFile * output, Obj stream)
output->file = -1;
output->line[0] = '\0';
output->pos = 0;
output->format = (CALL_1ARGS(PrintFormattingStatus, stream) == True);
output->format =
StreamFormatFromObj(CALL_1ARGS(PrintFormattingStatus, stream));
output->indent = 0;

// variables related to line splitting, very bad place to split
Expand Down Expand Up @@ -1236,7 +1239,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch)
// '\01', increment indentation level
if ( ch == '\01' ) {

if (!stream->format)
if (NoStreamFormat(stream->format))
return;

// add hint to break line
Expand All @@ -1246,7 +1249,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch)
// '\02', decrement indentation level
else if ( ch == '\02' ) {

if (!stream->format)
if (NoStreamFormat(stream->format))
return;

// if this is a better place to split the line remember it
Expand Down Expand Up @@ -1282,8 +1285,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch)

// and dump it from the buffer
stream->pos = 0;
if (stream->format)
{
if (stream->format.indent) {
// indent for next line
for ( i = 0; i < stream->indent; i++ )
stream->line[ stream->pos++ ] = ' ';
Expand Down Expand Up @@ -1318,12 +1320,12 @@ static void PutChrTo(TypOutputFile * stream, Char ch)

/* if we are going to split at the end of the line, and we are
formatting discard blanks */
if ( stream->format && spos == stream->pos && ch == ' ' ) {
if (stream->format.linewrap && spos == stream->pos && ch == ' ') {
;
}

// full line, acceptable split position
else if ( stream->format && spos != 0 ) {
else if (stream->format.linewrap && spos != 0) {

// add character to the line, terminate it
stream->line[ stream->pos++ ] = ch;
Expand All @@ -1340,18 +1342,19 @@ static void PutChrTo(TypOutputFile * stream, Char ch)
PutLineTo( stream, spos );
spos--;

// indent for the rest
stream->pos = 0;
if (stream->format.indent) {
// indent for the rest
for ( i = 0; i < stream->hints[3*hint+2]; i++ )
stream->line[ stream->pos++ ] = ' ';
spos -= stream->hints[3*hint+2];
}

// copy the rest onto the next line
for ( i = 0; str[ i ] != '\0'; i++ )
stream->line[ stream->pos++ ] = str[ i ];
// recover line break hints for copied rest
for ( i = hint+1; stream->hints[3*i] != -1; i++ )
{
for (i = hint + 1; stream->hints[3 * i] != -1; i++) {
stream->hints[3*(i-hint-1)] = stream->hints[3*i]-spos;
stream->hints[3*(i-hint-1)+1] = stream->hints[3*i+1];
stream->hints[3*(i-hint-1)+2] = stream->hints[3*i+2];
Expand All @@ -1362,9 +1365,8 @@ static void PutChrTo(TypOutputFile * stream, Char ch)
// full line, no split position
else {

if (stream->format)
{
/* append a '\',*/
if (stream->format.linewrap) {
// append a '\'
stream->line[ stream->pos++ ] = '\\';
stream->line[ stream->pos++ ] = '\n';
}
Expand All @@ -1376,7 +1378,7 @@ static void PutChrTo(TypOutputFile * stream, Char ch)
stream->pos = 0;
stream->line[ stream->pos++ ] = ch;

if (stream->format)
if (stream->format.indent)
stream->hints[0] = -1;
}

Expand Down Expand Up @@ -1816,6 +1818,42 @@ void SPrTo(Char *buffer, UInt maxlen, const Char *format, Int arg1, Int arg2)
}


// Convert GAP-level print formatting objects to kernel level, and vice-versa

StreamFormat StreamFormatFromObj(Obj o)
{
if (o == True) {
return MakeStreamFormat(TRUE, TRUE);
}
if (o == False) {
return MakeStreamFormat(FALSE, FALSE);
}

RequirePlainRec("Stream formatting", o);

Obj indent = ElmPRec(o, RNamName("indent"));
Obj linewrap = ElmPRec(o, RNamName("linewrap"));

RequireTrueOrFalse("indent in stream formatting", indent);
RequireTrueOrFalse("linewrap in stream formatting", linewrap);

BOOL i = (indent == True);
BOOL l = (linewrap == True);

return MakeStreamFormat(l, i);
}

Obj ObjFromStreamFormat(StreamFormat sf)
{
Obj o = NEW_PREC(2);
Obj indent = sf.indent ? True : False;
Obj linewrap = sf.linewrap ? True : False;
AssPRec(o, RNamName("indent"), indent);
AssPRec(o, RNamName("linewrap"), linewrap);
return o;
}


static Obj FuncINPUT_FILENAME(Obj self)
{
if (IO()->Input == 0)
Expand All @@ -1832,7 +1870,7 @@ static Obj FuncINPUT_LINENUMBER(Obj self)

static Obj FuncSET_PRINT_FORMATTING_STDOUT(Obj self, Obj val)
{
BOOL format = (val != False);
StreamFormat format = StreamFormatFromObj(val);
TypOutputFile * output = IO()->Output;
while (output) {
if (!output->stream && output->file == 1)
Expand All @@ -1845,12 +1883,12 @@ static Obj FuncSET_PRINT_FORMATTING_STDOUT(Obj self, Obj val)

static Obj FuncPRINT_FORMATTING_STDOUT(Obj self)
{
return IO()->PrintFormattingForStdout ? True : False;
return ObjFromStreamFormat(IO()->PrintFormattingForStdout);
}

static Obj FuncSET_PRINT_FORMATTING_ERROUT(Obj self, Obj val)
{
BOOL format = (val != False);
StreamFormat format = StreamFormatFromObj(val);
TypOutputFile * output = IO()->Output;
while (output) {
if (!output->stream && output->file == 3)
Expand All @@ -1863,7 +1901,7 @@ static Obj FuncSET_PRINT_FORMATTING_ERROUT(Obj self, Obj val)

static Obj FuncPRINT_FORMATTING_ERROUT(Obj self)
{
return IO()->PrintFormattingForErrout ? True : False;
return ObjFromStreamFormat(IO()->PrintFormattingForErrout);
}

/****************************************************************************
Expand All @@ -1882,8 +1920,8 @@ static Obj FuncCALL_WITH_FORMATTING_STATUS(Obj self, Obj status, Obj func, Obj a
if (!output)
ErrorMayQuit("CALL_WITH_FORMATTING_STATUS called while no output is open", 0, 0);

BOOL old = output->format;
output->format = (status != False);
StreamFormat old = output->format;
output->format = StreamFormatFromObj(status);

Obj result;
GAP_TRY
Expand Down Expand Up @@ -1964,8 +2002,8 @@ static Int InitKernel (
IO()->Output = 0;
IO()->InputLog = 0;
IO()->OutputLog = 0;
IO()->PrintFormattingForStdout = TRUE;
IO()->PrintFormattingForErrout = TRUE;
IO()->PrintFormattingForStdout = MakeStreamFormat(TRUE, TRUE);
IO()->PrintFormattingForErrout = MakeStreamFormat(TRUE, TRUE);

OpenOutput(&IO()->DefaultOutput, "*stdout*", FALSE);

Expand Down
Loading

0 comments on commit 3db2723

Please sign in to comment.