Version: 01.50.00 - last Update: Tuesday, October 13, 2009, 12:30:00
Examples | Good2Know | Tips&Tricks
Intro
Foxtools editor-related functions let us access VFP’s underlying Editor-API. Calls into VFP’s API are implemented in FLL libraries which are created with the help of FoxPro’s Library Construction Kit and a C/C++ compiler. For those who are not that familiar with C/C++ (like me) using the Foxtools editor functions is a handy way to access VFP’s Editor-API directly without having to write C/C++ code.
The only drawback in using a prefabricated set of FLL-based functions is that there is no way to fix bugs without having the sources. Thus, it is essential for a successful application of Foxtools’ editor functions to be aware of all bugs, even lurking oddities! Because this documentation demands to be a complete one, it cannot be sufficient to show how to properly use each function. There should be realistic examples and additional information as well.
Function Sub-Grouping
All 31 editor-related Foxtools functions can be sub-grouped into following categories:
- Display
- Content
- Clipboard
- Queries
- Undo
- Environment
- Error
Display
_EdActive | _EdSetPos | _EdSToPos | _EdSToSel
Display-related editor functions do not alter the editor’s content. They can show, hide and move the caret or scroll the textual content up and down in the edit area.
Content
_EdOpenFil | _EdCloseFi | _EdRevert | _EdSelect | _EdIndent | _EdInsert | _EdSendKey | _EdDelete | _EdComment
Content-related editor functions do alter the editor’s content, obviously. They let us open and close files, insert and delete text and save and revert our changes.
Clipboard
Clipboard-related editor functions enable us to retrieve content from (and store it to) the Windows clipboard.
Queries
_EdGetChar | _EdGetLNum | _EdGetLPos | _EdGetPos | _EdGetStr | _EdPosInVi | _EdSkipLin
Some of the queries retrieve caret-related information, other return a character or strings or calculate offsets. All those function have one thing in common: they always calculate their offsets from the beginning of the editor’s text buffer and use zero-based counting.
Undo
Undo-related commands let us group editor actions to undo/redo blocks. Apart from that, they map to the well known CTRL+Z & CTRL+Y shortcuts, that most of the Windows applications support.
Environment
_EdGetEnv | _EdSetEnv | _EdProcList | _EdProperties
Environment-related functions can be separated into those with a GUI and those without. _EDGetEnv and _EdSetEnv() are working with an internal array (without a GUI). _EdProcList() and _EdProperties() are used to launch the appropriate dialog forms.
Error
_EdLastErr() is the only error-related Foxtools function. In point of fact, errors that may be introduced by using invalid handles or pointers/offsets, can be trapped using TRY CATCH ENDTRY or any other VFP error handling because the Foxtools editor functions are “translating” editor-API errors into native VFP errors.
Common Terms
In this chapter I will explain some expressions used all over when talking about Foxtools’ editor functions.
Editor (Text-)Buffer
Opening a new editor instance using _EdOpenFil() for example, or by typing a MODIFY COMMAND ? into VFP’s Command window lets us select a file from our disk. The content of the file is then loaded into the editor session’s (text-)buffer. Each line of the file (on the disk) ends at least with an Carriage Return (CR := CHR(13)) but can also has an additional Line Feed (LF := CHR(10)). This depends on the Edit Properties setting shown below. BTW this setting can also be read/written using _EdGetEnv() and _EdSetEnv() – aEnv[7] holds the corresponding flag value.
During file load FoxPro strips off any additional Line Feeds so that all lines in the editor’s buffer only have a CR at their end. This is exactly what you will see when turning on display white spaces (see screenshot below).
You can determine the actual buffer content length using _EdGetEnv() – aEnv[2] holds that byte count (see below).
What we also see is that the CRs at the end of each line are counted! This is important to know when we have to calculate an offset within the text buffer.
The Caret
There are some other words for the caret which are used interchangeably; sometimes the caret is called Cursor, sometimes Insertion Point depending on the context. Anyway, the caret (I tried to use this name all over) plays a central role when it comes to programmatically modify an editor’s buffer. You can hide the caret using _EdActive(nWH, .F.) as long as the referenced editor session isn’t the active one. More important, you have to know exactly how the caret position (which is a simple integer value) is determined!
Counting From Zero
Let’s start with a new, empty editor session (with display white spaces enabled!). The text buffer length still is zero but the caret already is displayed! Therefore, this caret position value apparently can only be <0>! Same is true for line numbering: there still is no line content, the caret is on the empty line <0>. Now, let’s type in the letter “A”. The caret blinks behind the A; its position now is <1>. Press Carriage Return and the caret gets moved down to the next line. Behind the A we see a new CR-mark. What’s the position value of the caret now? You’re right, the new caret offset is <2> (on line <1>).
Offsets and Positions
Programming VFP’s string functions all day long, we got used to count the characters in our strings starting with <1>. In contrast, all editor functions start counting with <0>! Therefore, we have to keep in mind, that all offsets and line item specifications that are used by Foxtools’ editor functions are seen from a caret’s point of view!
During my documentation I noticed, I was using some position terms more often:
- BOF (begin of file)
- EOF (end of file)
- BOL (begin of line)
- EOL (end of line)
Using the first two may be a little bit confusing. To be precise, they should read BOB (begin of buffer) and EOB (end of buffer) because that’s where they really point to. During an editor session we add and/or delete words and lines. Thus, the EOB pointer will differ from the EOF pointer pretty fast – they equal each other only just after loading or saving the file. Nevertheless, I decided to prefer the better-known BOF and EOF abbreviations. Keep in mind, that we never talk about pointers to file contents, but always referring to the editor text buffers. Okay, now for a short description of the four…
BOF (Begin of File/Buffer)
This is no real, variable pointer. Its value is a fixed <0> (column/character #0, line #0)
EOF (End of File/Buffer)
The value of this pointer can be retrieved either using _EdGetEnv(nWhnd, @aEnv) (the buffer-size returned in aEnv[2] holds the EOF value) or by using a nested function call like this: _EdSkipLin(nWhnd, _EDGETLPOS(nWhnd, -1),1). The EOF pointer always holds the value we would position the caret if we wanted to add new text to the end of our editor buffer.
BOL (Begin of Line)
The value of this pointer can be easily retrieved using _EdGetLPos(nWhnd, nLineNo). Again, keep in mind line numbering is zero-based! Thus, _EdGetLPos(nWhnd, 0) will return the offset position before the fist line which equals BOF := <0>. The BOL pointer holds the value we would position the caret if we wanted to start adding new text before any existing one on a given line.
EOL (End of Line)
As there is no “native” Foxtools editor function to retrieve the value of an EOL pointer, we have to construct one ourselves. Fortunately, that is not really complicated. Assuming that <nLineNo> holds the (zero-based) line number we want to get the EOL value from, _EdGetLPos(nWhnd, nLineNo+1)-1 does the job. The EOL pointer holds the value we would position the caret if we wanted to add text at the end of a given line. After setting the caret to an EOL position like this:
_EdSetPos(nWHnd,_EdGetLPos(nWhnd, nLineNo +1)-1), we could see the caret blinking between the last character and the CR-mark (with display white spaces set ON, of course).
The Editor (Session-) Handle
There’s one thing all Foxtools editor functions have in common: they require a valid (session-)handle! Fortunately, passing an invalid handle today creates a trappable FoxPro error #2028 “API call caused an exception”. There’s only one way to test if a handle belongs to an active editor session: we have to check _EdGetEnv()’s return value. Because this involves some undesired overhead (we have to create an array first), my current solution is to wrap my editor functions in TRY-CATCH-ENDTRY statements if I’m not sure about my editor session handle’s validity. Naturally, you can use any other VFP error-trapping, too.
I’ve seen many code fragments used to demonstrate how to retrieve a valid editor session handle. Sometimes I’d got the notion that some of the authors didn’t know the difference between an editor session handle and a FoxPro window handle! The only truth is: there is none! At the moment you’ve retrieved the handle of a FoxPro window running an editor session you have the session handle as well! For example, the Foxtools window-related function _WONTOP() will return such an internal “old-fashioned” FoxPro windows handle. Now, if the expression: _EdGetEnv(_WOnTop(), @aEnv) = 1 is TRUE, then you’re already done: the current _WONTOP() window handle is a valid editor session handle! Naturally, the _EdOpenFil() function will always return a valid valid session handle, if its return value is not zero.
Boundary Checking
There are some Foxtools editor functions that allow us to move the caret or to retrieve text from the editor’s buffer, as well as writing text to it. These functions are working with offset parameters that tell the called function where to position the caret, or where to insert the new text. Unfortunately, there is no sufficient boundary-checking built in internally (if at all)! In other words, in some cases we are able to write/read over the editor buffer’s memory boundaries! Be aware of that when calculating offset values in your code. It seems to be a good idea to check them against valid boundary values twice before passing them in :-)