syntax highlight richedit control not working poperly - c++

I am trying to implement a syntax highlight editor with a richedit, it has works well with the current selected line, but I may be missing something. The CRichEdit is my own wrapper implementation of the richedit controller, the problem seems that the text is not selected properly even though I made sure the selected range generated with the code were what I get with the EM_EXGETSEL message.
The selection seems increasing 1 as the lines goes down, so I decided to ed_source.sendMessage(EM_LINEFROMCHAR, pos, 0) to the range which partially fix the problem except for some few lines where the coloring seems some time one or to position before and the real appropriate, so that is why I thing I may not be understanding something.
void parse(WIN::CRichEdit &ed_source, bool curseline)
{
int pos, offset = 0;
char delimiter[]={" \n\r(){};"}, *tok, *start;
CStringA s;
CString text;
CWnd api;
if(curseline){
ed_source.getLine(ed_source.getRow() - 1, text);
offset = ed_source.sendMessage(EM_LINEINDEX, -1, 0);
}else{
text = ed_source.getCaption();
}
s = text;
start = s.c_str();
if(!start) return;
tok = strtok(s.c_str(), delimiter);
CHARRANGE cr = ed_source.getSelecteRange();
ed_source.sendMessage(EM_HIDESELECTION, 1, 0) ;
CHARRANGE range;
while(tok)
{
int len = strlen(tok);
pos = (tok - start);
int x = ed_source.sendMessage(EM_LINEFROMCHAR, pos, 0);
range.cpMin = offset + pos - x;
range.cpMax = range.cpMin + len;
ed_source.selectRange(range);
if(isReserved(tok)){
ed_source.setTextStyle(true, false);
ed_source.setTextColor(keyboardColor);
}else
if(isType(tok)){
ed_source.setTextStyle(false, false);
ed_source.setTextColor(typeColor);
}else {
ed_source.setTextStyle(false, true);
ed_source.setTextColor(textColor);
}
tok = strtok(0, delimiter);
}
ed_source.sendMessage(EM_HIDESELECTION, 0, 0) ;
ed_source.selectRange(cr);
}
just to be more specific the moment I call the above function is immediately after loading the text on it. I assumed you may want to see the implementation of some of the above functions so here they are.
CHARRANGE CRichEdit::getSelecteRange()
{
CHARRANGE crg = {0} ;
sendMessage(EM_EXGETSEL, 0, (LPARAM)&crg);
return crg;
}
void CRichEdit::selectRange(const CHARRANGE &cr)
{
sendMessage( EM_EXSETSEL, 0, (LPARAM) &cr);
}
void CRichEdit::setTextColor(COLORREF col)
{
CHARFORMAT format;
memset(&format, 0, sizeof(CHARFORMAT));
format.cbSize = sizeof(CHARFORMAT);
format.dwMask = CFM_COLOR;
format.crTextColor = col;
sendMessage( EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &format);
}

Have a look at this article for some ideas:
Faster rich edit syntax highlighting
http://bcbjournal.org/articles/vol3/9910/Faster_rich_edit_syntax_highlighting.htm
It was written for the TRichEdit control in C++Builder, but the majority of the tips in it use straight Win32 API calls, and the few places that use VCL idioms can be easily adapted into Win32 equivilents.
Update: Try removing EM_LINEFROMCHAR from your loop. offset + pos is already an absolute character position within the RichEdit, there should be no need to adjust it on each loop iteration. If you really want to take line indexes into account then you should be looping through the lines one row at a time parsing each row individually, not parsing the entire content as a single string. Try something more like this instead:
void parse(WIN::CRichEdit &ed_source, bool curseline)
{
int startLine, endLine, offset;
const char* delimiters = " \n\r(){};";
char *tok, *start;
CStringA s;
CWnd api;
if (curseline)
{
startLine = ed_source.getRow() - 1;
endLine = startLine + 1;
}
else
{
startLine = 0;
endLine = ed_source.sendMessage(EM_GETLINECOUNT, 0, 0);
}
CHARRANGE cr = ed_source.getSelecteRange();
int eventMask = ed_source.SendMessage(EM_SETEVENTMASK, 0, 0);
ed_source.SendMessage(WM_SETREDRAW, FALSE, 0);
for (int line = startLine; line < endLine; ++line)
{
CString text;
ed_source.getLine(line, text);
s = text;
start = s.c_str();
if (!start) continue;
offset = ed_source.sendMessage(EM_LINEINDEX, line, 0);
tok = strtok(start, delimiters);
while (tok)
{
CHARRANGE range;
range.cpMin = offset + (int)(tok - start);
range.cpMax = range.cpMin + strlen(tok);
ed_source.selectRange(range);
if (isReserved(tok))
{
ed_source.setTextStyle(true, false);
ed_source.setTextColor(keyboardColor);
}
else if (isType(tok))
{
ed_source.setTextStyle(false, false);
ed_source.setTextColor(typeColor);
}
else
{
ed_source.setTextStyle(false, true);
ed_source.setTextColor(textColor);
}
tok = strtok(0, delimiters);
}
}
ed_source.SendMessage(WM_SETREDRAW, TRUE, 0);
ed_source.Invalidate(); // whatever your wrapper does to call ::InvalidateRect()
ed_source.SendMessage(EM_SETEVENTMASK, 0, eventMask);
ed_source.selectRange(cr);
}
With that said, instead of using getLine() and strtok() to parse text, you might consider using EM_FINDWORDBREAK to locate words and EM_EXSETSEL/EM_GETSELTEXT to retreive the characters of each word. That way, you are using less memory and letting the RichEdit do more of the searching for you. You can use EM_SETWORDBREAKPROC/EX if you want to customize the word delimiters searched for.

Related

Simple text file formatter crashes under Linux, but fine in Windows

I've made a simple .acf file to .json file formatter. But for some reason it runs correctly under Windows with GCC using msys2 - But after executing a string insert or replace - it segmentation faults every time.
What it does is convert the below file into a json compatible format. It appends commas after each entry, applies attribute set symbol and puts braces around it.
Save as test.acf:
"AppState"
{
"appid" "730"
"Universe" "1"
"name" "Counter-Strike: Global Offensive"
"StateFlags" "4"
"installdir" "Counter-Strike Global Offensive"
"LastUpdated" "1462547468"
"UpdateResult" "0"
"SizeOnDisk" "14990577143"
"buildid" "1110931"
"LastOwner" "76561198013962068"
"BytesToDownload" "8768"
"BytesDownloaded" "8768"
"AutoUpdateBehavior" "1"
"AllowOtherDownloadsWhileRunning" "0"
"UserConfig"
{
"Language" "english"
}
"MountedDepots"
{
"731" "205709710082221598"
"734" "5169984513691014102"
}
}
Minimal main code with defects triple slashed:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
file.open("test.acf");
std::string data((std::istreambuf_iterator<char>(file)), (std::istreambuf_iterator<char>()));
int indexQuote = 0;
int index[4];
int insertCommaNext = -1;
string delims = "\"{}"; // It skips between braces and quotes only
std::size_t found = data.find_first_of(delims);
while(found != std::string::npos)
{
int inc = 1; // 0-4 depending on the quote - 0"key1" 2"value3" 4{
char c = data.at(found);
if (c != '"') {
if (c == '}')
insertCommaNext = found + 1; // Record index to insert comma after (following closing brace)
else if (c == '{') {
///data.insert(index[1] + 1, ":");
///inc++;
}
indexQuote = 0;
} else {
if (insertCommaNext != -1) {
///data.insert(insertCommaNext, ",");
///inc++;
insertCommaNext = -1;
}
index[indexQuote] = found;
if (indexQuote == 2) { // Join 'key: value' by placing the comma
///data.replace(index[1] + 1, 1, ":");
} else if (indexQuote == 4) { // Add comma after each key/value entry
indexQuote = 0;
///data.insert(index[3] + 1, ",");
///inc++;
}
indexQuote++;
}
found = data.find_first_of(delims, found + inc);
}
data = "{" + data + "}";
}
If you uncomment any of the triple slashed /// lines - containing an insert/replace, it will crash.
I'm certian the code quality is not great, there's probably better ways to achieve this. Cheers.
The problem is that indexQuote gets higher than 3, so index[indexQuote] = found; goes out of bounds. You have the case below that resets indexQuote to 0, you have to do that before you try to call index[indexQuote].
For reference, I debugged this by adding prints everywhere and printing all the variables until I found where it crashed.

How to save specific part of a TRichEdit text RTF (c++ codegear)

I'm creating a search features in an existing c++ CodeGear project.
When you double-click a word, the background of all occurrences of the word is paint in green like in notepad++.
Before color is applied, I'm saving the original TRichEDit text in a TMemoryStream to be able to get the original text back. I reset the color back to normal on click event in the TRichEdit.
I would like to know if there is a way to save each occurrence of the search word in a TMemoryStream or maybe by using a Message like EM_STREAMOUT?
Right now everything works fine, but when the TRichEdit text is too big, it takes forever to reload the big memo of all the text. I think it would be better to only remember the color of the word that changed rather then reload all the text.
I'm really a beginner in programming, any help is appreciate. Tell me if it's not clear enough.
Here is my code that is working and putting background color to occurrences of word:
`
void SearchInText::searchWordInText(TRichEdit* reTextToSearch, AnsiString strWordToFind)
{
lstOccurrences->Clear(); //reset lst
strTextToParse = AnsiReplaceText(strTextToParse, "\r\n", "\n");
int nPrevTagPos = 0;
int nTagPos = strTextToParse.AnsiPos(strWordToFind);
while (nTagPos != 0)
{
int nPosMin = nPrevTagPos + nTagPos - 1;
//List of all the occurrence in the TRichEdit with their position in the text
//It's not a list of int, but it POINT to adresses of INT so it's the same result =)
lstOccurrences->Add((TObject*) nPosMin);
//Change color of background when there is an occurrence
changeBgColor(reTextToSearch, strWordToFind, nPosMin +1, 155, 255, 155); //lime
bColorWasApplied = true;
nPrevTagPos = nPosMin + strWordToFind.Length();
strTextToParse = strTextToParse.SubString(nTagPos + strWordToFind.Length(), strTextToParse.Length());
nTagPos = strTextToParse.AnsiPos(strWordToFind);
}
}
`
Try something like this:
#include <vector>
struct WordOccurrence
{
CHARRANGE Range;
CHARFORMAT2 OriginalFormat;
};
std::vector<WordOccurrence> WordOccurrences;
void TMyForm::HighlightWords(const String &WordToFind)
{
// disable the RichEdit's notification messages
int OriginalEventMask = RichEdit1->Perform(EM_SETEVENTMASK, 0, 0);
// disable the RichEdit's painting
RichEdit1->Perform(WM_SETREDRAW, FALSE, 0);
// save the RichEdit's current selection
CHARRANGE OriginalSelection;
RichEdit1->Perform(EM_EXGETSEL, 0, (LPARAM)&OriginalSelection);
// assign values to use while searching
int WordLen = WordToFind.Length();
int TextLen = RichEdit1->GetTextLen();
TSearchTypes SearchTypes = TSearchTypes() << stWholeWord << stMatchCase;
// find the first occurrence of the word
int StartPos = RichEdit1->FindText(WordToFind, 0, TextLen, SearchTypes);
while (StartPos != -1)
{
WordOccurrence Occurrence;
Occurrence.Range.cpMin = StartPos;
Occurrence.Range.cpMax = StartPos + WordLen;
// select the word
RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&Occurrence.Range);
// get the word's current formatting
Occurrence.OriginalFormat.cbSize = sizeof(CHARFORMAT2);
RichEdit1->Perform(EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&Occurrence.OriginalFormat);
// save it for later
WordOccurrences.push_back(Occurrence);
// set the word's new formatting
CHARFORMAT2 NewFormat = Occurrence.OriginalFormat;
NewFormat.dwMask |= (CFM_COLOR | CFM_BACKCOLOR);
NewFormat.crTextColor = ...;
newFormat.crBackColor = ...;
RichEdit1->Perform(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&NewFormat);
// find the next occurrence of the word
StartPos = RichEdit1->FindText(WordToFind, Occurrence.Range.cpMax, TextLen - Occurence.Range.cpMax, SearchTypes);
}
// restore the RichEdit's original selection
RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&OriginalSelection);
// re-enable the RichEdit's painting
RichEdit1->Perform(WM_SETREDRAW, TRUE, 0);
RichEdit1->Invalidate();
// re-enable the RichEdit's notification messages
RichEdit1->Perform(EM_SETEVENTMASK, 0, OriginalEventMask);
}
void TMyForm::RestoreHighlightedWords()
{
// are there any occurrences to restore?
if (WordOccurances.empty())
return;
// disable the RichEdit's notification messages
int OriginalEventMask = RichEdit1->Perform(EM_SETEVENTMASK, 0, 0);
// disable the RichEdit's painting
RichEdit1->Perform(WM_SETREDRAW, FALSE, 0);
// save the RichEdit's current selection
CHARRANGE OriginalSelection;
RichEdit1->Perform(EM_EXGETSEL, 0, (LPARAM)&OriginalSelection);
// restore the formatting of each occurrence
for (std::vector<WordOccurrence>::iterator iter = WordOccurrences.begin();
iter != WordOccurrences.end();
++iter)
{
WordOccurrence &occurrence = *iter;
// select the word
RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&occurrence.Range);
// restore the word's original formatting
RichEdit1->Perform(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&occurrence.OriginalFormat);
}
// clear the list
WordOccurances.clear();
// restore the RichEdit's original selection
RichEdit1->Perform(EM_EXSETSEL, 0, (LPARAM)&OriginalSelection);
// re-enable the RichEdit's painting
RichEdit1->Perform(WM_SETREDRAW, TRUE, 0);
RichEdit1->Invalidate();
// re-enable the RichEdit's notification messages
RichEdit1->Perform(EM_SETEVENTMASK, 0, OriginalEventMask);
}
Ok, so I finally get it!
I add a struct in my .h
Inside it, I store:
-the position in the TRichEdit of the word found (nStart)
-the length of the word (nLength)
-the actual text and his RTF
struct sSelectedWord : public TObject
{
public:
__fastcall ~sSelectedWord(); //destructor
int nStart;
int nLength;
TMemoryStream* memoRTF;
};
Here is the code that save the RTF of my TRichEdit in my struct I just created in the .h.
void SearchInText::searchWordInText(TRichEdit* reTextToSearch, AnsiString strWordToFind)
{
lstOccurrences->Clear(); //reset lst
lstOccWithRTFMemo->Clear();
nCountOccurrence = 0;
strTextToParse = AnsiReplaceText(strTextToParse, "\r\n", "\n");
int nPrevTagPos = 0;
int nTagPos = strTextToParse.AnsiPos(strWordToFind);
while (nTagPos != 0)
{
int nPosMin = nPrevTagPos + nTagPos - 1;
//List of all the occurrence in the TRichEdit with their position in the text
//It's not a list of int, but it POINT to adresses of INT so it's the same result =)
lstOccurrences->Add((TObject*) nPosMin);
nCountOccurrence++;
//selected the word in the TRichEdit to save it with is RTF
reTextToSearch->SelStart = nPosMin;
reTextToSearch->SelLength = strWordToFind.Length();
TMemoryStream* memo = new TMemoryStream;
//important part!
rtfSaveStream(reTextToSearch,memo);
sSelectedWord* currentWord = new sSelectedWord;
currentWord->nStart = nPosMin;
currentWord->nLength = strWordToFind.Length();
currentWord->memoRTF = memo;
//Here we go, we add our new object in a list to be able to loop through it when we will want to reset the color
lstOccWithRTFMemo->Add(currentWord);
lstOccWithRTFMemo->Count;
//Change color of background when there is an occurrence
changeBgColor(reTextToSearch, strWordToFind, nPosMin +1, 155, 255, 155); //lime
bColorWasApplied = true;
nPrevTagPos = nPosMin + strWordToFind.Length();
strTextToParse = strTextToParse.SubString(nTagPos + strWordToFind.Length(), strTextToParse.Length());
nTagPos = strTextToParse.AnsiPos(strWordToFind);
}
}
The important part was done with the EM_STREAMOUT message.
void SearchInText::rtfSaveStream(TRichEdit* re, TMemoryStream* memo)
{
// Create an instance of an EDITSTREAM that will contain:
// - The detail of our callback (StreamInCallback)
// - The TMemoryStream that contains the text to paste
EDITSTREAM es = {0};
ZeroMemory(&es, sizeof(es));
es.dwCookie = (DWORD_PTR) memo;
es.dwError = 0;
es.pfnCallback = &StreamSaveInCallback ; //pointer to function callBack
//To save the selected word of the TRichEdit, use STREAMOUT
re->Perform(EM_STREAMOUT, SF_RTF | SFF_SELECTION, (LPARAM)&es);
}
DWORD CALLBACK SearchInText::StreamSaveInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
TMemoryStream *memo = (TMemoryStream*)dwCookie;
memo->Write(pbBuff, cb);
*pcb = cb;
return 0;
}
In the pbuff, you can see the word that you selected in your TRichEdit with his RTF!
Hope it will help others with the same issue! Thanks for those who suggested code =)

`fgetpos` Not Returning the Correct Position

Update: To get around the problem below, I have done
if (ftell(m_pFile) != m_strLine.size())
fseek(m_pFile, m_strLine.size(), SEEK_SET);
fpos_t position;
fgetpos(m_pFile, &position);
this then returns the correct position for my file. However, I would still like to understand why this is occurring?
I want to get the position in a text file. For most files I have been reading the first line, storing the position, doing some other stuff and returning to the position afterwards...
m_pFile = Utils::OpenFile(m_strBaseDir + "\\" + Source + "\\" + m_strFile, "r");
m_strLine = Utils::ReadLine(m_pFile);
bEOF = feof(m_pFile) != 0;
if (bEOF)
{
Utils::CompilerError(m_ErrorCallback,
(boost::format("File '%1%' is empty.") % m_strFile).str());
return false;
}
// Open.
pFileCode = Utils::OpenFile(strGenCode + "\\" + m_strFile, options.c_str());
m_strLine = Utils::Trim(m_strLine);
Utils::WriteLine(pFileCode, m_strLine);
// Store location and start passes.
unsigned int nLineCount = 1;
fpos_t position;
fgetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);
...
fsetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);
With all files provided to me the storage of the fgetpos and fsetpos works correctly. The problem is with a file that I have created which looks like
which is almost identical to the supplied files. The problem is that for the file above fgetpos(m_pFile, &position); is not returning the correct position (I am aware that the fpos_t position is implementation specific). After the first ReadLine I get a position of 58 (edited from 60) so that when I attempt to read the second line with
fsetpos(m_pFile, &position);
m_strLine = Utils::ReadLine(m_pFile);
I get
on 700
instead of
Selection: Function ADJEXCL
Why is fgetpos not returning the position of the end of the first line?
_Note. The Utils.ReadLine method is:
std::string Utils::ReadLine(FILE* file)
{
if (file == NULL)
return NULL;
char buffer[MAX_READLINE];
if (fgets(buffer, MAX_READLINE, file) != NULL)
{
if (buffer != NULL)
{
std::string str(buffer);
Utils::TrimNewLineChar(str);
return str;
}
}
std::string str(buffer);
str.clear();
return str;
}
with
void Utils::TrimNewLineChar(std::string& s)
{
if (!s.empty() && s[s.length() - 1] == '\n')
s.erase(s.length() - 1);
}
Edit. Following the debugging suggestions in the comments I have added the following code
m_pFile = Utils::OpenFile(m_strBaseDir + "\\" + Source + "\\" + m_strFile, "r");
m_strLine = Utils::ReadLine(m_pFile);
// Here m-strLine = " Logic Definition Report Chart Version: New Version 700" (64 chars).
long vv = ftell(m_pFile); // Here vv = 58!?
fpos_t pos;
vv = ftell(m_pFile);
fgetpos(m_pFile, &pos); // pos = 58.
fsetpos(m_pFile, &pos);
m_strLine = Utils::ReadLine(m_pFile);
Sorry, but your Utils functions have clearly been written by an incompetent. Some issues are just a matter of style. For trimming:
void Utils::TrimNewLineChar(std::string& s)
{
if (!s.empty() && *s.rbegin() == '\n')
s.resize(s.size() - 1); // resize, not erase
}
or in C++11
void Utils::TrimNewLineChar(std::string& s)
{
if (!s.empty() && s.back() == '\n')
s.pop_back();
}
ReadLine is even worse, replace it with:
std::string Utils::ReadLine(FILE* file)
{
std::string str;
char buffer[MAX_READLINE];
if (file != NULL && fgets(buffer, MAX_READLINE, file) != NULL)
{
// it is guaranteed that buffer != NULL, since it is an automatic array
str.assign(buffer);
Utils::TrimNewLineChar(str);
}
// copying buffer into str is useless here
return str;
}
That last str(buffer) in the original worries me especially. If fgets reaches a newline, fills the buffer, or reaches end of file, you're guaranteed to get a properly terminated string in your buffer. If some other I/O error occurs? Who knows? It might be undefined behavior.
Best not to rely on the value of buffer when fgets fails.

Output formatted text to Screen

I have a vector that stores pairs. Each pair contains a CString and a bool.
If the CString is meant to be underlined then bool is true, else it is false.
I want to output the text in the vector to the screen making sure that text is underlined in the correct places.
So far I have the following code:
void CEmergenceView::AppendText( CString msg ) {
int nBegin;
CRichEditCtrl &rec = GetRichEditCtrl();
nBegin = rec.GetTextLength();
rec.SetSel(nBegin, nBegin); // Select last character
rec.ReplaceSel(msg); // Append, move cursor to end of text
rec.SetSel(-1,0); // Remove Black selection bars
nBegin = rec.GetTextLength(); // Get New Length
rec.SetSel(nBegin,nBegin); // Cursor to End of new text
// Fix annoying "do you want to save your changes?" when program exits
GetDocument()->SetModifiedFlag(FALSE); // -Optional- (sometimes you want this)
}
int nEnd = 0;
// loop through start of text to end of text
for(int k = 0; k < groups.size(); k++) {
rEditCtrl.SetSel(nEnd, nEnd);
rEditCtrl.GetSelectionCharFormat(cf);
if(groups.at(k).second) {
if(!cf.dwEffects & !CFE_UNDERLINE) {
CRichEditView::OnCharUnderline();
}
}
else if(!groups.at(k).second) {
if(cf.dwEffects & CFE_UNDERLINE) {
CRichEditView::OnCharUnderline();
}
}
AppendText(groups.at(k).first);
nEnd = nEnd + (groups.at(k).first.GetLength());
}
However, this is not underlining at all....Can anyone tell me what I'm doing wrong?? Thanks!
I think you should implement the OnCharUnderline
Try to call yours own function instead of the default one:
You can get it from here:
void CMyRichEditView::OnCharUnderline ()
{
CHARFORMAT2 cf;
cf = GetCharFormatSelection();
if (!(cf.dwMask & CFM_UNDERLINE) || !(cf.dwEffects & CFE_UNDERLINE))
cf.dwEffects = CFE_UNDERLINE;
else
cf.dwEffects = 0;
cf.dwMask = CFM_UNDERLINE;
SetCharFormat(cf);
}

Getting word under caret - C++, wxWidgets

I am writing a text editor using the wxWidgets framework. I need to get the word under caret from the text control. Here is what I came up with.
static bool IsWordBoundary(wxString& text)
{
return (text.Cmp(wxT(" ")) == 0 ||
text.Cmp(wxT('\n')) == 0 ||
text.Cmp(wxT('\t')) == 0 ||
text.Cmp(wxT('\r')) == 0);
}
static wxString GetWordUnderCaret(wxTextCtrl* control)
{
int insertion_point = control->GetInsertionPoint();
wxTextPos last_position = control->GetLastPosition();
int start_at, ends_at = 0;
// Finding starting position:
// from the current caret position, move back each character until
// we hit a word boundary.
int caret_pos = insertion_point;
start_at = caret_pos;
while (caret_pos)
{
wxString text = control->GetRange (caret_pos - 1, caret_pos);
if (IsWordBoundary (text)) {
break;
}
start_at = --caret_pos;
}
// Finding ending position:
// from the current caret position, move forward each character until
// we hit a word boundary.
caret_pos = ends_at = insertion_point;
while (caret_pos < last_position)
{
wxString text = control->GetRange (caret_pos, caret_pos + 1);
if (IsWordBoundary (text)) {
break;
}
ends_at = ++caret_pos;
}
return (control->GetRange (start_at, ends_at));
}
This code works as expected. But I am wondering is this the best way to approach the problem? Do you see any possible fixes on the above code?
Any help would be great!
Is punctuation part of a word? It is in your code -- is that what you want?
Here is how I would do it:
wxString word_boundary_marks = " \n\t\r";
wxString text_in_control = control->GetValue();
int ends_at = text_in_control.find_first_of( word_boundary_marks, insertion_point) - 1;
int start_at = text_in_control.Mid(0,insertion_point).find_last_of(word_boundary_marks) + 1;
I haven't tested this, so there likely are one or two "off-by-one" errors and you should add checks for "not found", end of string, and any other word markers. My code should give you the basis for what you need.