Post by Stefan on Mar 30, 2022 7:29:39 GMT -5
Hi George,
This post relates to some irregularities and "Aha!" moments I encountered whilst working on the LP (LISTPROC) macro.
I could have posted bits of this under "Suggestions", "Bugs" or "Documentation", but the concepts are all inter-related and macro-specific, so I placed it here.
There's perhaps a couple of buglets here (you decide), a suggestion for LOCATE cmd enhancement, and a request for a bit more hand-holding from the documentation (i've offered some words).
(1) Set_Csr()
I think the documentation needs a touch-up.
I think the documentation needs a touch-up.
a) It states:
"Operands line-ptr the line pointer of the line where the cursor is to be placed."
I mistakenly(!) interpreted this as Set_Csr will reposition the cursor at time of execution, e.g. mimicking a user moving the cursor with keyboard or mouse before entering a new command.
In practice, Set_Csr only pre-selects the desired cursor location to be applied when the macro exits, in the same way as Set_TopScrn_LPtr "pre-selects" the top of page line for macro exit.
The help doc for Set_Csr should probably use similar wording to that for Set_TopScrn_Lptr which correctly describes the function, e.g.:
"Operands line-ptr the line pointer for the line to be positioned at the top of screen when the macro exits."
"Operands line-ptr the line pointer for the line to be positioned at the top of screen when the macro exits."
b) I think the Set_Csr documentation should also mention that:
"REGARDLESS of where a macro's actions may leave the cursor, the cursor will ALWAYS be placed on the command line when the macro exits.
If you wish to place the cursor elsewhere, you MUST issue a Set_Csr command immediately before the macro ends"
Example:
' IT.MACRO
SPF_Cmd("FIND halt WORD")
Halt(OK,"Cursor LPtr="+Get_Csr_LPtr+" Col="+Get_Csr_Col)
This will hi-lite the word 'halt' and display message Cursor LPtr=3 Col=17 but the cursor will actually be positioned in the command line and not where the FIND command left it.
' IT.MACRO
SPF_Cmd("FIND halt WORD")
Halt(OK,"Cursor LPtr="+Get_Csr_LPtr+" Col="+Get_Csr_Col)
This will hi-lite the word 'halt' and display message Cursor LPtr=3 Col=17 but the cursor will actually be positioned in the command line and not where the FIND command left it.
(2) Set_TopScrn_Lptr
a) Under 'Special Notes' the Set_TopScrn_Lptr documentation states
"If your macro uses both Set_TopScrn_LPtr and Set_Csr, the
positioning of Set_Csr will override that of the Set_TopScrn_LPtr if
the desired cursor position is not within the visible screen as set by
the Set_TopScrn_LPtr function. i.e. Set_Csr 'wins'"
In reality, this is not true at all.
When both functions are specified, even if the Set_Csr position IS on the visible screen, Set_TopScrn_LPtr loses out.
The top line on the screen will be the line immediately preceeding the Set_Csr line.
I think this is a bug.
(Should be easily fixable if the code applies TopScrn_Lptr first and the applies Set_Csr. That's effectively what I do below via LOCATE)
The only way I found to reliably(!) set the Top-of-Screen line is to use LOCATE TOP followed by Set_Csr
Even then, the sequence of the statements is important.
Example: This works!
' IT.MACRO
SPF_Cmd("LOCATE TOP !50") ' Top of Page at Lptr 50
Set_Csr(60,25) ' Cursor at Lptr 60, col 25
HALT
SPF_Cmd("LOCATE TOP !50") ' Top of Page at Lptr 50
Set_Csr(60,25) ' Cursor at Lptr 60, col 25
HALT
Example: This does NOT work!
' IT.MACRO
Set_Csr(60,25) ' Cursor at Lptr 60, col 25
SPF_Cmd("LOCATE TOP !50") ' Top of Page at Lptr 50
HALT
Set_Csr(60,25) ' Cursor at Lptr 60, col 25
SPF_Cmd("LOCATE TOP !50") ' Top of Page at Lptr 50
HALT
The general case is that the Set_Csr statement always fails (or is ignored), if it is followed by another statement that moves the cursor before the macro ends.
(That's why I included the word 'immediately' in the in Help text in 1b) above)
Could be considered a buglet. Or be covered by amending the documentation accordingly(3) LOCATE command - how about a 'DX' operand
Given that Set_Csr(...) only applies at macro-exit time, an obvious choice to position the cursor during a macro might be the LOCATE command.
When LOCATE is used to position to a particular line, and that line happens to be 'excluded', the action of LOCATE will make the line visible.
Normally, this is desirable, after all, why would anyone locate a line and keep it hidden?
Well, for example, to get around the Set_Csr(...) constraints, e.g. reposition the cursor without affecting the line's attributes, like it's XSTATUS.
For now, this, rather inelegant, sequence circumvents the issue:
tmp$ = Get_XStatus$(LineLPtr) ' Get line exclude status
SPF_Cmd("LOCATE !"+LinePtr) ' Set cursor to LinePtr line
IF tmp$ = "X" THEN SPF_Cmd("LINE `X` !"+LinePtr) ' Put it back as Excluded
SPF_Cmd("LOCATE !"+LinePtr) ' Set cursor to LinePtr line
IF tmp$ = "X" THEN SPF_Cmd("LINE `X` !"+LinePtr) ' Put it back as Excluded
Suggestion: How about you add a 'DX' operand to the LOCATE command syntax?
The above effect would then be achieved simply (and more clearly) with this statement
SPF_Cmd("LOCATE DX !"+LinePtr) ' Set cursor to LinePtr line
(4) What's left in the command line when macro ends with non-zero RC?
Normally, when a command raise a WARNing or FAIL return code, the command, as entered by the user, is left in the command line.
When a macro issues ends with a WARN or FAIL return code, instead of the users's command, the, logically, last SPF_CMD() executed before macro exit is left on the command line.
Note, this is not necessarily the actual SPF_CMD(...) which raised the non-zero return code.
Therefore it's value as a debugging aid is, at best, questionable.
I think that command line should either be blank, or retain the name of the macro and its operands, as entered by the user - i.e. business as usual.
(Presently, I circumvent the problem by adding a SPF_CMD(" ") statement before the 'HALT' statement to always leave the command line blank.
Seeing a load of Reg-Ex gobbledeegook disguised as a FIND command isn't nice when LP issues RC=4 just to highlight the error message)
(5) GBL Tables - fabulous feature - thank you!
I hadn't worked with this before and found it quite confusing to begin with.
Most of my initial confusion stemmed from the names of the function calls being so similar and the some nomenclature is inconsistent, e.g. Get_Gbl_Num_Name$ actually requests what is also referred to as 'key-str' everywhere else.
Suggestion: (I suggest LABEL would be a more descriptive moniker than 'Name' or 'key-str' but it may be too late to change this)
Suggestion: Maybe a small section in the Appendix of the Documentation entitled "Working with Global Storage Tables" might be appropriate.
The individual function descriptions could remain brief and simply refer/link to that section for more info.
And it offers an opportunity to list and describe the functions in the order they relate to each other rather than purely alphabetically.
I humbly offer the following as an example/starter set:
<some words to introduce Global storage, and how it can be used to allow macros to share data with each other, within a given edit tab or even across edit tabs.
Perhaps also a reference to the XF, XFLY, XPOP macros in the sample set>.
STORAGE STRUCTURE:
1) Tables
Global data is saved in tables which are identified by a table number.
This table number is optional. If no table number is specified, SPFlite will use table number 0
The tables persist only until the SPFLite session terminates, i.e. data is not available to another instance of SPFLite. (Not sure 'instance' is the right word here)
<Some info here about what range of table number is allowed, do they need to be consequetive, do specific table numbers have different properties, e.g. table 9 is saved/reloaded at SPFlite stop/start respectively, etc>
(I briefly considered using Get_Uniq_ID fo LP.MACRO but wasn't sure if SPFLite would like the large numerical values)
2) Entries
Each entry in a table consists of a 'Label/key-str' and 'Value' pair.
Entries are organised according to the data type of the 'value' being stored.
Use the ...Gbl_Num... functions to store/retrieve/find numeric 'value' entries and the ...Gbl_Str... functions to store/retrieve/find string 'value' entries.
<some info here about how many entries are allowed/recommended for each table>
STORING DATA IN GLOBAL STORAGE:
Function Set_Gbl_Num(...) is used to create/replace a numeric 'value' entry
Function Set_GBL_Str(...) is used to create/replace a string 'value' entry
Both functions accept the following operands:
a table number Optional Number. If specified, it must be the first operand. If omitted, table number 0 is assumed.
the entry label Required String. This is a label/name to identify the 'value' to be stored.
the value Required String/Number. This is actual 'value' to be associated with the preceding label/name.
RETRIEVING DATA FROM GLOBAL STORAGE:
Function Get_Gbl_Num(...) is used to retrieve a number value from global storge
Function Get_Gbl_Str(...) is used to retrieve a string value from global storage.
Function Get_Gbl_Str(...) is used to retrieve a string value from global storage.
Both functions accept the following operands:
a table number Optional Number. If specified, it must be the first operand. If omitted, table number 0 is assumed.
the entry label Required String. This is a label/key-str used to identify the 'value' to be retrieved.
the value Required String/Number. This is actual 'value' which is associated with the preceding label/key-str.
a table number Optional Number. If specified, it must be the first operand. If omitted, table number 0 is assumed.
the entry label Required String. This is a label/key-str used to identify the 'value' to be retrieved.
the value Required String/Number. This is actual 'value' which is associated with the preceding label/key-str.
SEARCHING FOR DATA IN GLOBAL STORAGE: <--- I'm not sure how much of this section is correct. The descriptions mention 'index-num' but I think that should perhaps be 'key-str' or 'value'?
You can determine how many entries of either numeric values or string values there are in each table.
Function Get_Gbl_Num_Count(...) returns a count or the number of entries storing a numeric 'value'
Function Get_Gbl_Str_Count(...) returns a count or the number of entries storing a string 'value'
Both functions accept a single operand:
a table number Optional Number. If specified, it identifies a single table to be searched. If omitted, 0 is assumed and all tables will be searched.
(I don't understand the purpose of ...._tableName$. I assume it searches ALL tables and returns the first match it finds, i.e. it relies on the entry 'value' to be unique. Big assumption!)
You can search an individual table or all tables for a specific label/key-str/index string or for a specific 'value' entry.
Function Get_Gbl_Num_TableName$(...) is used to search for the table number and the label/key-str of an entry associated with a particular numeric 'value'.
Function Get_Gbl_Str_TableName$(...) is used to search for the table number and the label/key-str of an entry associated with a particular string 'value'
Function Get_Gbl_Str_TableName$(...) is used to search for the table number and the label/key-str of an entry associated with a particular string 'value'
Both functions accept a single operand:
the value Required String/Number. This is actual 'value' which is associated with the ith to be associated with the preceding label/name.
(Similarly, ...._Name$. I assume it searches ALL tables and returns the first match it finds, i.e. it relies on the entry 'value' to be unique.
Perhaps this one should also offer the optional, or even required table number operand to restrict the search)
Function Get_Gbl_Num_Name$(...) is used to search a table for the label/key-str of an entry associated with a particular numeric 'value'.
Function Get_Gbl_Str_Name$(...) is used to search a table for the label/key-str of an entry associated with a particular string 'value'
DELETING DATA FROM GLOABL STORAGE:
There doesn't seem to be a function that allows entries to be deleted/removed from global storage.
Is that an oversight or deliberate because the data vanishes when SPFLite terminates anyway?
General comments onthe documentation...
The use of the 'index-num' looks odd to me in the following help entries.
Get_Gbl_Num_Name$
Get_Gbl_Num_TableName$
Get_Gbl_Str_Name$
Get_Gbl_Str_TableName$
Get_Gbl_Num_TableName$
Get_Gbl_Str_Name$
Get_Gbl_Str_TableName$
There's no description regarding what an 'index-num' is meant to be, hence my uncertainty in the search paragraph above.
Is the 'index-num' perhaps related to the GET_GBL_xxx_COUNT functions, so one can obtain a count and then loop through the named table by index number?