Document | TSE_PRO_v4.4_Undocumented_Features.html |
Author | Carlo Hogeveen |
Origin | Website |
Version | 0.50 - 6 Feb 2022 |
This text file describes some of the features of TSE Pro v4.4 which are not documented in TSE's built-in Help system.
A topic title here usually references a same-named topic title in TSE's built-in Help system. A topic only occurs here if there is additional or corrected information. In this document only a topic's additional or corrected information is described.
Note that after you select a topic in the index, then you can copy its URL from the browser's address bar to use it elsewhere as a link.
It is not possible to conditionally compile only part of a condition.
For example, compiling the following macro reports a syntax error.
proc Main() if FALSE #ifdef WIN32 or TRUE #endif Warn('Yes!') else Warn('No!') endif PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
Bug: It is not possible to use a non-existing predefined constant in an #else clause.
For example, this fails to compile:
#if FALSE #else #define FUTURE_CONSTANT _FUTURE_VALUE_ #endif
A work-around is to use two #if statements, one for each conditional branch.
This function does not call the _on_exit_called_ hook, but otherwise on the last file implicitly does an Exit() too.
Therefore also see: Process().
"A maximum of 60 external Compiled Macro files may be loaded at any one time."My tests say the actual number is 58.
"Each external Compiled Macro file may have up to 63k of Compiled Macros."But not always:
Each procedure ("proc") can in its compiled form not be larger than 32 kB. For a larger compiled procedure the compiler will give the error message:
"Range of loop or goto > 32k, please reduce size"For example, if a macro only consists of one "proc", then compiling the macro will report an error if the procedure is so large that the resulting .mac file would be larger than 32 kB, even though normally .mac files may be 63kB in size.
White space means a sequence of space and horizontal tab characters.
This function has an optional integer parameter that indicates how many times to perform the action.
Some not explicitly documented behaviour of binary mode.
When loading a file in normal mode, TSE strips line ending characters like the carriage return (CR) and line feed (LF) characters from a text before showing it to us.
When loading a file in binary mode it does not do that stripping and treats the carriage return and line feed characters as any other character.
When you load a file in binary mode, for example by opening it with "-b<N> <filename>" where <N> is a positive number, then editor's shown lines for that file will have a fixed length <N> that will have have nothing to do with the text's actual lines: Line ending characters like a carriage return and line feed will explicitly be shown as characters in the text. (But see Note 2.)
Undocumented feature:
If you load a file with binary mode <N> is -3, then the file is loaded like
with a positive <N>, but with each line's actual length, including its actual
line ending characters like carriage returns and line feeds. Practical!
Note 1:
So binary mode -3 is like the binary modes <positive number>, but handier,
and unlike binary modes -1 and -2, which do something completely different.
Note 2:
In the GUI version of TSE with an ANSI compatible font any control characters,
like the line ending characters carriage return and line feed, are shown as
spaces, which is not practical in binary mode.
The TSE extension "ControlChars" from my website solves that by explicitly
showing each control character as a different character, and by making control
characters stand out for any TSE version and font.
Once you are editing a file in binary mode, you can lengthen and shorten an editor line by inserting characters up to TSE's maximum line length and by deleting characters down to an empty line. When you do not add or delete line ending characters this has no impact on the number of lines in the actual text.
You can even delete and insert empty editor lines without any impact on the file.
When saving a file in binary mode the editor's visual lines are ignored.
The saved file wil only have line endings where explicit carriage return and/or line feed characters occurred in the editor text.
TSE has a problem with searching in binary mode:
While TSE no longer implicitly sees text lines in binary mode,
TSE's search commands are still limited to finding search results
in buffer lines, so they will not find search results which are
(arbitrarily!) split between two buffer lines.
The "when" clause of a "case" statement can not only have a list of values separated by commas and a range of values separated by "..", but also both at the same time.
For Example:
case CurrChar() when 66..68, 70..72, 74..78, 80..84, 86..90 Warn('This is an upper case consonant') endcase
The range of a "when" clause can also be a range of characters.
For example:
case GetText(CurrPos(),1) when 'B'..'D', 'F'..'H', 'J'..'N', 'P'..'T', 'V'..'Z' Warn('This is an upper case consonant') endcase
If ChangeCurrFilename() successfully changes only the case of a file name, then the file is not marked as modified.
For example, given an unchanged file "D:\helloworld.txt", changing its name to "D:\HelloWorld.txt" will not mark the file as modified.
The WordSet and ChrSet() documentation misses a reference to the ClearBit(), GetBit() and SetBit() functions.
Its documentation states not wrongly that it returns a value < 0, == 0 or > 0, but actually it only returns the values -1, 0 or 1.
This enables us to execute the "expensive" CmpiStr() only once using a "case" statement.
For example:
case CmpiStr(string1, string2) when -1 // Usually most common ... // Handle ascending order when 1 ... // Hanlde descending order otherwise ... // Handle same order endcase
The 2nd paragraph of this topic's documentation still states:
"Command-line options are identified by either the "-" or "/" character, immediately followed by the letter that designates the desired option."As of TSE Pro 4.4, only the "-" character is supported.
Tip for macro programmers:
Default you can start a macro from the command line, but not pass it any
parameters other than files to be loaded simultaneously.
By installing the TSE extension
CmdLineParameter
you can pass parameters too.
You cannot debug a macro that contains a config ... endconfig clause.
A constant declaration may be made globally and in a procedure.
There is an undocumented way to initialize multiple constants in one statement. The actual syntax for "constant" is:
constant identifier [= constant_expression] [, identifier [= constant_expression]] ...The difference is, that the constant_expressions may be omitted.
If the constant_expression of the first identifier is omitted, then its value is 1.
If the constant_expression of any next identifier is omitted, then its value is that of its predecessor plus 1.
Examples:
constant a = 1, b, c // a == 1, b == 2, c == 3. constant d, e = 10, f // d == 1, e == 10, f == 11. constant g = -10, h, i // g == -10, h == -9, i == -8.The purpose is to shortly give significant names to consecutive values.
Examples:
constant January, February, March, April, May, June, July, August, September, October, November, December constant smaller_than = -1, equal_to, greater_than
A test showed that CopyBlock() used 33% less memory than Copy() + Paste().
To overwrite the destination file the third parameter must be truthy (any value that a conditional statement would interpret as true).
For example, instead of TRUE we can also use the more readable constant _OVERWRITE_.
The content of the Windows clipboard stops at a NULL character. In TSE that is the character represented by the single byte value 0. In the Windows clipboad text is default character encoded as UTF16-LE and then ended with two bytes with value 0.
This is not a TSE bug. It is a property of the Windows clipboard when it contains text.
This might become relevant when copying the contents of a binary file or a file with non-printable characters.
TSE's internal copy commands do not have this problem.
This setting determines the format of FFDateStr() too.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
Despite what its name might suggest, DelChar() does not add the deleted character to the Deletion Buffer, so it cannot be undeleted, and so there is overhead involved.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
Besides the documented parameters
_DISPLAY_TEXT_ _DISPLAY_HEX_ _DISPLAY_PICKFILE_it has these undocumented ones:
_DISPLAY_FINDS_ _DISPLAY_HELP_ _DISPLAY_USER_
_DISPLAY_FINDS_
This parameter will colour the current file the same as TSE colours the results of a Find() with the "v" option: The current line will be coloured with MenuSelectLtrAttr if the line starts with "File: ", and MenuSelectAttr otherwise. Other lines will be coloured with MenuTextLtrAttr if the line starts with "File: ", and MenuTextAttr otherwise.
But: Browsing to a new line will not change colouring accordingly. Modifying a line will change that line's colouring to that of a current line but will not recolour other lines. It seems necessary to do a new DisplayMode(_DISPLAY_FINDS_) after each user action that therefore might require new colouring of the editing window.
_DISPLAY_HELP_
A valuable source for this section was Chris Antos' GetHelp macro from 2002. Any mistakes in the document you are now reading are mine.
Again, a Unicode warning: This document uses UTF-8 character encoding, which matters to the below text: Read it with a web browser, or install the Unicode macro from my website to read this text in TSE.
DisplayMode(_DISPLAY_HELP_) changes the display of the current file immensely:
The file is displayed with OEM characters, mainly to use their line drawing capability (ANSI does not support this). For example see the Help2txt macro's "to_utf8" proc for Unicode codes and descriptions which are the equivalents of typically used OEM character codes. For users of a GUI version of TSE: Temporarily switch to an OEM font like Terminal, start drawing lines or (partioned) boxes, and switch back to an ANSI font like Courier New to see what you have wrought character-wise.
Default the text is coloured with HelpTextAttr.
Text between the following tags is coloured accordingly.
Text between the tags | Is coloured with |
---|---|
®I¯ and ®/I¯ | HelpItalicsAttr |
®B¯ and ®/B¯ | HelpBoldAttr (aka "Highlighted") |
®L¯ and ®/L¯ | HelpLinkAttr |
®LI¯ and ®/L¯ | HelpInfoAttr |
®T¯ and ®/T¯ | HelpTextAttr |
®S¯ and ®/S¯ | HelpTextAttr |
The tags are not shown: Shown text is left-shifted to the actual text.
Tag colouring exception 1:
If the cursor is on the first character of the opening
tag ®L¯ or ®LI¯, then the text after the tag is coloured
with HelpSelectAttr.
Tag colouring exception 2:
Some tag's colouring can overrule another's.
Text between the tags ®B¯®T¯ and ®/T¯®/B¯,
and text between the tags ®B¯®S¯ and ®/S¯®/B¯
will in both cases colour the text with HelpBoldAttr.
Note that DisplayMode(_DISPLAY_HELP_) only changes how the text of the current file is coloured, nothing more. It has no notion of what the text between tags means, and it performs no actions of any kind. For example, in TSE's Help the tags are used to colour links, but it is TSE's internal Help that acts when you select a link: DisplayMode(_DISPLAY_HELP_) and its tags do not do that.
_DISPLAY_USER_
Intended for use with HookDisplay(). See HookDisplay().
Outside HookDisplay() _DISPLAY_USER_ seems to behave like _DISPLAY_TEXT_.
This function has an optional integer parameter that indicates how many times to perform the action.
This function's flag parameter also has the flag _START_HIDDEN_, which will cause the command to invisibly start and run in a hidden Windows process.
In newer versions of TSE the _DONT_PROMPT_ and _DONT_CLEAR_ flags can be omitted when using the _START_HIDDEN_ flag, but that makes the macro not backwards compatible, so I advise against it.
This function also has a flag _DONT_WAIT_, which when combined with the _RUN_DETACHED_ flag will make the started command a parallel process.
For example,
#define DOS_SYNC_CALL_FLAGS _DONT_PROMPT_|_DONT_CLEAR_|_START_HIDDEN_|_RETURN_CODE_ #define DOS_ASYNC_CALL_FLAGS _DONT_PROMPT_|_DONT_CLEAR_|_START_HIDDEN_|_RETURN_CODE_|_RUN_DETACHED_|_DONT_WAIT_ if FALSE lDos(LoadDir(TRUE), '', DOS_ASYNC_CALL_FLAGS) else Dos(LoadDir(TRUE), DOS_ASYNC_CALL_FLAGS) endifstarts a second instance of the editor, and you can work in both instances of the editor simultaneously. Here lDos() is better, because Dos() also starts a useless blank window.
Without _RUN_DETACHED_ the Dos() command "eats" any unprocessed keys, making TSE ignore them. In tools that is usually not a problem, in extensions it ususally is.
This function has an optional integer parameter that indicates how many times to perform the action.
Unlike its documentation implies, its return value will only indicate whether it was capable of creating a new buffer, not whether it succeeded in loading the supplied file into it.
So if it could not load the file, then it still returns the id of a newly created empty buffer.
Also unlike its documentation implies, a successfully loaded file will not be marked as a character block like InsertFile() does.
Bug: EditThisFile() can open more than one file.
/* Example of EditThisFile() opening TWO files. Since quotes are illegal in file names, the appropriate response would be returning FALSE, and giving a warning if _DONT_PROMPT_ is not passed. */ proc Main() string my_file [MAXSTRINGLEN] = '"file1.txt" "file2.txt"' EditThisFile(my_file) PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
White space means a sequence of space and horizontal tab characters.
The below line from the documentation needed two additional qualifications:
If the RemoveTrailingWhite variable is set ON
and the buffer is not a _SYSTEM_ buffer
and the buffer is not in binary mode
,
then this command will remove any trailing white space found on the
current line.
Definitely see: Process().
Keyboards can have multiple places where you can type the same key. Typically this is the case for the cursor keys and the Home, End, Insert, Delete, PageUp, PageDown, /, *, +, - and Enter keys.
If the EquateEnhancedKbd setting is ON, which is the default, then it becomes irrelevant at which place on the keyboard you type a key.
If the EquateEnhancedKbd setting is OFF, then TSE sees different keys depending on at which place on the keyboard you type a key.
By using the ShowKey macro from TSE's Potpourri menu we can see, that TSE does or does not prefix the key name with "Grey " depending on where on the keyboard a key was typed.
Here is the main undocumented fact:
If EquateEnhancedKbd is OFF and no action is assigned to a "grey" key, then TSE executes the action assigned to the "non-grey" key.
An example of this can be found in the Potpourri's Calendar macro, that even if EquateEnhancedKbd is OFF will act on "grey" cursor keys despite having no definition for them.
Definitely see: Process().
The returned date is formatted according to the DateFormat setting.
The returned time is formatted according to the TimeFormat setting.
This is not a topic in TSE's built-in Help system.
To find out which specific folders and files on your computer TSE cannot access, you can execute the DirList macro, and supply it with "C:\ D:\" etcetera as a parameter.
In the result you can then search for "<inaccessible" with options "giv", and optionally use <Alt e> to edit that search result as a file.
Possible annotations to find are "<inaccessible folder>" and "<inaccessible file>".
TSE has several problems with too long paths. For example MkDir()'s specific problem starts after 247 characters. According to Semware the general limit is >= 255 characters.
Luckily, such deep paths are not the norm.
Unluckily, even one such path can make TSE's "-s" parameter return an aborted result or even hang TSE. The "-s" is a command line and EditFile() parameter to list files in all subfolders too.
Reader warning: If you read this file offline with TSE: This is a web browser optimized document that uses Unicode characters, especially in this topic. To read it in TSE you should have TSE's Unicode extension installed. Otherwise use a web browser to read this document.
The Windows file system stores its folder and file names in the UTF-16LE character encoding, which is a fully complient Unicode character encoding, that therefore implements practically all the world's characters, for example containing 137,994 characters as of Unicode 12.1, released in March 2019.
TSE only knows the ANSI (formally Windows-1252) character encoding for the file system. ANSI contains 218 characters.
TSE does no conversion of its own, but uses the standard Windows ANSI APIs to access the file system. For more info see the Microsoft documentation about Unicode in the Windows API and Code Pages .
These Windows ANSI APIs have the nice feature, that (when TSE reads a folder name or file name) they convert the file system's UTF-16LE to ANSI if these character encodings have an equivalent character, and that they convert a UTF-16LE character to a close approximation in ANSI if the character encodings do not have an equivalent character. The other way around (when TSE writes a folder name or file name) the Windows APIs always convert characters exactly, because all ANSI characters have a Unicode equivalent.
For example, this means that a "copyright sign", written as "©", is no problem in a folder or file name, because both UTF-16LE and ANSI have this character, so the Windows ANSI APIs never have a problem converting it.
For another example, this means that when we browse with TSE, we see a "greek small letter alpha" in a folder or file name as an "a", because the greek letter alpha exists in UTF-16LE but not in ANSI, so the Windows ANSI APIs show TSE an approximation. From TSE opening a folder name containing an alpha fails with an error, because the nearest ANSI equivalent of an alpha is an "a", and the folder does not exist with an "a" in its name. From TSE opening a file name containing an alpha fails by opening a new empty file: It does not open the file with an alpha in its name, but it opens a new empty file that has an "a" in the alpha's place.
If you do not use any Apple products in Windows, then the following does not apply to you. But if, for instance, you use Apple's iCloud drive in Windows, or you otherwise have or get access to files created on a Mac or iProduct, then do read on for some dirty details.
In Unicode (and therefore in UTF-16LE) characters with a diacrital mark can be written in two ways:
- As one character. For example, the character "é" can be written as the one Unicode character "latin small letter e with acute".
- As two characters. For example, the character "é" can be written as the two Unicode characters "latin small letter e" and "combining acute accent".
Windows, and thus the Windows ANSI APIs, and thus TSE, all default to the first format. So if you use TSE just with Windows products then life is good.
Enter Apple, who uses the second format when it creates new folders and files.
Both Apple's operating systems and Windows know both formats, and for both formats show the same single character. So far life is still OK.
( Though not perfect: This creates the weird possibility, that in one folder you can have two files with what appears to be the same name without the ability in Apple and Windows to see why they differ. )
The Windows ANSI APIs choose to convert the second format to two ANSI characters: The base character followed by a normal accent character. (Because ANSI does not have "combining" accent characters, the APIs again convert to the nearest equivalent; a "normal" accent character.)
To continue the previous example, when browsing, TSE sees an Apple folder or file with an "é" character as "e'". Opening a folder with an Apple "é" in its name fails with an error, because TSE tries to open that name with "e'" instead. Opening a file with an Apple "é" in its name opens a new empty file with "e'" in its name instead.
Unlike with the alpha character you can work around the diacritical problem:
- The first work-around is to not use diacritical marks for folder and file names shared between Apple products and Windows.
- The second work-around is to create or once rename such folders and files in Windows: In my experience Apple products understand and do not change back the "non-combining" Windows convention for existing folder and file names with diacritical marks. Note, that you typically only need to do this for folder and file names that need to be accessible from TSE.
This function contains an obscure bug, that I ran into when looking for a solution to be absolute sure about opening only one specific given file.
Here is a macro that demonstrates the problem:
/* If the following file exists in the current folder "file1.txt file2.txt" then when accessing the not-existing file '"file1.txt" "file2.txt"' FileExists() and fOpen() erroneously do find it, while FirstFirstFile() correctly does not. It does not matter if "file1.txt" and "file2.txt" exist. */ integer proc FileExists_with_FindFirstFile(string p_file) integer result = FALSE integer handle = -1 handle = FindFirstFile(p_file, -1) if handle <> -1 result = FFAttribute() FindFileClose(handle) endif return(result) end FileExists_with_FindFirstFile integer proc FileExists_with_fOpen(string p_file) integer result = FALSE integer handle = -1 handle = fOpen(p_file) if handle <> -1 fClose(handle) result = TRUE endif return(result) end FileExists_with_fOpen proc Main() string my_file [MAXSTRINGLEN] = '"file1.txt" "file2.txt"' while Ask('Test existence of which folder or file:', my_file) Message('File is ===', my_file, '===') Warn('File'; iif(FileExists(my_file), 'DOES', 'does NOT'); 'exist with FileExists().') Warn('File'; iif(FileExists_with_fOpen(my_file), 'DOES', 'does NOT'); 'exist with fOpen().') Warn('File'; iif(FileExists_with_FindFirstFile(my_file), 'DOES', 'does NOT'); 'exist with FindFirstFile().') endwhile PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
Unlike its documentation states, this command will NOT find a folder unless a second parameter _DIRECTORY_ is supplied.
As of TSE Pro v4.2 this function also works for letters with diacritics if the editor does not use an OEM font.
This function contains an obscure bug, that I ran into when looking for a solution to be absolute sure about opening only one specific given file:
If the following file exists in the current folder "file1.txt file2.txt", then when accessing the non-existing file '"file1.txt" "file2.txt"' FileExists() and fOpen() erroneously do find it, while FirstFirstFile() correctly does not. It does not matter if "file1.txt" and "file2.txt" exist. For an example macro see FileExists().
Given that the "for" statement syntax is:
for integer_variable = numeric_expression to/downto numeric_expression2 [by numeric_expression3] statements endforThe "statements" can influence the for-loop by changing the value of "integer_variable", but not by changing "numeric_expression", "numeric_expression2" or "numeric_expression3".
In other words, "numeric_expression", "numeric_expression2" and "numeric_expression3" are evaluated only once; at the start of the for-loop.
In some cases this can make a "for" statement (possibly in combination with a "break" statement) more efficient than a "while" statement.
If "by numeric_expression3" comes after "to numeric_expression2", then a positive value for "numeric_expression3" will increase "integer_variable" and a negative value for "numeric_expression3" will decrease "integer_variable".
If "by numeric_expression3" comes after "downto numeric_expression2", then a positive value for "numeric_expression3" will decrease "integer_variable" and a negative value for "numeric_expression3" will increase "integer_variable".
That said, "numeric_expression3" should never be negative, because with it only for-loops can be written that loop zero or infinite times.
It could be argued that this is a bug, since its value is allowed to be negative but is then handled inconsistently.
For example:
for i = 1 to 2 by -1 -> infinite times for i = 1 to 1 by -1 -> infinite times for i = 1 to 0 by -1 -> zero times for i = 1 to -1 by -1 -> zero times for i = 1 to -2 by -1 -> zero times for i = 1 downto 2 by -1 -> zero times for i = 1 downto 1 by -1 -> infinite times for i = 1 downto 0 by -1 -> infinite times for i = 1 downto -1 by -1 -> infinite times for i = 1 downto -2 by -1 -> infinite times
If you use semicolons (";") instead of commas (",") to separate parameters, then the concatanated parameters will be separated by the equal amount of spaces.
For example, after
s1 = Format('a', 'b'; 'c';; 'd';;; 'e';;;; 'f';;;;; 'g')s1 will contain the string
'ab c d e f g'
If you keep reading when the end of the file has been reached, then fRead() keeps returning 0 for the bytes read, not -1 for an error.
Chr(0) bug: SetBufferStr() and GetBufferStr() strip characters with ASCII code 0 from the end of a value, and Warn() strips it and all other characters after one such a character.
Demo macro:
proc Main() integer hash_id = 0 integer org_id = GetBufferId() string s [MAXSTRINGLEN] = 'a' + Chr(0) hash_id = CreateTempBuffer() GotoBufferId(org_id) SetBufferStr('key', s, hash_id) Warn('Bug: "2 2 a ." <> "', Length(s); Length(GetBufferStr('key', hash_id)); s, '."') AbandonFile(hash_id) PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
Beware of this risk! :-) GetClockTicks() returns the number of "clockticks" (the number of 1/18ths of a second) since the start of the TSE session, and TSE's integer limit is 2,147,483,647, so your TSE session might destabilize if left open for more than 3.78 years!
As documented this function has two var parameters, that return the next variable name and variable value from a section of an initialization file (typically with extension ".ini"), the contents of which for example look like:
[section name 1] var name 1=value 1 var name 2=value 2 var name 3=value 3 ...However, sometimes you need to store just a list of values, for example:
[section name 2] value 1 value 2 value 3 ...Undocumented is, that GetNextProfileItem() can handle that as long as the .ini file's data line contains no "=" character. In that case it returns an empty string for the variable name and it returns the whole line for the variable value.
For completeness sake: If a data line contains two or more "=" characters then GetNextProfileItem() returns everything before the first "=" character as the variable name and everything after the first "=" character as the variable value. For example for this data line:
var name 1=value 1=the best value=a great deal=the greatestthe function GetNextProfileItem() returns the two parameter values "var name 1" and "value 1=the best value=a great deal=the greatest".
GetNextProfileItem() will trim spaces from variable names and values. For instance, for a line " variable 1 name = variable 1 value " GetNextProfileItem() will return the parameter values "variable 1 name" and "variable 1 value".
GetNextProfileItem() only ignores empty lines, so there is no way to comment lines in a section that GetNextProfileItem() might be used on. The only safe ways to comment a TSE initialization file is before the first section or to put comments in their own separate section(s). For example:
This is a comment. [section 1] var1=value1 [section 2 comments] The value "value1" may only be the string "true" or "false". [section 2] var1=value1
The parameter "item" stands for the item's name.
Spaces around the item name are irrelevant, both in the parameter and in the initialization file.
If a section in the initialization file contains the same item name twice, then GetProfileStr() will return the value of the first occurrence.
The parameter item name may be an empty string. For example, if the initialization file looks like this:
[file extension descriptions] .s=This is a SAL (Semware Application Language) macro. .txt=This is a text file. =This is an extensionless file. .pl=This is a Perl program.then GetProfileStr('file extension descriptions', '', 'Not Found') will return "This is an extensionless file.".
See GetNextProfileItem() for more info on the initialization file.
To define it more specifically, the second format, GetTime() without parameters, returns the number of hundredths of seconds since the last midnight.
GetToken(string s, string delimiter, integer token_no) works differently if the delimiter is a space character:
- Multiple spaces are treated as one space.
- Leading spaces are ignored.
For example, Gettoken(' a b', ' ', 1) returns "a" and Gettoken(' a b', ' ', 2) returns "b" instead of empty strings.
This command does not change the column position.
This function has an optional integer parameter.
If UserHiliteFoundText() is FALSE, then HiLiteFoundText(N) will hilite a string N positions to the right of where it otherwise would. N can be negative to hilite to the left.
According to Semware this parameter was once upon a time created for one user for one macro.
The editor can handle 168 hooks total overall.
Undocumented properties for these specific hooks:
It was not possible to update the screen from an idle event, but as of the GUI version of TSE Pro v4.4 it is: See the Transparency topic.
This hook exists from the GUI version of TSE Pro v4.2 onwards.
It is also called when TSE closes. A Warn() statement from a _LOSING_FOCUS_ hook, that is called when TSE closes, might leave a hidden TSE session. I am still investigating the details.
Bug: This hook is not called when the GUI version of TSE is closed with its close button.
Contrary to what its documentation states, the _ON_FIRST_EDIT_ hook is also called when changing an already loaded file's name.
I received the following information from Semware:
QUOTE
HookDisplay(currline_offset, before_offset, after_offset, foundtext) currline_offset, before_offset, after_offset, foundtext_offset are macro procs that are called at certain times: currline_offset : called for each line (redrawline) before_offset : called before redraw after_offset : called after redraw foundtext_offset: called when hilited text is found See debug.si, potpourr.s, and whtspc.s for examples.UNQUOTE
The following information was deduced and tested.
HookDisplay([proc1], [proc2], [proc3], [proc4]) optionally hooks each of four specific events to a proc name without parameters. The commas are mandatory.
If you do not want to use all four hooks then you just leave out a proc name. For example, HookDisplay(,,,MyProc) is legal syntax.
For the first proc you can define it to have no or one integer parameter. An integer parameter would receive a boolean value that is TRUE if the proc is called for the current line and FALSE otherwise
HookDisplay() also sets DisplayMode(_DISPLAY_USER_) to enable these hooks.
Temporarily setting DisplayMode() to another value disables the hooks without unhooking them.
For example: The Potpourri menu uses DisplayHook() to colour the first 12 characters of each line differently, but with DisplayMode(_DISPLAY_TEXT_) it temporarily disables that while viewing the help for an item (F1) and while editing the help text for an item (Alt E), and it sets DisplayMode(_DISPLAY_USER_) back when these excursions from the Potpourri menu are done.
UnhookDisplay() unhooks the four possible events, and restores DisplayMode() to the value it had when HookDisplay() was called.
The function name and the first line of the official documentation are misleading as to its broader functionality, which is correctly explained in the rest of the topic as recognizing a string that consists of one or more digits.
Another way to define isDigit(s) is, that for every value of string s:
isDigit(s) == StrFind('^[0-9]#$', s, 'x'))Note that the value of isDigit('') is FALSE, and that the value of isDigit() depends on the character under the cursor.
This function is obsolete and always returns 0.
The "in" operator has non-intuitive behaviour.
The "in" operator is correctly implemented as documented, but it deserves an explicit mention because of
"and" and "or" are higher precedence operators than "in" and ",".
For instance, the condition
if (2 in 1, 2, 3) and FALSEevaluates to
FALSE
But the condition
if 2 in 1, 2, 3 and FALSEevaluates as
if 2 in 1, 2, (3 and FALSE)which evaluates as
if 2 in 1, 2, 0which evaluates to
TRUE
"not" is a higher precedence operator than "in" and ",".
For instance, the condition
if not (2 in 4, 5, 6)evaluates to
TRUE
But the condition
if not 2 in 4, 5, 6evaluates as
if (not 2) in 4, 5, 6which evaluates as
if 0 in 4, 5, 6which evaluates to
FALSE
Advice:
Whether (you are in doubt) or (you are not in doubt),
always use parentheses with the "in" operator.
You cannot include a file from an included file. That is, nested includes do not work.
The inserted data is marked as a character block.
Additial note: This command also fails if the supplied file does not exist.
If a macro uses KeyDef to limit user keys while editing text, then CUAMark and "friends" (other macros that work likewise) do not honour those limits.
That is because CUAMark does not use key definitions for most of its editing keys, but it checks what keys were pressed and then adds it own functionality, whether a key is currently defined or not. Luckily CUAMark and friends are an exception, but on occasion they have to be dealt with.
A work-around for TSE Pro v4.4 upwards is for the "KeyDef-macro" to be lower in TSE's Macro AutoLoad List than CUAMark and friends or to be otherwise loaded later than CUAMark and friends, and for the "KeyDef-macro" to implement this _AFTER_GETKEY_ hook:
proc after_getkey() if not isKeyAssigned(Query(Key)) BreakHookChain() // Nice solution: leaves Key's value unchanged. // Set(Key, -1) // Hard solution: changes Key to dummy value. endif end after_getkey proc WhenLoaded() Hook(_AFTER_GETKEY_, after_getkey) end WhenLoaded
Known bug:
In TSE's GUI version after a key is pressed the first call to KeyPressed() always returns FALSE.
The work-around is to first do another KeyPressed() and ignore its result.
KeyPressed() has a useful side-effect for macros that run a long time.
Probably since an earlier Windows version but definitely since Windows 10, when a macro runs for some time without user interaction, Windows stops updating the screen and shows an hourglass until the macro is finished.
This is not a TSE-specific issue but a general Windows issue.
This typically is a problem if the macro is showing a progress indicator. Any other visual progress on the screen is halted too.
KeyPressed() to the rescue!
By adding a KeyPressed() to the macro inside a loop where it will be called regularly, Windows sees an attempt at user interaction and will not disable screen updates.
Since KeyPressed() has no other side-effects, it will not effect the macro's functionality.
This function has an optional integer parameter that indicates how many times to perform the action.
lDos() also has a flag _START_HIDDEN_, which will cause the command to invisibly start and run in a hidden Windows process.
In newer versions of TSE the _DONT_PROMPT_ and _DONT_CLEAR_ flags can be omitted when using the _START_HIDDEN_ flag, but that makes the macro not backwards compatible, so I advise against it.
lDos() also has a flag _DONT_WAIT_, which when combined with the _RUN_DETACHED_ flag will make the started command a parallel process.
For example,
#define DOS_SYNC_CALL_FLAGS _DONT_PROMPT_|_DONT_CLEAR_|_START_HIDDEN_|_RETURN_CODE_ #define DOS_ASYNC_CALL_FLAGS _DONT_PROMPT_|_DONT_CLEAR_|_START_HIDDEN_|_RETURN_CODE_|_RUN_DETACHED_|_DONT_WAIT_ if TRUE lDos(LoadDir(TRUE), '', DOS_ASYNC_CALL_FLAGS) else Dos(LoadDir(TRUE), DOS_ASYNC_CALL_FLAGS) endifstarts a second instance of the editor, and you can work in both instances of the editor simultaneously.
Here lDos() is better because Dos() also starts a useless blank window.
Without _RUN_DETACHED_ the lDos() command "eats" any unprocessed keys, making TSE ignore them. In tools that is usually not a problem, in extensions it ususally is.
lDos() also has a flag _DONT_CHANGE_TITLE_.
This function has an optional integer parameter that indicates how many times to perform the action.
The current buffer is emptied when the supplied file does not exist.
This function has an optional integer parameter, which if not zero (not FALSE) will make LoadDir() return the fully qualified name of TSE's executable.
For example for the GUI version of TSE:
exe_string = LoadDir(TRUE) // exe_string == 'C:\Users\Carlo\Tse\g32.exe'
As of TSE Pro v4.2 this function also works for letters with diacritics if the editor does not use an OEM font.
If used to execute and terminate a loop within a file (the original Find() or lFind() it was based on did not use the "a" option to search across files), then this command automatically stops.
Bug: If used to execute and terminate a loop across files (the original Find() or lFind() it was based on did use the "a" option to search across files), and the search string occurs in more than one open file, then the loop becomes infinite, i.e. never stops.
White space means a sequence of space and horizontal tab characters.
The built-in documentation states that the available stack space is "approximately 16k". A test says it is approximately 61k.
This function has an optional integer parameter.
The parameter is the block_type, as in: _INCLUSIVE_, _NON_INCLUSIVE_, _LINE_, _COLUMN_.
To be more specific, MakeTempName() only looks at the disk to create a new unique filename, not at TSE's unsaved buffers nor at its own previous call results.
You can supply the optional extension parameter with or without a leading period.
Aside, the numbers MakeTempName() generates are not as random as they seem, because in tests without saved disk files they consistently turned repetitive within 200 tries.
The editors maximum line length is documented as being 16000, while it actually is 32000.
If you use semicolons (";") instead of commas (",") to separate parameters, then the concatanated parameters will be separated by the equal amount of spaces.
For example
Message('a', 'b'; 'c';; 'd';;; 'e';;;; 'f';;;;; 'g')will show the string
'ab c d e f g'
TSE strings can have a maximum length of 255 characters, but based on experiments MkDir's parameter is limited to a maximum length of 247 characters.
To overwrite the destination file the third parameter can be any truthy value, i.e. any value not equal to FALSE.
For example, instead of TRUE we can also use the more readable constant _OVERWRITE_.
There is a very minor bug in MoveFile():
MoveFile(<file1>, <file2> [, <overwrite>])deletes <file2> if <file1> does not exist and <overwrite> is truthy.
When you pass MsgBox() two parameters (title and message), then MsgBox() presents an OK button, but always returns zero, even when you press or click the OK button.
Too long lines are not wrapped to the next line.
Its documentation states that it does.
MsgBox() and MsgBoxEx() do not have this bug.
Here is a test macro that demonstrates the bug:
proc Main() integer i = 0 integer org_id = GetBufferId() string s [MAXSTRINGLEN] = '' integer tmp_id = CreateTempBuffer() for i = 10 to 200 by 10 s = Format(s, i:10:'.') endfor AddLine('Hello world!', tmp_id) AddLine(s, tmp_id) Warn('Hello world!', Chr(13), s) MsgBox('MsgBox', Format('Hello world!', Chr(13), s)) MsgBoxEx('MsgBoxEx', Format('Hello world!', Chr(13), s), '[&OK]') MsgBoxBuff('MsgBoxBuff') GotoBufferId(org_id) AbandonFile(tmp_id) PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
This function has an optional integer parameter that indicates how many times to perform the action.
NextChar(variable) returns FALSE if the variable has value 0.
NextChar(0) returns an unpredictable integer value that varies with the context in which the command is used. The return value can be 0 too. On the bright side, in practice it makes no sense to use a hardcoded 0 as NextChar()'s parameter, let alone question its return value.
NoOp() has the erroneous side effect, that when it is used in an _AFTER_GETKEY_ hook, then it disables the CUAmark macro's ability to delete a shift-marked block when we start typing.
The logical work-around is to use nothing or a comment instead of NoOp().
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
PushUndoMark() and PopUndoMark() are undocumented functions with a serious bug.
Their intended function seems to be, that you can do PushUndoMark() in a normal buffer, do any number of temporary changes, and then restore the buffer with PopUndoMark() Undo().
However, if there were no changes between PushUndoMark() and PopUndoMark(), then PopUndoMark() Undo() restores the buffer to an extra Undo() earlier than that.
Demo of the bug:
/* This macro demonstrates a bug in PushUndoMark() and PopUndoMark(). For UNDO_MARK = 50 it correctly creates a new buffer with numbers 1 to 50. for UNDO_MARK = 100 it incorrectly creates a new buffer with numbers 1 to 91. The bug can be phrased this way: If there were no changes between PushUndoMark() and PopUndoMark(), then PopUndoMark() and Undo() restore the buffer not to its state at PushUndoMark(), but to one extra Undo() before that. */ proc Main() integer i = 0 integer UNDO_MARK = 50 NewFile() for i = 1 to 100 if (i - 1) mod 10 == 0 AddLine(' ' + Str(i)) else EndLine() InsertText(' ' + Str(i), _INSERT_) endif if i == UNDO_MARK PushUndoMark() endif endfor PopUndoMark() Undo() PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
Example of how PushUndoMark() and PopUndoMark() can be used safely:
proc Main() integer old_UndoCount = 0 // ... Get to the point where a current buffer's state needs preserving ... // Save the buffer's current state. old_UndoCount = UndoCount() PushUndoMark() // ... Do stuff to it that needs reversing later ... // Restore the buffer's saved state. PopUndoMark() Undo() if UndoCount() < old_UndoCount Redo() // Correct for the PopUndoMark() bug's extra Undo(). endif // ... Go on with the restored buffer ... PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
Unlike its name suggests and the documentation states, the keyboard is completely bypassed, and no key appears pressed anywhere in any way.
No TSE command is capable of noticing a key was "pressed" by PressKey(), and the passed key is not stored in TSE's "Key" variable.
Instead PressKey() directly executes the commands that are assigned to the key, and any statements after PressKey() are not executed until PressKey()'s assigned commands are finished.
By itself PressKey() is not capable of executing commands that are assigned to a key combination. You can get around that by doing a PushKey() of the second key followed by a PressKey() of the first key.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter.
PrevPosition() only tracks file and line position changes.
PrevPosition(1) also tracks column position changes.
This function has an optional integer parameter.
The intended functionality is this:
The actual functionality is different and much more elaborate, but in its current usage the differences are irrelevant:
Terminology is very important here. Let's follow and build on Semware's terminology as much as possible.
The Process() topic states that it starts a new "editor process".
It would be more specific to state that Process() starts the "editing loop" of a new "editor process".
An "editing loop" is an optional part of an "editor process". For instance at the start of a .ui file's WhenLoaded() procedure there already is an "editor process" that is running the WhenLoaded() procedure but there is no "editing loop" yet. When Process() starts an "editor process" it also starts its "editing loop".
Semware speaks of "the main editing loop" in the "Event", "Hook", and "QueryEditState()" topics.
In TSE's context an "editing loop" is the part of the "editor process" that for the current editing buffer waits for and acts on your key strokes.
QueryEditState() will return zero for an editing loop started by Process() too.
Process() starts a new editor process like a subroutine: The editor process that calls Process() waits until the editing loop of the called editor process is finished before continuing with any next statement.
A called editor process inherits the complete state of the calling editor process.
When the called editor process finishes, the calling editor process inherits any state back that the called editor added with the specific exception of key definitions.
Any called Process() can initiate its own Process(), thus creating a stack of called editors processes.
A called editor process can mainly be exited in two ways:
EndProcess() ends the editor process at the top of the stack of those editors processes that were created with Process(). So it does nothing when executed in the base editor process, because that was not started by a Process().
Exit() possibly ends the whole stack of those editor processes that were created with Process(), and sometimes the base editor process.
For Exit() it matters if the base editor process has an editing loop or not. If the WhenLoaded() procedure in the editor's .ui file starts a Process() and thus the first editing loop, then the base editor process has no editing loop.
At the time Exit() is called
if all the editor processes on the stack were called with Process() or Process(0), then Exit() immediately terminates all editor processes without executing any statements after any Process(), otherwise Exit() will will wait for editing loops to be (re)turned to and terminate them, until no more editing loops exist or a new file is opened.
Note that not all of this is necessarily logical behaviour. For instance the above "if" condition reveals that a non-zero child Process() parameter can negate a zero parent Process() parameter. The described behaviour was revealed by extensively testing commands beyond their current usage.
Unlike the documentation states, the key stack is not limited to 64 keys. That was true for TSE v2.8 and below. As of TSE v3.0 the key stack is limited to 512 keys.
The documentation uses the term "stack" to describe PushKey()'s behaviour.
Stack explanation:
A stack implies, that when you put things on a stack in a certain order,
then you have to take them off off the stack in the reverse order.
For PushKey() this stack-like behaviour means for example that
PushKey(<a>) PushKey(<b>) PushKey(<c>)results in TSE's next keyboard reading commands seeing the text "cba".
Terminology:
TSE's documentation contains a pleonasm: It states that its keyboard stack is
a LIFO (Last In First Out) stack. But all stacks are LIFO. That is what the
term "stack" means. The common counterpart of a stack is a queue. A queue is
processed FIFO (First In First Out).
Unlike the documentation states, the key stack is not limited to 64 keys. That was true for TSE v2.8 and below. As of TSE v3.0 the key stack is limited to 512 keys.
For example, the sequence of commands
PushKeyStr('blue') PushKeyStr('pink')results in TSE's next keyboard reading commands seeing the text "pinkblue".
For example, to enter two lines of text, the stack-principle applies too, so push the Enter key before pushing each line of text, and push the lines in reverse order:
PushKey(<Enter>) PushKeyStr('This is the second line.') PushKey(<Enter>) PushKeyStr('This is the first line.')
See PopUndoMark().
This is a synonym for _dont_prompt_, and can be used everywhere where _dont_prompt_ can be used.
For an example: Semware uses it in their AutoSave macro.
Bug: PutStrAttrXY(..., ..., ...., '', Color(Black on Black)) uses Query(Attr) instead of Color(Black on Black).
This bug is specific to the Color(Black on Black) value.
For example, this will display a yellow on blue text:
Set(Attr, Color(bright yellow ON blue)) PutStrAttrXY(5, 5, 'Hello world!', '', Color(black ON black))
A work-around is to Set(Attr, Color(Black on Black)) before using PutStrAttrXY().
If QuitFile() closes the last open file, then (without calling the _onexit_called_ hook) implicitly an Exit() is done.
Therefore also see: Process().
TSE's maximum string length is 255 characters. When quoting an unquoted string of 254 or 255 characters, QuotePath() deletes the last 1 or 2 characters of the string respectively, so that it always can add the quotes.
This function takes a string parameter and returns the string without a trailing slash if it had one.
Examples:
s = RemoveTrailingSlash('a') // s == 'a' t = RemoveTrailingSlash('a\') // t == 'a'
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
White space means a sequence of space and horizontal tab characters.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
Obviously and implicitly an Exit() is done too.
Therefore also see: Process().
As documented in Hook(), this function does not call the _ON_FILE_SAVE_ and _AFTER_FILE_SAVE_ hooks.
As documented in Hook(), this function does not call the _ON_FILE_SAVE_ and _AFTER_FILE_SAVE_ hooks.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
Here is the most insignificant TSE bug I have ever found, but it is somewhat relevant, because it might confuse users who try to delve into the rest:
If you use TSE's regular Find() command to search without the "+" option for a regular expression that matches an empty string, and you do that twice without changing the cursor position, then TSE hilites the current cursor position.
This is a hiliting bug: in this case a character is hilited when an empty string is found.
Examples:
Find('.*', 'x') // Anywhere in or at the end of a line. Find('.@', 'x') // At the end of a line.
The regular expression character "?" is non-greedy. In TSE's terminology: it uses minimal closure. Both mean to say that it prefers to match an empty string. A scary example: if a text contains "book" and you search for "book?" then you will find "boo" (highlighted).
Here is a cool pattern matching hack:
If you create a regular expression with a sequence of tagged patterns AND group them with a tag AND follow that group with "|<something that always matches>", then as long as from left to right the tagged subpatterns match, each match still gets a tag number (that is 1 higher than its occurrence).
For example, if a text contains a line with 3 items like
"(a,b,c)"
and you search that line for 5 subpatterns like with
"{({a},{b},{c},{d},{e})}|{,}"
with the "cgx" option, then for n = 1 to 5 the statement
GetFoundText(n + 1) will return the subpatterns that matched until
a non-matching one is found and an empty string otherwise;
here "a", "b", "c", "", "".
Note 1: The patterns before the "|" must not be able to overlap for this to work. So for example instead of a list of patterns like '"{.*}","{.*}"' use a list of patterns like '"{[~"]*}","{[~"]*}"'. In other words, the list of patterns must be allowed to fail as a whole, and while failing the regular expression will try to match longer strings for a ".*" pattern, which much fail for our purpose.
Note 2: The <something that always matches> part is tricky: not all logical values work; you might have to experiment a bit.
The following is not an undocument feature, but a caveat about implied behaviour that macro programmers tend to stumble upon.
".*" "[0-9]*" "[A-Za-z]?" "{a}|{.*}"
"a@" // If the current character is not an "a". "{a}|{.@}" // Always at the end of a line.
Chr(0) bug: SetBufferStr() and GetBufferStr() strip characters with ASCII code 0 from the end of a value, and Warn() strips it and all other characters after one such a character.
Demo macro:
proc Main() integer hash_id = 0 integer org_id = GetBufferId() string s [MAXSTRINGLEN] = 'a' + Chr(0) hash_id = CreateTempBuffer() GotoBufferId(org_id) SetBufferStr('key', s, hash_id) Warn('Bug: "2 2 a ." <> "', Length(s); Length(GetBufferStr('key', hash_id)); s, '."') AbandonFile(hash_id) PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
As the CreateBuffer() help states:
"Undo/Redo information is NOT recorded for _SYSTEM_ buffers."
TSE has "three" sort programs:
The internal Sort() function.
The TSE Help documentation states, that it needs a marked block to sort on, that it only uses the first 80 characters of that block as its sort key, and that it can sort a maximum of 65535 lines.
Tests show the maximum sort key size is actually 282 characters.
The external tsort.com executable.
Start it from the command line with "tsort /?" to see its possible arguments. Where it says "99" you can actually use more than two digits.
Tests show its maximum sort key size is 4095 characters.
Horribly, tests also show that it splits lines that are longer than 8191 characters!
The Sort.s macro, used by TSE's menu.
Based on convoluted rules this tool either calls the internal Sort() function or the external tsort.com executable.
The Sort macro calls the internal Sort() function if one of these conditions applies:
How | When |
---|---|
Silently | If no block is defined. |
Silently | If the block has less than 2000 lines. |
After asking you | If it cannot find the external tsort.com program. |
After asking you | If the current file is in binary mode. |
After asking you | If the current block contains a vertical tab, a carriage return or a line feed character. Note that a normal file normally contains no carriage returns nor line feeds when loaded in TSE. |
If you are asked " ... Use slow sort?", then this refers to the internal Sort function, and if you reply No or Cancel or Escape, then no sort is done at all.
Sad conclusion:
There are files that TSE cannot sort.
The menu's Sort a.k.a. the Sort macro, hides which set of limits
applies and thereby why a sort fails.
Moreover, when any TSE sort fails, it often does so silently,
and possibly even horribly.
This function has an optional integer parameter that indicates how many times to perform the action.
The function StrCount(needle, haystack) counts overlapping needles too.
Examples:
StrCount('aa', 'aaa' ) // Returns 2. StrCount('aa', 'aaaa') // Returns 3.
This function is imperfectly documented, and the 4th parameter is incorrectly implemented.
Abbreviated syntax:
result = StrFind(needle, haystack, options, start, var len)StrFind's return value (further on referred to as "Result") is documented as:
The fourth parameter "start" is weirdly documented as:
The fourth parameter was better named "occurrence", and was better defined as:
Especially for backward searches the "start" parameter is incorrectly implemented; its results are inconsistent.
Below is the output of a test macro that demonstrates the problems. When two separate assesments are given, then the first pertains to the returned result and the second to the returned length. It is acceptable that start 0 is treated as default for start 1. It is acceptable that for result 0 length has no defined value.
StrFind('b', 'abcabc', 'i',-1, len) // Result = 1, Length = 0 WRONG StrFind('b', 'abcabc', 'i', 0, len) // Result = 2, Length = 1 ACCEPTABLE StrFind('b', 'abcabc', 'i', 1, len) // Result = 2, Length = 1 OK StrFind('b', 'abcabc', 'i', 2, len) // Result = 5, Length = 1 OK StrFind('b', 'abcabc', 'i', 3, len) // Result = 0, Length = 1 OK, ACCEPTABLE StrFind('b', 'abcabc', 'bi',-1, len) // Result = 7, Length = 0 WRONG StrFind('b', 'abcabc', 'bi', 0, len) // Result = 5, Length = 1 ACCEPTABLE StrFind('b', 'abcabc', 'bi', 1, len) // Result = 5, Length = 1 OK StrFind('b', 'abcabc', 'bi', 2, len) // Result = 5, Length = 1 WRONG StrFind('b', 'abcabc', 'bi', 3, len) // Result = 2, Length = 1 WRONG StrFind('b', 'abcabc', 'bi', 4, len) // Result = 0, Length = 1 OK, ACCEPTABLE
StrFind() is "slow". This is because it is implemented as pasting the haystack into a helper buffer and then doing an lFind(). Anything that updates a TSE buffer is "slow". This "slowness" is only human noticeable when a macro does massive amounts of StrFind()s. In such cases it pays where possible to use Pos() or FastStrFind() in its stead.
This function does not have the errors of StrFind.
StrReplace('b', 'abcabc', 'B', 'i',-1) // Result = "abcabc" ACCEPTABLE StrReplace('b', 'abcabc', 'B', 'i', 0) // Result = "aBcaBc" ACCEPTABLE StrReplace('b', 'abcabc', 'B', 'i', 1) // Result = "aBcaBc" OK StrReplace('b', 'abcabc', 'B', 'i', 2) // Result = "abcaBc" OK StrReplace('b', 'abcabc', 'B', 'i', 3) // Result = "abcabc" OK StrReplace('b', 'abcabc', 'B', 'bi',-1) // Result = "abcabc" ACCEPTABLE StrReplace('b', 'abcabc', 'B', 'bi', 0) // Result = "aBcaBc" ACCEPTABLE StrReplace('b', 'abcabc', 'B', 'bi', 1) // Result = "aBcaBc" OK StrReplace('b', 'abcabc', 'B', 'bi', 2) // Result = "aBcabc" OK StrReplace('b', 'abcabc', 'B', 'bi', 3) // Result = "abcabc" OK StrReplace('b', 'abcabc', 'B', 'bi', 4) // Result = "abcabc" OK
A string slice with only one parameter has length 1.
For example, the string slices s[3] and s[3:1] work exactly the same, both before and after the assigment operator.
Examples:
string s[9] = 'abcde' string t[9] = '' t = s[3] // t == 'c' s[4] = 'x' // s == 'abcxe'
Info:
Delimiters can be strings with letters: Such delimiters are case
sensitive.
Bug:
In the TSE submenu "SyntaxHilite Mapping Configuration" ->
"Delimiter Tokens" we can define three Quotes and an Escape character
for each Quote.
Testing shows, that each Escape character applies to its matching Quote
only, so the position of the Escape character in the configuration menu
matters.
The bug is, that if a previous Quote has no Escape character in the
configuration menu and an Escape character is applied to a later Quote
in the menu, then initially and visually the menu seems to do so, but
after (!) leaving the menu when the changes are automatically saved to
the .syn file, then the Escape character is moved to the first Quote
that had no Escape character.
So you did not escape the Quote that you thought you did.
Work-around: define a Quote that has an Escape character before a Quote
that has none.
Info:
Examples of what strings are hilited as, assuming default SAL syntax hiliting and "-" being part of the hiliting Keyword WordSet:
String(s) | Hilited as |
---|---|
1b | A (binary) number. |
1a | One text. |
+1 | A keyword and a number. |
-1 | A bug and a number. |
1a+b | Text, a keyword and text. |
1a-b | One text. |
1-ab | A number, a bug and text. |
and or | A keyword, text and a keyword. |
andor | One text. |
Grey+ | One keyword. |
Grey- | One keyword. |
Grey+proc | Two keywords. |
Grey-proc | One text. |
Note, that it is quite common that predefined keywords are not hilited as such.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
This setting determines the format of FFTimeStr() too.
Changing this setting only works in the GUI version of TSE.
Trick:
Changing the Transparancy setting refreshes the screen.
This can be a work-around in cases where UpdateDisplay() does not work,
for example from an _IDLE_ or _NONEDIT_IDLE_ hook.
For these hooks this needs to be followed by an UpdateDisplay(),
in other cases the screen updates without it.
Example:
Set(Transparency, Query(Transparency)) UpdateDisplay() // Mandatory for _IDLE_ hook, optional in some other cases
White space means a sequence of space and horizontal tab characters.
As elsewhere the CreateBuffer() help states:
"Undo/Redo information is NOT recorded for _SYSTEM_ buffers."
As the CreateBuffer() help states:
"Undo/Redo information is NOT recorded for _SYSTEM_ buffers."
Unhooks the procs hooked with HookDisplay() and restores DisplayMode() to the value it had when HookDisplay() was called.
The exact specification is untested, so the following is just an educated guess.
Syntax: UnloadAllBuffers()
Returns: Unknown.
Does an UnloadBuffer() for all open files.
I do not know a practical use case for this command. If you actually do use this command please let me know what for.
Syntax: UnloadBuffer(integer id)
Returns: TRUE if it did unload the buffer, FALSE if it did not.
Unloads the content of the buffer for which the id is passed,
but only if that buffer:
AND has a _NORMAL_ BufferType(),
AND has no changes,
AND exists as an identically named file on disk.
Note, that it is a TSE feature, that files can be opened and not yet loaded. This typically happens when you open multiple files at once using wildcards; then only the first file will be loaded and the rest will not be until they are accessed.
One possible use of UnloadBuffer() is to simply reduce TSE's memory usage by unloading a file that for now is no longer used.
An extreme(ly useful) example of UnloadBuffer()'s usage is the following. Using wildcards you can open more files than TSE can load into memory. A macro can still process all those files without running out of memory by opening them one at a time and doing an UnloadBuffer() for each file after processing it.
This function has two optional integer parameters:
UnLockCurrentFile([integer keep[, integer file_attribute]])
There are two kinds of file locking - handle and attribute.
Handle locking
In handle locking, the file is sometimes created.
In some cases, when one is unlocking the file, one wants to remove this file, in other cases, not.
This can be indicated by setting "keep" to FALSE or TRUE.
The file_attribute is used in attribute locking (e.g., read-only).
This function has an optional integer parameter that indicates how many times to perform the action.
In some cases UpdateDisplay() cannot refresh the screen, for example from an _IDLE_ or _NONEDIT_IDLE_ hook.
See the Transparency setting for a work-around trick.
As of TSE Pro v4.2 this function also works for letters with diacritics if the editor does not use an OEM font.
This function is undocumented.
So far its observed behaviour is, that it seems to return TRUE immediately after a Find() and FALSE immediately after an lFind().
Trailing spaces are ignored too. For example, Val("123 ") will return the number 123.
If you use semicolons (";") instead of commas (",") to separate parameters, then the concatanated parameters will be separated by the equal amount of spaces.
For example
Warn('a', 'b'; 'c';; 'd';;; 'e';;;; 'f';;;;; 'g')will show the string
'ab c d e f g'
In the console version of TSE Warn() behaves as described.
In the GUI version of TSE this function displays the formatted result string differently than described:
Example:
A GUI version of TSE with a ridiculously small screen width of 40
would display
Warn('He sissed:', Chr(13), '':40:'s')as
He sissed: ssssssssssssssssssssssssssssssssssss ssss
A Console version of TSE would display the single status line:
He sissed:Xssssssssssssss Press <Escape>where X is whatever your console version of TSE displays for a carriage-return character (possibly a music symbol) and where 26 "s" characters are cut off.
Tip:
In the file "Compatibility_downto_tse40.inc" v1.5 or higher a procedure
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Chr(0) bug: SetBufferStr() and GetBufferStr() strip characters with ASCII code 0 from the end of a value, and Warn() strips it and all other characters after one such a character.
Demo macro:
proc Main() integer hash_id = 0 integer org_id = GetBufferId() string s [MAXSTRINGLEN] = 'a' + Chr(0) hash_id = CreateTempBuffer() GotoBufferId(org_id) SetBufferStr('key', s, hash_id) Warn('Bug: "2 2 a ." <> "', Length(s); Length(GetBufferStr('key', hash_id)); s, '."') AbandonFile(hash_id) PurgeMacro(SplitPath(CurrMacroFilename(), _NAME_)) end Main
A WhenPurged() procedure is implicitly forward referenced. This means, that in a macro you can call a WhenPurged() proc that is defined further on in the source without defining a forward reference.
A WhenPurged() procere is not called when the editor is closed. Often this is irrelevant, because WhenPurged() usually just implements cleaning up data in TSE memory. But if a WhenPurged() procedure also cleans up data outside TSE, like for example a temporary disk file, then an easy solution is to add a Hook(_ON_ABANDON_EDITOR_, WhenPurged) to the WhenLoaded() procedure.
This function has an optional integer parameter that indicates how many times to perform the action.
This function has an optional integer parameter that indicates how many times to perform the action.
The WordSet and ChrSet() documentation misses a reference to the ClearBit(), GetBit() and SetBit() functions.