View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0002294 | Wishes | Editor | public | 2013-02-08 23:57 | 2017-11-11 22:36 |
Reporter | MikeMirzayanov | Assigned To | DrKnS | ||
Priority | normal | Severity | minor | Reproducibility | N/A |
Status | assigned | Resolution | open | ||
Product Version | 3.0 | ||||
Summary | 0002294: Идея и реализация PreserveStyle в SearchReplace (есть патч) | ||||
Description | Предлагаю добавить режим «умной» замены в поиск-замену в редакторе. Прилагаю полный diff с реализацией. Вроде только не поправил документацию и не протащил PreserveStyle в EditorOptions (не уверен, что это надо). Смогу сделать и то и другое, если есть заинтересованность в использовании моего патча. Идея. Редактируя исходные тексты (и не только), часто надо делать замену с сохранением стиля написания (что-то вроде рефакторинга «rename»). Простой пример. Во фразе «A number of a bytes» надо заменить «the» на «a». В идеале одной заменой надо получить «The number of the bytes». Именно с таким регистром символов. Пример сложнее. Пусть есть следующий гипотетический код (написан просто для примера): public class UserName { public static final int MAX_USER_NAME_SIZE = 100; /* Я так не называю поля в Java, странное имя - для полноты примера :) */ private String m_userNameText = null; public void setUserNameText(String userNameText) { m_userNameText = userNameText; } public String getUserNameText() { if (m_userNameText == null) { return ConfigurationProperties.get("default_user_name") || ConfigurationProperties.get("default.user.name") || ConfigurationProperties.get("default-user-name"); } return m_userNameText; } } В нем хочется заменить «UserName» на «PersonalLoginId» и получить такое (обратите внимание на регистры и стилизацию всех упоминаний PersonalLoginId): public class PersonalLoginId { public static final int MAX_PERSONAL_LOGIN_ID_SIZE = 100; /* Я так не называю поля в Java, странное имя - для полноты примера :) */ private String m_personalLoginIdText = null; public void setPersonalLoginIdText(String personalLoginIdText) { m_personalLoginIdText = personalLoginIdText; } public String getPersonalLoginIdText() { if (m_personalLoginIdText == null) { return ConfigurationProperties.get("default_personal_login_id") || ConfigurationProperties.get("default.personal.login.id") || ConfigurationProperties.get("default-personal-login-id"); } return m_personalLoginIdText; } } Т.е. при замене угадывается стиль того что заменяется и заменяемый текст под этот стиль преобразуется. Оба примера работают в одну замену в пропатченном мной FAR-е. | ||||
Additional Information | Если надо что-то доработать/исправить/пояснить, сделаю всё что надо. Может добавить аналогичную тему в форум в Предложения и идеи, послушать что люди скажут? | ||||
Tags | No tags attached. | ||||
Build | |||||
|
PreserveStyle.diff (26,005 bytes)
Index: unicode_far/stddlg.hpp =================================================================== --- unicode_far/stddlg.hpp (revision 9550) +++ unicode_far/stddlg.hpp (working copy) @@ -82,6 +82,9 @@ Regexp ����� �� ���������, ������� �� ������� ���� "Regular expressions" + Regexp + ����� �� ���������, ������� �� ������� ���� "Preserve style" + HelpTopic �� ��� �����. ���� nullptr ��� ����� ������ - ���� ����� �� ���������. @@ -104,6 +107,7 @@ bool* WholeWords, bool* Reverse, bool* Regexp, + bool* PreserveStyle, const wchar_t *HelpTopic=nullptr, bool HideAll=false ); Index: unicode_far/editor.hpp =================================================================== --- unicode_far/editor.hpp (revision 9550) +++ unicode_far/editor.hpp (working copy) @@ -215,7 +215,7 @@ /* $ 30.07.2000 KM ���� ��������� �� ������ "Whole words" */ - bool LastSearchCase,LastSearchWholeWords,LastSearchReverse, LastSearchRegexp; + bool LastSearchCase,LastSearchWholeWords,LastSearchReverse,LastSearchRegexp,LastSearchPreserveStyle; uintptr_t m_codepage; //BUGBUG Index: unicode_far/preservestyle.hpp =================================================================== --- unicode_far/preservestyle.hpp (revision 0) +++ unicode_far/preservestyle.hpp (working copy) @@ -0,0 +1,3 @@ +#pragma once + +bool PreserveStyleReplaceString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr, int& CurPos, int Position, int Case, int WholeWords, const wchar_t *WordDiv, int Reverse, int& SearchLength); Index: unicode_far/strmix.cpp =================================================================== --- unicode_far/strmix.cpp (revision 9550) +++ unicode_far/strmix.cpp (working copy) @@ -39,6 +39,7 @@ #include "language.hpp" #include "config.hpp" #include "pathmix.hpp" +#include "preservestyle.hpp" string &FormatNumber(const wchar_t *Src, string &strDest, int NumDigits) { @@ -1381,13 +1382,16 @@ return (UuidFromString((unsigned short*)Value,&Guid)==RPC_S_OK)?true:false; } -bool SearchString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr,int& CurPos, int Position,int Case,int WholeWords,int Reverse,int Regexp, int *SearchLength,const wchar_t* WordDiv) +bool SearchString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr,int& CurPos, int Position,int Case,int WholeWords,int Reverse,int Regexp,int PreserveStyle, int *SearchLength,const wchar_t* WordDiv) { *SearchLength = 0; if (!WordDiv) WordDiv=Global->Opt->strWordDiv; + if (!Regexp && PreserveStyle && PreserveStyleReplaceString(Source, StrSize, Str, ReplaceStr, CurPos, Position, Case, WholeWords, WordDiv, Reverse, *SearchLength)) + return true; + if (Reverse) { Position--; @@ -1467,6 +1471,17 @@ if (!Str[J]) { CurPos=I; + + // � ����� PreserveStyle: ���� �� �������� ������ ������ c ����� PreserveStyleReplaceString, + // �� ��� � ������� ������� ������ ����. + if (PreserveStyle && !ReplaceStr.IsEmpty() && IsAlpha(ReplaceStr[0]) && IsAlpha(Source[I])) + { + if (IsUpper(Source[I])) + ReplaceStr.GetBuffer()[0] = Upper(ReplaceStr[0]); + if (IsLower(Source[I])) + ReplaceStr.GetBuffer()[0] = Lower(ReplaceStr[0]); + } + return true; } Index: unicode_far/far.vc11.vcxproj.filters =================================================================== --- unicode_far/far.vc11.vcxproj.filters (revision 9550) +++ unicode_far/far.vc11.vcxproj.filters (working copy) @@ -326,6 +326,9 @@ <ClCompile Include="poscache.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="preservestyle.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="print.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -853,6 +856,9 @@ <ClInclude Include="poscache.hpp"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="preservestyle.hpp"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="print.hpp"> <Filter>Header Files</Filter> </ClInclude> Index: unicode_far/makefile_gcc =================================================================== --- unicode_far/makefile_gcc (revision 9550) +++ unicode_far/makefile_gcc (working copy) @@ -108,6 +108,7 @@ plugins.cpp \ plugsettings.cpp \ poscache.cpp \ + preservestyle.cpp \ print.cpp \ privilege.cpp \ processname.cpp \ Index: unicode_far/help.cpp =================================================================== --- unicode_far/help.cpp (revision 9550) +++ unicode_far/help.cpp (working copy) @@ -1339,7 +1339,7 @@ string strTempStr; //int RetCode = GetString(MSG(MHelpSearchTitle),MSG(MHelpSearchingFor),L"HelpSearch",strLastSearchStr,strLastSearchStr0); - int RetCode = GetSearchReplaceString(false, MSG(MHelpSearchTitle), MSG(MHelpSearchingFor), strLastSearchStr0, strTempStr, L"HelpSearch", L"", &Case, &WholeWords, nullptr, &Regexp,nullptr,true); + int RetCode = GetSearchReplaceString(false, MSG(MHelpSearchTitle), MSG(MHelpSearchingFor), strLastSearchStr0, strTempStr, L"HelpSearch", L"", &Case, &WholeWords, nullptr, &Regexp, nullptr, nullptr, true); if (RetCode <= 0) return TRUE; @@ -1908,7 +1908,7 @@ string ReplaceStr; int CurPos=0; int SearchLength; - bool Result=SearchString(strReadStr,(int)strReadStr.GetLength(),strLastSearchStr,ReplaceStr,CurPos,0,LastSearchCase,LastSearchWholeWords,false,LastSearchRegexp,&SearchLength); + bool Result=SearchString(strReadStr,(int)strReadStr.GetLength(),strLastSearchStr,ReplaceStr,CurPos,0,LastSearchCase,LastSearchWholeWords,false,false,LastSearchRegexp,&SearchLength); if (Result) { Index: unicode_far/makefile_vc =================================================================== --- unicode_far/makefile_vc (revision 9550) +++ unicode_far/makefile_vc (working copy) @@ -200,6 +200,7 @@ "$(INTDIR)\plugins.obj" \ "$(INTDIR)\plugsettings.obj" \ "$(INTDIR)\poscache.obj" \ + "$(INTDIR)\preservestyle.obj" \ "$(INTDIR)\print.obj" \ "$(INTDIR)\privilege.obj" \ "$(INTDIR)\processname.obj" \ Index: unicode_far/strmix.hpp =================================================================== --- unicode_far/strmix.hpp (revision 9550) +++ unicode_far/strmix.hpp (working copy) @@ -123,4 +123,4 @@ string GuidToStr(const GUID& Guid); bool StrToGuid(const wchar_t* Value,GUID& Guid); -bool SearchString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr,int& CurPos, int Position,int Case,int WholeWords,int Reverse,int Regexp, int *SearchLength,const wchar_t* WordDiv=nullptr); +bool SearchString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr,int& CurPos, int Position,int Case,int WholeWords,int Reverse,int Regexp,int PreserveStyle, int *SearchLength,const wchar_t* WordDiv=nullptr); Index: unicode_far/farlang.templ.m4 =================================================================== --- unicode_far/farlang.templ.m4 (revision 9550) +++ unicode_far/farlang.templ.m4 (working copy) @@ -4988,6 +4988,16 @@ "Expresiones re&gulares" "Re&gulárne výrazy" +MEditSearchPreserveStyle +"&Сохранять стиль" +"&Preserve style" +upd:"&Zachovat styl" +upd:"&Preserve Stil" +upd:"&Megőrzése stílus" +upd:"&Zachowaj styl" +upd:"&Preservar estilo" +upd:"&Zachovať štýl" + MEditSearchSearch "Искать" "Search" Index: unicode_far/far.vcxproj =================================================================== --- unicode_far/far.vcxproj (revision 9550) +++ unicode_far/far.vcxproj (working copy) @@ -568,6 +568,7 @@ <ClCompile Include="plugins.cpp" /> <ClCompile Include="plugsettings.cpp" /> <ClCompile Include="poscache.cpp" /> + <ClCompile Include="preservestyle.cpp" /> <ClCompile Include="print.cpp" /> <ClCompile Include="privilege.cpp" /> <ClCompile Include="processname.cpp" /> Index: unicode_far/edit.cpp =================================================================== --- unicode_far/edit.cpp (revision 9550) +++ unicode_far/edit.cpp (working copy) @@ -2097,7 +2097,7 @@ ������� ������ �������� ��-�� ������������ ��������� ������ ��� ����. */ -int Edit::Search(const string& Str,string& ReplaceStr,int Position,int Case,int WholeWords,int Reverse,int Regexp, int *SearchLength) +int Edit::Search(const string& Str,string& ReplaceStr,int Position,int Case,int WholeWords,int Reverse,int Regexp,int PreserveStyle, int *SearchLength) { #if 0 *SearchLength = 0; @@ -2226,7 +2226,7 @@ return FALSE; #else - return SearchString(this->Str,this->StrSize,Str,ReplaceStr,CurPos,Position,Case,WholeWords,Reverse,Regexp,SearchLength,WordDiv()); + return SearchString(this->Str,this->StrSize,Str,ReplaceStr,CurPos,Position,Case,WholeWords,Reverse,Regexp,PreserveStyle,SearchLength,WordDiv()); #endif } Index: unicode_far/far.vc11.vcxproj =================================================================== --- unicode_far/far.vc11.vcxproj (revision 9550) +++ unicode_far/far.vc11.vcxproj (working copy) @@ -425,6 +425,7 @@ <ClCompile Include="plugins.cpp" /> <ClCompile Include="plugsettings.cpp" /> <ClCompile Include="poscache.cpp" /> + <ClCompile Include="preservestyle.cpp" /> <ClCompile Include="print.cpp" /> <ClCompile Include="privilege.cpp" /> <ClCompile Include="processname.cpp" /> @@ -816,6 +817,7 @@ <ClInclude Include="plugins.hpp" /> <ClInclude Include="plugsettings.hpp" /> <ClInclude Include="poscache.hpp" /> + <ClInclude Include="preservestyle.hpp" /> <ClInclude Include="print.hpp" /> <ClInclude Include="privilege.hpp" /> <ClInclude Include="processname.hpp" /> Index: unicode_far/contrib/codeblocks/Far.cbp =================================================================== --- unicode_far/contrib/codeblocks/Far.cbp (revision 9550) +++ unicode_far/contrib/codeblocks/Far.cbp (working copy) @@ -328,6 +328,8 @@ <Unit filename="plugins.hpp" /> <Unit filename="poscache.cpp" /> <Unit filename="poscache.hpp" /> + <Unit filename="preservestyle.cpp" /> + <Unit filename="preservestyle.hpp" /> <Unit filename="print.cpp" /> <Unit filename="print.hpp" /> <Unit filename="processname.cpp" /> Index: unicode_far/stddlg.cpp =================================================================== --- unicode_far/stddlg.cpp (revision 9550) +++ unicode_far/stddlg.cpp (working copy) @@ -59,6 +59,7 @@ bool* pWholeWords, bool* pReverse, bool* pRegexp, + bool* pPreserveStyle, const wchar_t *HelpTopic, bool HideAll) { @@ -81,6 +82,7 @@ bool WholeWords=pWholeWords?*pWholeWords:false; bool Reverse=pReverse?*pReverse:false; bool Regexp=pRegexp?*pRegexp:false; + bool PreserveStyle=pPreserveStyle?*pPreserveStyle:false; if (IsReplaceMode) @@ -96,7 +98,7 @@ 05 | | 06 +--------------------------------------------------------------------+ 07 | [ ] Case sensitive [ ] Regular expressions | - 08 | [ ] Whole words | + 08 | [ ] Whole words [ ] Preserve style | 09 | [ ] Reverse search | 10 +--------------------------------------------------------------------+ 11 | [ Replace ] [ Cancel ] | @@ -115,6 +117,7 @@ {DI_CHECKBOX,5,8,0,8,WholeWords,nullptr,nullptr,0,MSG(MEditSearchWholeWords)}, {DI_CHECKBOX,5,9,0,9,Reverse,nullptr,nullptr,0,MSG(MEditSearchReverse)}, {DI_CHECKBOX,40,7,0,7,Regexp,nullptr,nullptr,0,MSG(MEditSearchRegexp)}, + {DI_CHECKBOX,40,8,0,8,PreserveStyle,nullptr,nullptr,0,MSG(MEditSearchPreserveStyle)}, {DI_TEXT,-1,10,0,10,0,nullptr,nullptr,DIF_SEPARATOR,L""}, {DI_BUTTON,0,11,0,11,0,nullptr,nullptr,DIF_DEFAULTBUTTON|DIF_CENTERGROUP,MSG(MEditReplaceReplace)}, {DI_BUTTON,0,11,0,11,0,nullptr,nullptr,DIF_CENTERGROUP,MSG(MEditSearchCancel)}, @@ -129,6 +132,8 @@ ReplaceDlg[8].Flags |= DIF_DISABLE; // DIF_HIDDEN ?? if (!pRegexp) ReplaceDlg[9].Flags |= DIF_DISABLE; // DIF_HIDDEN ?? + if (!pPreserveStyle) + ReplaceDlg[10].Flags |= DIF_DISABLE; // DIF_HIDDEN ?? Dialog Dlg(ReplaceDlg,ARRAYSIZE(ReplaceDlgData)); Dlg.SetPosition(-1,-1,76,14); @@ -138,7 +143,7 @@ Dlg.Process(); - if(Dlg.GetExitCode() == 11) + if(Dlg.GetExitCode() == 12) { Result = 1; SearchStr = ReplaceDlg[2].strData; @@ -147,6 +152,7 @@ WholeWords=ReplaceDlg[7].Selected == BSTATE_CHECKED; Reverse=ReplaceDlg[8].Selected == BSTATE_CHECKED; Regexp=ReplaceDlg[9].Selected == BSTATE_CHECKED; + PreserveStyle=ReplaceDlg[10].Selected == BSTATE_CHECKED; } } else @@ -223,6 +229,8 @@ *pReverse=Reverse; if (pRegexp) *pRegexp=Regexp; + if (pPreserveStyle) + *pPreserveStyle=PreserveStyle; return Result; } Index: unicode_far/editor.cpp =================================================================== --- unicode_far/editor.cpp (revision 9550) +++ unicode_far/editor.cpp (working copy) @@ -88,6 +88,7 @@ LastSearchWholeWords(Global->GlobalSearchWholeWords), LastSearchReverse(Global->GlobalSearchReverse), LastSearchRegexp(Global->Opt->EdOpt.SearchRegexp), + LastSearchPreserveStyle(false), m_codepage(CP_DEFAULT), StartLine(-1), StartChar(-1), @@ -3681,7 +3682,7 @@ string strMsgStr; const wchar_t *TextHistoryName=L"SearchText",*ReplaceHistoryName=L"ReplaceText"; int CurPos, NewNumLine; - bool Case,WholeWords,ReverseSearch,Regexp,Match,UserBreak; + bool Case,WholeWords,ReverseSearch,Regexp,PreserveStyle,Match,UserBreak; AutoUndoBlock UndoBlock(this); if (Next && strLastSearchStr.IsEmpty()) @@ -3692,6 +3693,7 @@ Case=LastSearchCase; WholeWords=LastSearchWholeWords; ReverseSearch=LastSearchReverse; + PreserveStyle=LastSearchPreserveStyle; Regexp=LastSearchRegexp; bool FindAllReferences = false; @@ -3710,7 +3712,7 @@ } } - int DlgResult = GetSearchReplaceString(ReplaceMode, nullptr, nullptr, strSearchStr, strReplaceStr, TextHistoryName, ReplaceHistoryName, &Case, &WholeWords, &ReverseSearch, &Regexp, L"EditorSearch"); + int DlgResult = GetSearchReplaceString(ReplaceMode, nullptr, nullptr, strSearchStr, strReplaceStr, TextHistoryName, ReplaceHistoryName, &Case, &WholeWords, &ReverseSearch, &Regexp, &PreserveStyle, L"EditorSearch"); if (!DlgResult) { return FALSE; @@ -3727,6 +3729,7 @@ LastSearchWholeWords=WholeWords; LastSearchReverse=ReverseSearch; LastSearchRegexp=Regexp; + LastSearchPreserveStyle=PreserveStyle; if(FindAllReferences) { @@ -3808,7 +3811,7 @@ int SearchLength=0; string strReplaceStrCurrent(ReplaceMode?strReplaceStr:L""); - if (CurPtr->Search(strSearchStr,strReplaceStrCurrent,CurPos,Case,WholeWords,ReverseSearch,Regexp,&SearchLength)) + if (CurPtr->Search(strSearchStr,strReplaceStrCurrent,CurPos,Case,WholeWords,ReverseSearch,Regexp,PreserveStyle,&SearchLength)) { Match=1; Edit *FoundPtr = CurPtr; Index: unicode_far/mkdep.list =================================================================== --- unicode_far/mkdep.list (revision 9550) +++ unicode_far/mkdep.list (working copy) @@ -209,6 +209,8 @@ plugsettings.hpp poscache.cpp poscache.hpp +preservestyle.cpp +preservestyle.hpp print.cpp print.hpp privilege.cpp Index: unicode_far/preservestyle.cpp =================================================================== --- unicode_far/preservestyle.cpp (revision 0) +++ unicode_far/preservestyle.cpp (working copy) @@ -0,0 +1,326 @@ +#include "headers.hpp" +#pragma hdrstop + +#include "preservestyle.hpp" + +static const wchar_t *PreserveStyleTokenSeparators = L"_-."; + +enum PreserveStyleType +{ + UPPERCASE_ALL, + LOWERCASE_ALL, + UPPERCASE_FIRST, + UNKNOWN +}; + +struct PreserveStyleToken +{ + string Token; + wchar_t PrependChar; + int TypeMask; +}; + +static inline bool IsPreserveStyleTokenSeparator(wchar_t C) +{ + return wcschr(PreserveStyleTokenSeparators, C) != 0; +} + +static int GetPeserveCaseStyleMask(const string& strStr) +{ + int Result = 15; + + for (size_t I = 0; I < strStr.GetLength(); I++) + { + int Upper = IsUpper(strStr[I]); + int Lower = IsLower(strStr[I]); + if (!Upper) + Result &= ~(1 << UPPERCASE_ALL); + if (!Lower) + Result &= ~(1 << LOWERCASE_ALL); + if ((!Upper || !IsAlpha(strStr[I])) && I == 0) + Result &= ~(1 << UPPERCASE_FIRST); + if (!Lower && I > 0) + Result &= ~(1 << UPPERCASE_FIRST); + } + + return Result; +} + +static std::vector<PreserveStyleToken> InternalPreserveStyleTokenize(const string& strStr, int From, int Length) +{ + std::vector<PreserveStyleToken> Result; + + wchar_t Sep = 0; + std::vector<bool> Seps(Length, false); + for (int I = From+1; I+1 < From+Length; I++) + if (IsPreserveStyleTokenSeparator(strStr[I]) + && !IsPreserveStyleTokenSeparator(strStr[I-1]) + && !IsPreserveStyleTokenSeparator(strStr[I+1])) + { + if (Sep != 0 && strStr[I] != Sep) + { + PreserveStyleToken T; + T.Token = strStr.SubStr(From, Length); + T.PrependChar = 0; + T.TypeMask = 1 << UNKNOWN; + Result.push_back(T); + return Result; + } + + Seps[I-From] = true; + } + + int L = From; + for (int I = From+1; I < From+Length; I++) + { + if (Seps[I-From]) + { + PreserveStyleToken T; + T.Token = strStr.SubStr(L, I-L); + T.PrependChar = 0; + if (L-1-From >= 0 && Seps[L-1-From]) + T.PrependChar = strStr[L-1]; + Result.push_back(T); + L = I+1; + I++; + continue; + } + + if (!Seps[I-From-1] && IsLower(strStr[I-1]) && IsUpper(strStr[I])) + { + PreserveStyleToken T; + T.Token = strStr.SubStr(L, I-L); + T.PrependChar = 0; + if (L-1-From >= 0 && Seps[L-1-From]) + T.PrependChar = strStr[L-1]; + Result.push_back(T); + L = I; + } + } + + if (L < From+Length) + { + PreserveStyleToken T; + T.Token = strStr.SubStr(L, From+Length-L); + T.PrependChar = 0; + if (L-1-From >= 0 && Seps[L-1-From]) + T.PrependChar = strStr[L-1]; + Result.push_back(T); + } + + if (Result.size() > 1) + { + wchar_t PrependChar = Result[1].PrependChar; + for (size_t I = 2; I < Result.size(); I++) + if (PrependChar != Result[I].PrependChar) + { + Result.clear(); + PreserveStyleToken T; + T.Token = strStr.SubStr(From, Length); + T.PrependChar = 0; + T.TypeMask = 1 << UNKNOWN; + Result.push_back(T); + return Result; + } + } + + return Result; +} + +static std::vector<PreserveStyleToken> PreserveStyleTokenize(const string& strStr, int From, int Length) +{ + std::vector<PreserveStyleToken> Tokens = InternalPreserveStyleTokenize(strStr, From, Length); + + int Mask = -1; + for (size_t I = 0; I < Tokens.size(); I++) + { + if (I == 0) + Tokens[I].TypeMask = GetPeserveCaseStyleMask(Tokens[I].Token); + else + { + if (Mask == -1) + Mask = GetPeserveCaseStyleMask(Tokens[I].Token); + else + Mask &= GetPeserveCaseStyleMask(Tokens[I].Token); + } + } + + for (size_t I = 1; I < Tokens.size(); I++) + Tokens[I].TypeMask = Mask; + + return Tokens; +} + +static void ToPreserveStyleType(string& strStr, PreserveStyleType type) +{ + if (type != UNKNOWN) + { + for (size_t I = 0; I < strStr.GetLength(); I++) + { + if (type == UPPERCASE_ALL) + strStr.GetBuffer()[I] = Upper(strStr[I]); + if (type == LOWERCASE_ALL) + strStr.GetBuffer()[I] = Lower(strStr[I]); + if (type == UPPERCASE_FIRST) + { + if (I == 0) + strStr.GetBuffer()[I] = Upper(strStr[I]); + else + strStr.GetBuffer()[I] = Lower(strStr[I]); + } + } + } +} + +static PreserveStyleType ChoosePreserveStyleType(int Mask) +{ + if (Mask == (1 << UNKNOWN)) + return UNKNOWN; + + PreserveStyleType Result = UNKNOWN; + for (int Style = 0; UPPERCASE_ALL+Style < UNKNOWN; Style++) + if ((Mask & (1 << Style)) != 0) + Result = PreserveStyleType(UPPERCASE_ALL+Style); + + return Result; +} + +bool PreserveStyleReplaceString(const wchar_t *Source, int StrSize, const string& Str, string& ReplaceStr, int& CurPos, int Position, int Case, int WholeWords, const wchar_t *WordDiv, int Reverse, int& SearchLength) +{ + SearchLength = 0; + + if (Reverse) + { + Position--; + + if (Position>=StrSize) + Position=StrSize-1; + + if (Position<0) + return false; + } + + if (Position>=StrSize || Str.IsEmpty() || ReplaceStr.IsEmpty()) + return false; + + + std::vector<PreserveStyleToken> StrTokens = PreserveStyleTokenize(Str, 0, Str.GetLength()); + + for (int I=Position; (Reverse && I>=0) || (!Reverse && I<StrSize); Reverse ? I--:I++) + { + if (WholeWords && !(I == 0 || IsSpace(Source[I-1]) || wcschr(WordDiv, Source[I-1]))) + continue; + + bool Matched = true; + + int Idx = I; + size_t J = 0; + size_t T = 0; + + while (((J+1 < StrTokens.size()) || (J+1 == StrTokens.size() && T < StrTokens[J].Token.GetLength())) + && Source[Idx]) + { + bool Sep = (I < Idx && Source[I+1] && IsPreserveStyleTokenSeparator(Source[Idx]) + && !IsPreserveStyleTokenSeparator(Source[Idx-1]) + && !IsPreserveStyleTokenSeparator(Source[Idx+1])); + + if (Sep) + { + if (T == StrTokens[J].Token.GetLength()) + { + Idx++; + T = 0; + J++; + continue; + } + else + { + Matched = false; + break; + } + } + + Sep = (I < Idx && IsLower(Source[Idx-1]) && IsUpper(Source[Idx]) + && !IsPreserveStyleTokenSeparator(Source[Idx-1]) + && !IsPreserveStyleTokenSeparator(Source[Idx])); + + if (Sep && T != 0) + { + if (T == StrTokens[J].Token.GetLength()) + { + T = 0; + J++; + continue; + } + else + { + Matched = false; + break; + } + } + + if (T >= StrTokens[J].Token.GetLength()) + { + Matched = false; + break; + } + + if (Case && Source[Idx] != StrTokens[J].Token[T]) + { + Matched = false; + break; + } + + if (!Case && Upper(Source[Idx]) != Upper(StrTokens[J].Token[T])) + { + Matched = false; + break; + } + + T++; + Idx++; + } + + if (WholeWords && !(Idx >= StrSize || IsSpace(Source[Idx]) || wcschr(WordDiv, Source[Idx]))) + continue; + + if (Matched && T == StrTokens[J].Token.GetLength() && J+1 == StrTokens.size()) + { + std::vector<PreserveStyleToken> SourceTokens = PreserveStyleTokenize(Source, I, Idx-I); + + bool Same = SourceTokens.size() == StrTokens.size(); + for (size_t K = 0; Same && K < SourceTokens.size(); K++) + Same &= SourceTokens[K].Token.GetLength() == StrTokens[K].Token.GetLength(); + + if (Same) + { + std::vector<PreserveStyleToken> ReplaceStrTokens = PreserveStyleTokenize(ReplaceStr, 0, ReplaceStr.GetLength()); + ToPreserveStyleType(ReplaceStrTokens[0].Token, ChoosePreserveStyleType(SourceTokens[0].TypeMask)); + ReplaceStrTokens[0].PrependChar = SourceTokens[0].PrependChar; + + int Last = SourceTokens.size()-1; + if (Last > 0) + for (size_t K = 1; K < ReplaceStrTokens.size(); K++) + { + ToPreserveStyleType(ReplaceStrTokens[K].Token, ChoosePreserveStyleType(SourceTokens[Last].TypeMask)); + ReplaceStrTokens[K].PrependChar = SourceTokens[Last].PrependChar; + } + + ReplaceStr = ""; + for (size_t K = 0; K < ReplaceStrTokens.size(); K++) + { + if (ReplaceStrTokens[K].PrependChar != 0) + ReplaceStr += ReplaceStrTokens[K].PrependChar; + ReplaceStr += ReplaceStrTokens[K].Token; + } + + CurPos = I; + SearchLength = Idx-I; + + return true; + } + } + } + + return false; +} Index: unicode_far/edit.hpp =================================================================== --- unicode_far/edit.hpp (revision 9550) +++ unicode_far/edit.hpp (working copy) @@ -113,7 +113,7 @@ void AppendString(const wchar_t *Str); void InsertString(const wchar_t *Str); void InsertBinaryString(const wchar_t *Str,int Length); - int Search(const string& Str,string& ReplaceStr,int Position,int Case,int WholeWords,int Reverse,int Regexp, int *SearchLength); + int Search(const string& Str,string& ReplaceStr,int Position,int Case,int WholeWords,int Reverse,int Regexp,int PreserveStyle, int *SearchLength); void SetClearFlag(bool Flag) {Flags.Change(FEDITLINE_CLEARFLAG,Flag);} int GetClearFlag() {return Flags.Check(FEDITLINE_CLEARFLAG);} void SetCurPos(int NewPos) {CurPos=NewPos; SetPrevCurPos(NewPos);} Index: unicode_far/far.vcxproj.filters =================================================================== --- unicode_far/far.vcxproj.filters (revision 9550) +++ unicode_far/far.vcxproj.filters (working copy) @@ -326,6 +326,9 @@ <ClCompile Include="poscache.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="preservestyle.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="print.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -853,6 +856,9 @@ <ClInclude Include="poscache.hpp"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="preservestyle.hpp"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="print.hpp"> <Filter>Header Files</Filter> </ClInclude> |
|
Такому место в плагине. Зачем это в фар пихать? |
|
Это общая функциональность - она полезна при правке любого текста, даже литературного. Не говоря уже об исходниках. Мне кажется, что такой режим может быть часто востребован (вот Regular Expressions есть же). |
|
Это специфичный функционал, с не совсем предвиденным результатом. В стороннем плагине (или даже макросе) ему самое место. |
|
Ну ок, хотя меня не убедили. Кажется, что таким функционалом почти всегда можно пользоваться, больно уж часто проблемы как минимум с регистром при заменах. Это всегда мешает. А точки зрения пользователя даже результат Whole words тоже непредвиденный - так как какой там список сепараторов мало кто знает. А какой-нибудь встроенный Process List значительно дальше от files-and-archives, чем прокачка редактора, однако он в ядре. Ну да ладно. Какой плагин порекомендуете взять за основу? Что наиболее похожее из существующего уже есть, что использует современный Plugin API? Возможно ли как-то встроиться в стандартный диалог Search-Replace и процесс замены (чтобы автоматически работал доп. диалог Replace-All-Skip-Cancel)? |
|
Из аргументов почему он может быть в FAR-е еще такое - эта функциональность органично встроилась в существующий функционал. Т.е. для пользователя добавилась одна галочка в одном диалоге и все. Никаких других неожиданностей нет. Она не требует доп-знаний или чтения документации, название "Preserve style" (Сохранять стиль) довольно самоописательное. Поведение довольно интуитивное. Ну и мне просто кажется, что эта крутая фича, которая выгодно бы отличала FAR от других редакторов файлов. Вот Regular Expressions встроили же. |
|
Можешь вырезать нужный код из самого фара и переделать его на plugin api, думаю не так уже и много работы. Для самого близкого примера можно посмотреть на плагин EditCase. |
|
Ну напиши на форуме, посмотрим что там скажут. |
|
А мне идея нравится. |
|
Спасибо. Какой план? Могу написать на форум и приложить пропатченный FAR, чтобы можно было самостоятельно без накатывания патча попробовать, как все работает. |
|
Да. |
|
А, и почему PreserveStyle, если это по факту PreserveCase? |
|
Не совсем. Посмотрите второй пример. Он сохраняет ТАКОЙ_СПОСОБ_ИМЕНОВАНИЯ, такой_способ_именования, такой-способ-именования, такой.способ.именования и прочее (разделители настраиваются константой static const wchar_t *PreserveStyleTokenSeparators = L"_-."; в preservestyle.cpp). Для литературных текстов он выродится в PreserveCase, а в исходниках получается помощней. Мне кажется PreserveStyle более общее и отражающее суть название. |
|
Build 3182, с парой изменений, чтобы предупреждений не было. Ждём документацию. |
|
Может, стоит сделать PreserveStyleTokenSeparators настраиваемым? Хотя бы через far:config |
|
help.diff (2,330 bytes)
Index: unicode_far/FarRus.hlf.m4 =================================================================== --- unicode_far/FarRus.hlf.m4 (revision 9639) +++ unicode_far/FarRus.hlf.m4 (working copy) @@ -3001,6 +3001,8 @@ #Регулярные выражения# - ^<wrap>использовать регулярные выражения для ~поиска~@RegExp@ и ~замены~@RegExpRepl@. Поиск построчный, поэтому многострочные конструкции и переводы строк не будут найдены. + #Сохранять стиль# - ^<wrap>сохранять стиль (регистр и форматирование для файлов исходных текстов) во время ~замены~@RegExpRepl@. + При нажатии кнопки #Всё# будет показано ~меню~@FindAllMenu@ с результатами поиска всех вхождений. @FindAllMenu Index: unicode_far/FarEng.hlf.m4 =================================================================== --- unicode_far/FarEng.hlf.m4 (revision 9639) +++ unicode_far/FarEng.hlf.m4 (working copy) @@ -2954,11 +2954,13 @@ #Reverse search# - ^<wrap>change the direction of search (from the end of file towards the beginning) #Regular expressions# - ^<wrap>treat input as Perl regular expression (~search~@RegExp@ and ~replace~@RegExpRepl@). -Поиск построчный, поэтому многострочные конструкции и переводы строк не будут найдены. +It processes lines separately, so multi-line entries line-break characters will not be found. - При нажатии кнопки #Всё# будет показано ~меню~@FindAllMenu@ с результатами поиска всех вхождений. + #Preserve style# - ^<wrap>preserve style (case and code style for program source files) (~replace~@RegExpRepl@). + By pressing the button #All# it will be shown the ~menu~@FindAllMenu@ with the whole list of matched entries. + @FindAllMenu $ #Редактор: меню с результатами поиска всех вхождений# В этом меню доступны следующие сочетания клавиш: |
|
Загрузил файл help.diff с документацией. |
|
Мне кажется (если следовать стилю, что "Help в Far Manager достаточно полно и понятно описывает..."), что "Preserve style" заслуживает отдельного топика в хелпе, описывающего более детально как ЭТО работает (пример - "@HardSymLink"). В дополнении к help.diff. |
|
2MikeMirzayanov: так топик-разжовыватель этой фишки в хелпе будет? |
|
2vskirdin: да, я напишу подробный текст |
|
PreserveStyle-Description.diff (6,600 bytes)
Index: unicode_far/FarRus.hlf.m4 =================================================================== --- unicode_far/FarRus.hlf.m4 (revision 9730) +++ unicode_far/FarRus.hlf.m4 (working copy) @@ -3004,10 +3004,60 @@ #Регулярные выражения# - ^<wrap>использовать регулярные выражения для ~поиска~@RegExp@ и ~замены~@RegExpRepl@. Поиск построчный, поэтому многострочные конструкции и переводы строк не будут найдены. - #Сохранять стиль# - ^<wrap>сохранять стиль (регистр и форматирование для файлов исходных текстов) во время замены. + ~Сохранять стиль~@PreserveStyle@ - ^<wrap>сохранять стиль (регистр и форматирование для файлов исходных текстов) во время замены. При нажатии кнопки #Всё# будет показано ~меню~@FindAllMenu@ с результатами поиска всех вхождений. + +@PreserveStyle +$ #Режим замены: Сохранять стиль# + +Режим замены #"Сохранять стиль"# позволяет осуществлять замену с сохранением регистра +заменяемого текста и/или стиля его написания для файлов исходных текстов. Например, +при замене в этом режиме во фразе #"Tu be or not tu be"# слова #"tu"# на слово #"to"# будет +получен результат: #"To be or not to be"# (обратите внимание на регистр). Аналогично, +при замене #"UserName"# на #"PersonLogin"# в следующем фрагменте: + + #String writerUserName = user.name || DEFAULT_USER_NAME || configuration("default-user-name");# + +будет получен результат: + + #String writerPersonLogin = person.login || DEFAULT_PERSON_LOGIN || configuration("default-person-login");# + +Обратите внимание, что замена сохранила стиль именования идентификаторов для всех вхождений. + +Замена с сохранением стиля использует следующий алгоритм. + 1 Образец и результат замены разбиваются на части, используя символы #"_-."# в + качестве разделителей, кроме того разделением считается изменение регистра + буквы со строчной на прописную. Разбиение осуществляется только по одному из + вариантов, если существует неоднозначность в выборе правила, то данная строка + считается одной частью. Например, строки "testMe", "WhatIsIt", "far-manager", + "USER_FIRST_NAME" будут разбиты на части (две, три, две и три части + соответственно), а строки «test_userName”, “one.two-three” разбиты не будут + (остануться одной частью). Все получившиеся части как образца, так и результата + замены не пусты (кроме тривиальных случаев пустых строк в качестве образца + и/или текста замены). + 2 Осуществляется проход по тексту и поиск таких подстрок, которые при разбиении + на части в соответствии с пунктом 1 дают в точности те же части, что и образец + (при сравнении частей регистр игнорируется). + 3 Для всех частей найденной подстроки вычисляется набор правил форматирования + под которые он подходит. Возможные варианты: "все прописными", "все строчными", + "первая заглавная, затем все строчными", "произвольный формат". Вариант + "произвольный формат" добавляется в набор в любом случае. Для первой части подстроки + набор сохраняется как есть, а остальные наборы (для всех частей кроме первой) + пересекаются как множества. + 4 Набор частей результата замены преобразуется так, что первая часть форматируется + в соответствии с самым сильным из правил в наборе правил первой части строки, + а остальные - в соответствии с самым сильным из правил в найденном пересечении + правил. + 5 Набор частей замены соединяется в с сохранением того разделителя, которым разделены + части обрабатываемой подстроки. Результат записывается на место подстроки. + 6 Если таким способом не получилось сделать ни одной замены, то осуществляется + поиск-замена стандартным способом. При замене, если и в образце и в заменяемом + тексте первый символ – буква, то регистр этой буквы сохраняется (то есть + приводится к регистру первой буквы заменяемой подстроки). + + @FindAllMenu $ #Редактор: меню с результатами поиска всех вхождений# В этом меню доступны следующие сочетания клавиш: |
|
Написал подробное описание на русском. Давайте отредактируем его, затем переведу на английский. |
|
> 5 Набор частей замены соединяется в с сохранением того недописано: "в с"? Добавил немного отформатированный вариант. |
|
|
|
Есть, например, текст: свистелки.и.сопелки Свистелки.И.Сопелки СВИСТЕЛКИ.И.СОПЕЛКИ Свистелки.и.Сопелки меняю "свистелки.и.сопелки" на "bells.and.whistles" со включенной опцией. получаю bells.and.whistles Bells.And.Whistles BELLS.AND.WHISTLES Bells.and.whistles Почему не сохранился регистр в последней строке? |
|
Потому что стиль определяется одновременно для всех токенов. В данном случае есть смешение стиля и легко ошибиться, сделав неверную замену. Например, как заменять в случае, если количество токенов в образце и результате замены не совпадает? Как вариант, можно сделать так: если кол-во токенов одинаково, то сохранять стиль токенов отдельно по одному. Кажется, что это решит эту проблему и, возможно, это будет частый способ использования. |
|
> Как вариант, можно сделать так: Я как раз об этом. Для одинакового числа токенов неопределённости нет, и, как по мне, это более ожидаемое поведение. |
|
Да, сделаю такое поведение. |
|
Что с этим? |
|
PreserveStyle-Improvement.diff (5,834 bytes)
Index: unicode_far/preservestyle.cpp =================================================================== --- unicode_far/preservestyle.cpp (revision 10203) +++ unicode_far/preservestyle.cpp (working copy) @@ -167,30 +167,11 @@ { std::list<PreserveStyleToken> Tokens = InternalPreserveStyleTokenize(strStr, From, Length); - int Mask = -1; - bool First = true; std::for_each(RANGE(Tokens, i) { - if (First) - { - i.TypeMask = GetPeserveCaseStyleMask(i.Token); - First = false; - } - else - { - if (Mask == -1) - Mask = GetPeserveCaseStyleMask(i.Token); - else - Mask &= GetPeserveCaseStyleMask(i.Token); - } + i.TypeMask = GetPeserveCaseStyleMask(i.Token); }); - auto Start = Tokens.begin(); - ++Start; - std::for_each(Start, Tokens.end(), [&Mask](VALUE_TYPE(Tokens)& i) - { - i.TypeMask = Mask; - }); return Tokens; } @@ -228,6 +209,63 @@ return Result; } +void FindStyleTypeMaskAndPrependCharByExpansion(const wchar_t* Source, const size_t StrSize, const int Begin, const int End, int& TypeMask, wchar_t& PrependChar) +{ + /* Try to expand to the right. */ + { + int Right = End; + + if (static_cast<size_t>(Right) < StrSize && (IsAlphaNum(Source[Right]) || IsPreserveStyleTokenSeparator(Source[Right]))) + { + Right++; + + while (static_cast<size_t>(Right) < StrSize) + { + if (!IsAlphaNum(Source[Right]) || (IsLower(Source[Right-1]) && IsUpper(Source[Right]))) + break; + Right++; + } + + const std::list<PreserveStyleToken> SegmentTokens = PreserveStyleTokenize(Source, Begin, Right-Begin); + + if (SegmentTokens.size() > 1) + { + TypeMask = SegmentTokens.back().TypeMask; + PrependChar = SegmentTokens.back().PrependChar; + return; + } + } + } + + /* Try to expand to the left. */ + { + int Left = Begin - 1; + + if (Left >= 1 && (IsAlphaNum(Source[Left]) || IsPreserveStyleTokenSeparator(Source[Left]))) + { + Left--; + + while (Left >= 0) + { + if (!IsAlphaNum(Source[Left]) || (IsLower(Source[Left]) && IsUpper(Source[Left + 1]))) + break; + Left--; + } + + Left++; + + const std::list<PreserveStyleToken> SegmentTokens = PreserveStyleTokenize(Source, Left, End-Left); + + if (SegmentTokens.size() > 1) + { + TypeMask = SegmentTokens.back().TypeMask; + PrependChar = SegmentTokens.back().PrependChar; + return; + } + } + } +} + bool PreserveStyleReplaceString(const wchar_t* Source, size_t StrSize, const string& Str, string& ReplaceStr, int& CurPos, int Position, int Case, int WholeWords, const wchar_t *WordDiv, int Reverse, int& SearchLength) { SearchLength = 0; @@ -338,24 +376,74 @@ for(auto SrcI = SourceTokens.cbegin(), StrI = StrTokens.cbegin(); Same && SrcI != SourceTokens.cend(); ++SrcI, ++StrI) Same &= SrcI->Token.GetLength() == StrI->Token.GetLength(); } + if (Same) { std::list<PreserveStyleToken> ReplaceStrTokens = PreserveStyleTokenize(ReplaceStr, 0, ReplaceStr.GetLength()); - ToPreserveStyleType(ReplaceStrTokens.front().Token, ChoosePreserveStyleType(SourceTokens.front().TypeMask)); - ReplaceStrTokens.front().PrependChar = SourceTokens.front().PrependChar; - if (!SourceTokens.empty()) + if (ReplaceStrTokens.size() == SourceTokens.size()) { - auto ReplaceI = ReplaceStrTokens.begin(); - ++ReplaceI; + int CommonTypeMask = -1; + std::for_each(RANGE(SourceTokens, i) + { + if (CommonTypeMask == -1) + CommonTypeMask = i.TypeMask; + else + CommonTypeMask &= i.TypeMask; + }); + + PreserveStyleType CommonType = ChoosePreserveStyleType(CommonTypeMask); + if (CommonTypeMask != -1 && CommonType == UNKNOWN) + CommonTypeMask = -1; + auto SourceI = SourceTokens.cbegin(); - ++SourceI; - for (; ReplaceI != ReplaceStrTokens.end(); ++ReplaceI, ++SourceI) + std::for_each(RANGE(ReplaceStrTokens, i) { - ToPreserveStyleType(ReplaceI->Token, ChoosePreserveStyleType(SourceI->TypeMask)); - ReplaceI->PrependChar = SourceTokens.back().PrependChar; + ToPreserveStyleType(i.Token, CommonTypeMask != -1 ? CommonType : ChoosePreserveStyleType(SourceI->TypeMask)); + i.PrependChar = SourceI->PrependChar; + SourceI++; + }); + } + else + { + ToPreserveStyleType(ReplaceStrTokens.front().Token, ChoosePreserveStyleType(SourceTokens.front().TypeMask)); + ReplaceStrTokens.front().PrependChar = SourceTokens.front().PrependChar; + + if (!SourceTokens.empty()) + { + int AfterFirstCommonTypeMask = -1; + wchar_t PrependChar = SourceTokens.back().PrependChar; + + auto SourceI = SourceTokens.cbegin(); + ++SourceI; + for (; SourceI != SourceTokens.end(); ++SourceI) + { + if (AfterFirstCommonTypeMask == -1) + AfterFirstCommonTypeMask = SourceI->TypeMask; + else + AfterFirstCommonTypeMask &= SourceI->TypeMask; + } + + if (AfterFirstCommonTypeMask == -1) + FindStyleTypeMaskAndPrependCharByExpansion(Source, StrSize, I, Idx, AfterFirstCommonTypeMask, PrependChar); + + if (AfterFirstCommonTypeMask == -1) + { + AfterFirstCommonTypeMask = SourceTokens.front().TypeMask; + PrependChar = ReplaceStrTokens.back().PrependChar; + } + + auto ReplaceI = ReplaceStrTokens.begin(); + ++ReplaceI; + for (; ReplaceI != ReplaceStrTokens.end(); ++ReplaceI) + { + ToPreserveStyleType(ReplaceI->Token, ChoosePreserveStyleType(AfterFirstCommonTypeMask)); + ReplaceI->PrependChar = PrependChar; + } } + } + ReplaceStr.Clear(); std::for_each(CONST_RANGE(ReplaceStrTokens, i) { |
|
Добавил PreserveStyle-Improvement.diff В нем реализовано сохранение стилей по токенам, если их количество совпадает. Кроме того, значительно улучшено поведение, если заменяемый токен единственный. Например, при замене "size" на "lengthOrCount" в MAX_SIZE=12 получится MAX_LENGTH_OR_COUNT, а раньше было плохо. После того как получу подтверждение, что текущее поведение нравится, то могу актуализировать описание алгоритма в документации. Кстати, после этого надо английское описание написать. |
|
3378 |
|
Я не уверен в корректности некоторых ваших правок. Например, замена int на size_t в строке "size_t Left = Begin - 1;" может быть небезопасна. При Begin=0 получим переполнение. Кроме того, код в FindStyleTypeMaskAndPrependCharByExpansion для двух случаев был максимально симметричен, а теперь стал разным. В этой же функции случай удлинения влево (второй) мне кажется исправлен неправильно. Например, мой цикл "while (Left >= 0)" завершался с постусловием, что Left указывает на 1 позицию левее разрыва (поэтому затем шел Left++), в от время как в вашем варианте цикл "for (;;)" благодаря "if (!Left) break;" завершится в Left=0 (если явного разрыва не нашлось). Это нарушает постусловие и дальше код уже неверен (например, Left++ уже делать не надо бы). Возможно есть еще проблемы, я внимательно пока не все прочитал. Кстати, я бы к основной функции preservestyle.cpp написал бы тестов - это было бы полезно. Есть инфраструктура для тестов? Куда и как их лучше написать? |
|
Там был варнинг, я поправил как смог :) В 3379 должно быть как надо. Тесты - это здорово, но инфраструктуры пока нет, так что всё обсуждаемо. |
|
Да, теперь ОК. Кстати, а зачем всюду исправили std::vector на std::list. Конечно, память может чуток экономите, но итерации по std::list значительно медленнее из-за cache miss + проще ухудшить производительность за счет O(n) операций size и []. О тестах подумаю. |
|
В рамках глобального рефакторинга. Если здесь это критично по скорости - не вопрос, пусть будет вектор. |
|
Думать надо, скорее ничего страшного. Я посмотрю. Просто, кажется, это странный рефакторинг. Вроде как-раз по-дефолту лучше vector использовать из-за причин, что я описал. На StackOverflow тоже обсуждалось, вроде это общее мнение сообщества. Еще вопрос - чем компилируете, что появлялись warnings? Я компилирую MinGW 4.7.2 вот так "build.bat gcc 32 [debug]". Может добавить "-Wextra -Wconversion" в makefile_gcc_common? |
|
vc2010/2012. -Wextra -Wconversion пока даёт слишком много лишнего, но в перспективе можно, да. |
|
В справке по этой уникальной функции я нашел несколько опечаток. Вот они: 1. "будут (остануться одной частью).": в слове "остануться" надо убрать мягкий знак (т.е. правильно будет "останутся") 2. "...части как образца, так и результата замены не пусты...": после "части" и после "замены" я бы поставил тире 3. "набор правил форматирования под которые он подходит": после "форматирования" надо поставить запятую |
|
MikeMirzayanov, проверьте пожалуйста имплементацию InternalPreserveStyleTokenize. Там есть такое: wchar_t Sep = 0; ... if (Sep != 0 && strStr[I] != Sep) { <code> } Похоже, что <code> никогда не исполняется. |
|
Похоже это правда. Я перечитал код, видимо это осталось от какой-то промежуточной версии. Прикладываю патч, где вырезал этот момент. |
|
preservestyle.cpp.patch (790 bytes)
Index: preservestyle.cpp =================================================================== --- preservestyle.cpp (revision 11364) +++ preservestyle.cpp (working copy) @@ -81,23 +81,12 @@ { std::list<PreserveStyleToken> Result; - wchar_t Sep = 0; std::vector<bool> Seps(Length, false); for (size_t I = From+1; I+1 < From+Length; I++) if (IsPreserveStyleTokenSeparator(strStr[I]) && !IsPreserveStyleTokenSeparator(strStr[I-1]) && !IsPreserveStyleTokenSeparator(strStr[I+1])) { - if (Sep != 0 && strStr[I] != Sep) - { - PreserveStyleToken T; - T.Token = strStr.substr(From, Length); - T.PrependChar = 0; - T.TypeMask = 1 << UNKNOWN; - Result.emplace_back(T); - return Result; - } - Seps[I-From] = true; } |
|
Не доделано? |
|
Ошибки в справке тоже не исправлены (см. 0002294:0010941). |
Date Modified | Username | Field | Change |
---|---|---|---|
2013-02-08 23:57 | MikeMirzayanov | New Issue | |
2013-02-08 23:57 | MikeMirzayanov | File Added: PreserveStyle.diff | |
2013-02-09 00:17 | alexy | Note Added: 0010235 | |
2013-02-09 00:26 | MikeMirzayanov | Note Added: 0010236 | |
2013-02-09 00:30 | alexy | Note Added: 0010237 | |
2013-02-09 00:48 | MikeMirzayanov | Note Added: 0010238 | |
2013-02-09 00:54 | MikeMirzayanov | Note Added: 0010239 | |
2013-02-09 00:57 | alexy | Note Added: 0010240 | |
2013-02-09 01:01 | alexy | Note Added: 0010241 | |
2013-02-09 09:47 | DrKnS | Note Added: 0010242 | |
2013-02-09 10:08 | MikeMirzayanov | Note Added: 0010243 | |
2013-02-09 10:19 | DrKnS | Note Added: 0010244 | |
2013-02-09 12:18 | DrKnS | Note Added: 0010260 | |
2013-02-09 12:40 | MikeMirzayanov | Note Added: 0010261 | |
2013-02-12 19:57 | DrKnS | Note Added: 0010272 | |
2013-02-13 09:01 | DAtaMan | Note Added: 0010277 | |
2013-02-14 15:28 | MikeMirzayanov | File Added: help.diff | |
2013-02-14 15:28 | MikeMirzayanov | Note Added: 0010293 | |
2013-02-15 06:19 | vskirdin | Note Added: 0010296 | |
2013-02-15 21:13 | DrKnS | Assigned To | => DrKnS |
2013-02-15 21:13 | DrKnS | Status | new => assigned |
2013-02-18 05:55 | vskirdin | Note Added: 0010312 | |
2013-02-18 12:27 | MikeMirzayanov | Note Added: 0010313 | |
2013-02-27 21:48 | MikeMirzayanov | File Added: PreserveStyle-Description.diff | |
2013-02-27 21:49 | MikeMirzayanov | Note Added: 0010393 | |
2013-02-28 06:00 | vskirdin | Note Added: 0010394 | |
2013-02-28 06:00 | vskirdin | File Added: PreserveStyle.hlf | |
2013-03-17 12:30 | DrKnS | Note Added: 0010535 | |
2013-03-17 13:11 | MikeMirzayanov | Note Added: 0010536 | |
2013-03-17 13:40 | DrKnS | Note Added: 0010537 | |
2013-03-17 14:29 | MikeMirzayanov | Note Added: 0010538 | |
2013-04-28 13:20 | alexy | Note Added: 0010913 | |
2013-04-29 23:59 | MikeMirzayanov | File Added: PreserveStyle-Improvement.diff | |
2013-04-30 00:03 | MikeMirzayanov | Note Added: 0010924 | |
2013-04-30 18:24 | DrKnS | Note Added: 0010928 | |
2013-04-30 18:53 | MikeMirzayanov | Note Added: 0010929 | |
2013-04-30 19:22 | DrKnS | Note Added: 0010930 | |
2013-04-30 19:48 | MikeMirzayanov | Note Added: 0010931 | |
2013-04-30 19:53 | DrKnS | Note Added: 0010933 | |
2013-04-30 20:10 | MikeMirzayanov | Note Added: 0010934 | |
2013-04-30 20:42 | DrKnS | Note Added: 0010935 | |
2013-05-01 18:24 | fml2 | Note Added: 0010941 | |
2014-01-19 16:32 | DrKnS | Note Added: 0011722 | |
2014-01-19 20:04 | MikeMirzayanov | Note Added: 0011723 | |
2014-01-19 20:04 | MikeMirzayanov | File Added: preservestyle.cpp.patch | |
2017-11-11 16:38 | JohnDoe | Note Added: 0015823 | |
2017-11-11 22:36 | fml2 | Note Added: 0015830 |