From eb23b02147644fd72152f915c61b2027c5f75af1 Mon Sep 17 00:00:00 2001 From: cbmarini Date: Wed, 17 Jun 2026 10:09:44 +0200 Subject: [PATCH] fix: fixes PushHide/PopHide mixing with Hide/UnHide. This resolves #828 --- check/examples.frm | 34 ++++++++++++++++ check/fixes.frm | 61 +++++++++++++++++++++++++++++ doc/manual/statements.tex | 82 +++++++++++++++++++++++++++++++++++---- sources/compcomm.c | 16 ++++++-- 4 files changed, 181 insertions(+), 12 deletions(-) diff --git a/check/examples.frm b/check/examples.frm index b2d7ae370..29432855f 100644 --- a/check/examples.frm +++ b/check/examples.frm @@ -1084,6 +1084,40 @@ PopHide; .end assert compile_error?("PopHide statement without corresponding PushHide statement") *--#] Sta_PushPopHide_2 : +*--#[ Sta_PushPopHide_3 : +Local F1 = 1; +.sort +PushHide; +Local F2 = 2; +.sort +Hide; +Local F3 = 3; +.sort +PushHide; +Local F4 = 4; +.sort +Hide; +.sort +PopHide; +* F3 and F4 are active; F1 and F2 remain hidden. +Print; +.sort +UnHide; +* F2, F3 and F4 are active; F1 remains hidden. +Print; +.sort +PopHide; +* All four expressions are active. +Print; +.end +assert succeeded? +assert_equal ["F3", "F4", "F2", "F3", "F4", "F1", "F2", "F3", "F4"], + stdout.scan(/^[ \t]+(F[1-4])\s*=/).flatten +assert result("F1") =~ expr("1") +assert result("F2") =~ expr("2") +assert result("F3") =~ expr("3") +assert result("F4") =~ expr("4") +*--#] Sta_PushPopHide_3 : *--#[ Sta_Print_1 : Symbols a,b,c; Local F = 3*a+2*b; diff --git a/check/fixes.frm b/check/fixes.frm index 94c7198cf..72ef32261 100644 --- a/check/fixes.frm +++ b/check/fixes.frm @@ -4979,6 +4979,67 @@ Global F1 = E{`i' % 10}*E2*E3*E4; .end assert succeeded? *--#] Issue808 : +*--#[ Issue828_1 : +Local F = 1; +Global G = 2; +.sort +PushHide; +* Repeated Hide statements must preserve the pending PushHide level. +Hide; +Hide F,G; +.sort +UnHide; +Multiply 2; +.sort +PopHide; +Print; +.end +assert succeeded? +assert result("F") =~ expr("1") +assert result("G") =~ expr("2") +*--#] Issue828_1 : +*--#[ Issue828_2 : +Local F = 1; +Global G = 2; +.sort +PushHide; +.sort +PopHide; +NUnHide; +.sort +* The saved hide levels are now higher than the current hide level. +UnHide; +Print; +.end +assert succeeded? +assert result("F") =~ expr("1") +assert result("G") =~ expr("2") +*--#] Issue828_2 : +*--#[ Issue828_3 : +Local F1 = 1; +.sort +PushHide; +Local F2 = 2; +.sort +Hide; +.sort +* Explicit names allow UnHide to reach an enclosing hide level. +UnHide F1; +Print; +.end +assert succeeded? +assert_equal ["F1"], stdout.scan(/^[ \t]+(F[12])\s*=/).flatten +assert result("F1") =~ expr("1") +*--#] Issue828_3 : +*--#[ Issue828_4 : +Local F = 1; +.sort + +Hide G; +.end +assert compile_error?("G is not an expression") +assert return_value != 0 +*--#] Issue828_4 : *--#[ Issue833_1 : #- #: TermsInSmall 1024 diff --git a/doc/manual/statements.tex b/doc/manual/statements.tex index b68206314..312d765a3 100644 --- a/doc/manual/statements.tex +++ b/doc/manual/statements.tex @@ -2507,6 +2507,11 @@ \section{hide} expressions for being put in hidden\index{hide} storage. In the second variety it marks only the specified active\index{active expressions} expressions as such. \vspace{4mm} +\noindent Hide has no further effect on expressions that are already +hidden or marked for hiding. Examples of combining hide with pushhide, +pophide and unhide are given in \ref{substapushhide}. +\vspace{4mm} + \noindent If an expression is marked for being hidden, it will be copied to the `hide\index{hide file} file'\index{file!hide}, a storage which is either in memory or on file depending on the combined size of all @@ -4655,7 +4660,7 @@ \section{pophide} \end{tabular} \vspace{4mm} \noindent Undoes\index{pophide} the action of the most recent -pushhide\index{pushhide} statement (see \ref{substapushhide}). If there is +pushhide\index{pushhide} statement (see \ref{substapushhide}). If there is no matching pushhide statement an error will result: % THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS % WELL! (Sta_PushPopHide_2) @@ -4672,6 +4677,10 @@ \section{pophide} pushpophide-2.frm Line 9 --> PopHide statement without corresponding PushHide s tatement \end{verbatim} +\vspace{4mm} +\noindent It also brings back expressions hidden with \texttt{hide} since +that pushhide. Expressions that were already hidden before that pushhide +stay hidden. See also \ref{substapushhide} for an example. \vspace{10mm} %--#] pophide : @@ -4995,6 +5004,54 @@ \section{pushhide} F3 = 8; \end{verbatim} + +\noindent Hide and unhide can also be used between pushhide and pophide. +The following rules apply: suppose pushhide has hidden F1, and hide then hides F2. There +are two ways to bring expressions back: +\begin{itemize} +\item \verb|UnHide;| makes F2 active again and leaves F1 hidden. +\item \verb|PopHide;| makes both F1 and F2 active again. +\end{itemize} +Expressions that were already hidden before the pushhide stay hidden in +both cases. To bring back a particular expression, even one hidden by +pushhide, name it explicitly: \verb|UnHide F1;|. Here is a nested example. +The comments show which expressions each print statement prints: +% THIS EXAMPLE IS PART OF THE TESTSUITE. CHANGES HERE SHOULD BE APPLIED THERE AS +% WELL! (Sta_PushPopHide_3) +\begin{verbatim} + Local F1 = 1; + .sort + PushHide; + Local F2 = 2; + .sort + Hide; + Local F3 = 3; + .sort + PushHide; + Local F4 = 4; + .sort + Hide; + .sort + PopHide; + * F3 and F4 are active; F1 and F2 remain hidden. + Print; + .sort + UnHide; + * F2, F3 and F4 are active; F1 remains hidden. + Print; + .sort + PopHide; + * All four expressions are active. + Print; + .end +\end{verbatim} +\noindent For package management, the user can set expressions aside with +pushhide while a package does its work, then bring them back with pophide. +An argument-free \verb|UnHide;| inside the package does not undo the user's +pushhide or unhide expressions that were already hidden before it. +Existing packages can therefore continue using hide and unhide for their +own expressions without changing those statements. For new packages, it is +recommended to use the pushhide/pophide mechanism though. \vspace{10mm} %--#] pushhide : @@ -7194,13 +7251,22 @@ \section{unhide} pophide (\ref{substapophide}) \end{tabular} \vspace{4mm} -\noindent In its\index{unhide} first variety this statement causes all -expressions in the hide\index{hide} file\index{file!hide} to become -active\index{active} expressions again. In its second variety only the -specified expressions are taken from the hide system and become active -again. An expression that is made active again can be manipulated again in -the module in which the unhide statement occurs. For more information one -should look at the hide statement in \ref{substahide}. \vspace{4mm} +\noindent Without an expression list, unhide\index{unhide} normally makes +all expressions in the hide\index{hide} file\index{file!hide} +active\index{active} again. Between a pushhide and its pophide, however, +it leaves the expressions hidden by pushhide alone, as well as any +expressions that were already hidden before the pushhide. It brings back +expressions hidden with hide in the meantime. See the examples in +\ref{substapushhide}. \vspace{4mm} + +\noindent With an expression list, unhide makes the specified expressions +active again. This also works for expressions hidden by pushhide; for +example, \verb|UnHide F1;| brings back F1 even if pushhide hid it. +\vspace{4mm} + +\noindent An expression made active by unhide can be manipulated in the +same module. For more information, see hide in \ref{substahide}. +\vspace{4mm} \noindent Note that if only a number of expressions are taken from the hide system, the hide file may be left with `holes', i.e.\ space between the diff --git a/sources/compcomm.c b/sources/compcomm.c index 4c281613b..6fd73f23c 100644 --- a/sources/compcomm.c +++ b/sources/compcomm.c @@ -1522,15 +1522,21 @@ int SetExprCases(int par, int setunset, int val) int SetExpr(UBYTE *s, int setunset, int par) { - WORD *w, numexpr; + WORD *w, numexpr, status; int error = 0, i; UBYTE *name, c; if ( *s == 0 ) { for ( i = 0; i < NumExpressions; i++ ) { + /* UnHide without names must not reach enclosing hide levels. */ + if ( par == UNHIDE && setunset == 1 && Expressions[i].hidelevel < AC.HideLevel ) { + continue; + } w = &(Expressions[i].status); + status = *w; *w = SetExprCases(par,setunset,*w); if ( *w < 0 ) error = 1; - if ( ( par == HIDE || par == INTOHIDE ) && setunset == 1 ) + /* Already hidden or marked expressions must keep their hide level. */ + if ( ( par == HIDE || par == INTOHIDE ) && setunset == 1 && *w != status ) Expressions[i].hidelevel = AC.HideLevel; } return(0); @@ -1546,12 +1552,14 @@ int SetExpr(UBYTE *s, int setunset, int par) c = *s; *s = 0; if ( GetName(AC.exprnames,name,&numexpr,NOAUTO) == CEXPRESSION ) { w = &(Expressions[numexpr].status); + status = *w; *w = SetExprCases(par,setunset,*w); if ( *w < 0 ) error = 1; - if ( ( par == HIDE || par == INTOHIDE ) && setunset == 1 ) + /* Already hidden or marked expressions must keep their hide level. */ + if ( ( par == HIDE || par == INTOHIDE ) && setunset == 1 && *w != status ) Expressions[numexpr].hidelevel = AC.HideLevel; } - else if ( GetName(AC.varnames,name,&numexpr,NOAUTO) != NAMENOTFOUND ) { + else { MesPrint("&%s is not an expression",name); error = 1; }