[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:
parent
d39c743ff4
commit
197a28d1bd
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user