[ENHANCEMENT] (Author: Ivan Radic,aka. Loreia L.) Enhance TAB/Space conversion: support UTF8 and to preserve formatting.

git-svn-id: svn://svn.tuxfamily.org/svnroot/notepadplus/repository/trunk@1060 f5eea248-9336-0410-98b8-ebc06183d4e3
This commit is contained in:
Don Ho 2013-06-18 19:44:32 +00:00
parent d39c743ff4
commit 197a28d1bd

View File

@ -1043,177 +1043,220 @@ bool Notepad_plus::matchInList(const TCHAR *fileName, const vector<generic_strin
return false; return false;
} }
void Notepad_plus::wsTabConvert(spaceTab whichWay) void Notepad_plus::wsTabConvert(spaceTab whichWay)
{ {
int tabWidth = _pEditView->execute(SCI_GETTABWIDTH); int tabWidth = _pEditView->execute(SCI_GETTABWIDTH);
int docLength = int(_pEditView->execute(SCI_GETLENGTH)) + 1; int currentPos = _pEditView->execute(SCI_GETCURRENTPOS);
if (docLength < 2) int lastLine = _pEditView->lastZeroBasedLineNumber();
return; int docLength = int(_pEditView->execute(SCI_GETLENGTH)) + 1;
int count = 0; if (docLength < 2)
int column = 0; return;
int counter = 0;
int tabStop = tabWidth - 1; // remember, counting from zero !
bool onlyLeading = false;
bool nonSpaceFound = false;
char * source = new char[docLength]; int count = 0;
if (source == NULL) int column = 0;
return; int counter = 0;
_pEditView->execute(SCI_GETTEXT, docLength, (LPARAM)source); int newCurrentPos = 0;
int tabStop = tabWidth - 1; // remember, counting from zero !
bool onlyLeading = false;
bool nonSpaceFound = false;
vector<int> bookmarks;
vector<int> folding;
if (whichWay == tab2Space) for (int i=0; i<lastLine; ++i)
{ {
// count how many tabs are there if (bookmarkPresent(i))
for (const char * ch=source; *ch; ++ch) bookmarks.push_back(i);
{
if (*ch == '\t') if ((_pEditView->execute(SCI_GETFOLDLEVEL, i) & SC_FOLDLEVELHEADERFLAG))
++count; if (_pEditView->execute(SCI_GETFOLDEXPANDED, i) == 0)
} folding.push_back(i);
if (count == 0) }
{
delete [] source; char * source = new char[docLength];
return; if (source == NULL)
} return;
} _pEditView->execute(SCI_GETTEXT, docLength, (LPARAM)source);
// allocate tabwidth-1 chars extra per tab, just to be safe
size_t newlen = docLength + count * (tabWidth - 1) + 1; if (whichWay == tab2Space)
char * destination = new char[newlen]; {
if (destination == NULL) // count how many tabs are there
{ for (const char * ch=source; *ch; ++ch)
delete [] source; {
return; if (*ch == '\t')
} ++count;
}
if (count == 0)
{
delete [] source;
return;
}
}
// allocate tabwidth-1 chars extra per tab, just to be safe
size_t newlen = docLength + count * (tabWidth - 1) + 1;
char * destination = new char[newlen];
if (destination == NULL)
{
delete [] source;
return;
}
char * dest = destination; char * dest = destination;
switch (whichWay) switch (whichWay)
{ {
case tab2Space: case tab2Space:
{ {
// rip through each line in the file // rip through each line of the file
for (const char * ch = source; *ch; ++ch) for (int i = 0; source[i] != '\0'; ++i)
{ {
if (*ch == '\t') if (source[i] == '\t')
{ {
size_t insertTabs = tabWidth - (column % tabWidth); size_t insertTabs = tabWidth - (column % tabWidth);
for (size_t i = 0; i<insertTabs; ++i) for (size_t j = 0; j<insertTabs; ++j)
{
*dest++ = ' ';
}
column += insertTabs;
}
else
{
*dest++ = *ch;
if ((*ch == '\n') || (*ch == '\r'))
column = 0;
else
++column;
}
}
*dest = '\0';
break;
}
case space2TabLeading:
{
onlyLeading = true;
}
case space2TabAll:
{
bool nextChar = false;
for (const char * ch=source; *ch; ++ch)
{
if (nonSpaceFound == false)
{
while (*(ch + counter) == ' ')
{
if ((column + counter) == tabStop)
{
tabStop += tabWidth;
if (counter >= 1) // counter is counted from 0, so counter >= max -1
{
*dest++ = '\t';
ch += counter;
column += counter + 1;
counter = 0;
nextChar = true;
break;
}
else if (*(ch+1) == ' ' || *(ch+1) == '\t') // if followed by space or TAB, convert even a single space to TAB
{
*dest++ = '\t';
ch++;
column += 1;
counter = 0;
}
else // single space, don't convert it to TAB
{
*dest++ = *ch;
column += 1;
counter = 0;
nextChar = true;
break;
}
}
else
++counter;
}
if (nextChar == true)
{
nextChar = false;
continue;
}
if (*ch == ' ' && *(ch + counter) == '\t') // spaces "absorbed" by a TAB on the right
{ {
*dest++ = '\t'; *dest++ = ' ';
ch += counter; if (i <= currentPos)
column = tabStop + 1; ++newCurrentPos;
tabStop += tabWidth; }
counter = 0; column += insertTabs;
}
else
{
*dest++ = source[i];
if (i <= currentPos)
++newCurrentPos;
if ((source[i] == '\n') || (source[i] == '\r'))
column = 0;
else if ((source[i] & 0xC0) != 0x80) // UTF_8 support: count only bytes that don't start with 10......
++column;
}
}
*dest = '\0';
break;
}
case space2TabLeading:
{
onlyLeading = true;
}
case space2TabAll:
{
bool nextChar = false;
for (int i=0; source[i] != '\0'; ++i)
{
if (nonSpaceFound == false)
{
while (source[i + counter] == ' ')
{
if ((column + counter) == tabStop)
{
tabStop += tabWidth;
if (counter >= 1) // counter is counted from 0, so counter >= max-1
{
*dest++ = '\t';
i += counter;
column += counter + 1;
counter = 0;
nextChar = true;
if (i <= currentPos)
++newCurrentPos;
break;
}
else if (source[i+1] == ' ' || source[i+1] == '\t') // if followed by space or TAB, convert even a single space to TAB
{
*dest++ = '\t';
i++;
column += 1;
counter = 0;
if (i <= currentPos)
++newCurrentPos;
}
else // single space, don't convert it to TAB
{
*dest++ = source[i];
column += 1;
counter = 0;
nextChar = true;
if (i <= currentPos)
++newCurrentPos;
break;
}
}
else
++counter;
}
if (nextChar == true)
{
nextChar = false;
continue; continue;
} }
}
if (source[i] == ' ' && source[i + counter] == '\t') // spaces "absorbed" by a TAB on the right
{
*dest++ = '\t';
i += counter;
column = tabStop + 1;
tabStop += tabWidth;
counter = 0;
if (i <= currentPos)
++newCurrentPos;
continue;
}
}
if (onlyLeading == true && nonSpaceFound == false) if (onlyLeading == true && nonSpaceFound == false)
nonSpaceFound = true; nonSpaceFound = true;
if (*ch == '\n' || *ch == '\r') if (source[i] == '\n' || source[i] == '\r')
{
*dest++ = *ch;
column = 0;
tabStop = tabWidth - 1;
nonSpaceFound = false;
}
else if (*ch == '\t')
{ {
*dest++ = *ch; *dest++ = source[i];
column = 0;
tabStop = tabWidth - 1;
nonSpaceFound = false;
}
else if (source[i] == '\t')
{
*dest++ = source[i];
column = tabStop + 1; column = tabStop + 1;
tabStop += tabWidth; tabStop += tabWidth;
counter = 0; counter = 0;
} }
else else
{ {
*dest++ = *ch; *dest++ = source[i];
++column; counter = 0;
counter = 0; if ((source[i] & 0xC0) != 0x80) // UTF_8 support: count only bytes that don't start with 10......
{
++column;
if (column > 0 && column % tabWidth == 0) if (column > 0 && column % tabWidth == 0)
tabStop += tabWidth; tabStop += tabWidth;
}
} }
}
*dest = '\0'; if (i <= currentPos)
++newCurrentPos;
}
*dest = '\0';
break; break;
} }
} }
_pEditView->execute(SCI_BEGINUNDOACTION); _pEditView->execute(SCI_BEGINUNDOACTION);
_pEditView->execute(SCI_SETTEXT, 0, (LPARAM)destination); _pEditView->execute(SCI_SETTEXT, 0, (LPARAM)destination);
_pEditView->execute(SCI_ENDUNDOACTION); _pEditView->execute(SCI_GOTOPOS, newCurrentPos);
// clean up for (size_t i=0; i<bookmarks.size(); ++i)
delete [] source; _pEditView->execute(SCI_MARKERADD, bookmarks[i], MARK_BOOKMARK);
delete [] destination;
for (size_t i=0; i<folding.size(); ++i)
_pEditView->fold(folding[i], false);
_pEditView->execute(SCI_ENDUNDOACTION);
// clean up
delete [] source;
delete [] destination;
} }
void Notepad_plus::doTrim(trimOp whichPart) void Notepad_plus::doTrim(trimOp whichPart)