Fix Mark occurences for notepad2-mod

4 views
Skip to first unread message

johnsonj

unread,
Jun 2, 2016, 10:51:45 PM6/2/16
to 파이썬문서고
소스에서는 대용량 파일에서 작동이 원활하지 않으므로 2000개 이하로 제한 되어 있음.
한 화면 안에서만 작동하도록 고침.

-------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/Edit.c b/src/Edit.c
@@ -5807,18 +5813,29 @@ void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase
   struct TextToFind ttf;
   int iPos;
   char *pszText;
+  int iTextFirstLine;
+  int iTextFirst;
+  int iTextLastLine;
+  int iTextLast;
   int iTextLen;
   int iSelStart;
   int iSelEnd;
   int iSelCount;
   int iMatchesCount;
 
+  if ((SendMessage(hwnd,SCI_GETSELECTIONS,0,0) > 1)
+     && (SendMessage(hwnd,SCI_GETSELECTIONMODE,0,0) == SC_SEL_STREAM))
+    return;
+
   // feature is off
   if (!iMarkOccurrences)
     return;
 
-
-  iTextLen = (int)SendMessage(hwnd,SCI_GETLENGTH,0,0);
+  iTextFirstLine = (int)SendMessage(hwnd,SCI_GETFIRSTVISIBLELINE,0,0);
+  iTextFirst = (int)SendMessage(hwnd,SCI_POSITIONFROMLINE,iTextFirstLine, 0);
+  iTextLastLine = iTextFirstLine + (int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0);
+  iTextLast = (int)SendMessage(hwnd,SCI_GETLINEENDPOSITION,iTextLastLine, 0);
+  iTextLen = iTextLast - iTextFirst;
 
   // get current selection
   iSelStart = (int)SendMessage(hwnd,SCI_GETSELECTIONSTART,0,0);
@@ -5827,7 +5844,7 @@ void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase
 
   // clear existing indicator
   SendMessage(hwnd, SCI_SETINDICATORCURRENT, 1, 0);
-  SendMessage(hwnd, SCI_INDICATORCLEARRANGE, 0, iTextLen);
+  SendMessage(hwnd, SCI_INDICATORCLEARRANGE, iTextFirst, iTextLen);
 
   // if nothing selected or multiple lines are selected exit
   if (iSelCount == 0 ||
@@ -5857,7 +5874,7 @@ void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase
 
   ZeroMemory(&ttf,sizeof(ttf));
 
-  ttf.chrg.cpMin = 0;
+  ttf.chrg.cpMin = iTextFirst;
   ttf.chrg.cpMax = iTextLen;
   ttf.lpstrText = pszText;
 

johnsonj

unread,
Jun 3, 2016, 12:38:18 AM6/3/16
to 파이썬문서고
1. editmarkall이 무조건 실행되도록 바꿀 필요가 있다.
2. SCI_GETFIRSTVISIBLELINE이 작동하지 않는 문제와
3. 인디케이터를 지워야 하는 문제를 해결해야 함.
인디케이터는 어떻게 지워야 하나...
인디케이터 번호를 무효로 만들면 간단하게 없어지는데..
 

johnsonj

unread,
Jun 3, 2016, 9:33:37 PM6/3/16
to 파이썬문서고
구조를 효율적으로 변경...
키보드 이동이 힘들 정도의 텍스트에
마우스와는 랙없이 잘 작동...
//=============================================================================
//
//  EditMarkAll()
//  Mark all occurrences of the text currently selected (by Aleksandar Lekov)
//
void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase, BOOL bMarkOccurrencesMatchWords)
{

  struct TextToFind ttf;
  int iPos;
  char *pszText;

  int iTextLenDoc;
  int iTextStartLine;
  int iTextEndLine;
  int iTextStartLineDoc;
  int iTextEndLineDoc;
  int iTextStart;
  int iTextEnd;


  int iSelStart;
  int iSelEnd;
  int iSelCount;
  int iMatchesCount;

  if ((SendMessage(hwnd,SCI_GETSELECTIONS,0,0) > 1)
     && (SendMessage(hwnd,SCI_GETSELECTIONMODE,0,0) == SC_SEL_STREAM))
    return;


  // feature is off
  if (!iMarkOccurrences)
    return;

  // clear existing indicator
  SendMessage(hwnd, SCI_SETINDICATORCURRENT,1,0);
  iTextLenDoc = (int)SendMessage(hwnd,SCI_GETLENGTH,0,0);
  SendMessage(hwnd, SCI_INDICATORCLEARRANGE,0,iTextLenDoc);


  // get current selection
  iSelStart = (int)SendMessage(hwnd,SCI_GETSELECTIONSTART,0,0);
  iSelEnd = (int)SendMessage(hwnd,SCI_GETSELECTIONEND,0,0);
  iSelCount = iSelEnd - iSelStart;


  // if nothing selected or multiple lines are selected exit
  if (iSelCount == 0 ||
      (int)SendMessage(hwnd, SCI_LINEFROMPOSITION, iSelStart, 0) !=
      (int)SendMessage(hwnd, SCI_LINEFROMPOSITION, iSelEnd, 0))
    return;

  pszText = LocalAlloc(LPTR,iSelCount + 1);
  (int)SendMessage(hwnd,SCI_GETSELTEXT,0,(LPARAM)pszText);

  // exit if selection is not a word and Match whole words only is enabled
  if (bMarkOccurrencesMatchWords)
  {
    iSelStart = 0;
    while (pszText[iSelStart])
    {
      if (StrChrIA(" \t\r\n@#$%^&*~-=+()[]{}\\/:;'\"", pszText[iSelStart]))
      {
        LocalFree(pszText);
        return;
      }
      iSelStart++;
    }
  }

  iTextStartLine = (int)SendMessage(hwnd,SCI_GETFIRSTVISIBLELINE,0,0);
  iTextStartLineDoc = (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextStartLine,0);
  iTextStart = (int)SendMessage(hwnd,SCI_POSITIONFROMLINE,iTextStartLineDoc, 0);

  iTextEndLine = iTextStartLine + (int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0);
  iTextEndLineDoc = (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextEndLine,0);
  iTextEnd = (int)SendMessage(hwnd,SCI_GETLINEENDPOSITION,iTextEndLineDoc, 0);

  ZeroMemory(&ttf,sizeof(ttf));

  ttf.chrg.cpMin = iTextStart;
  ttf.chrg.cpMax = iTextEnd;
  ttf.lpstrText = pszText;

  // set style
  SendMessage(hwnd, SCI_INDICSETALPHA, 1, 100);
  SendMessage(hwnd, SCI_INDICSETFORE, 1, 0xff << ((iMarkOccurrences - 1) << 3));
  SendMessage(hwnd, SCI_INDICSETSTYLE, 1, INDIC_ROUNDBOX);

  iMatchesCount = 0;
  while ((iPos = (int)SendMessage(hwnd, SCI_FINDTEXT,
      (bMarkOccurrencesMatchCase ? SCFIND_MATCHCASE : 0) | (bMarkOccurrencesMatchWords ? SCFIND_WHOLEWORD : 0),
      (LPARAM)&ttf)) != -1
      && ++iMatchesCount < 2000)
  {
    // mark this match
    SendMessage(hwnd, SCI_INDICATORFILLRANGE, iPos, iSelCount);
    ttf.chrg.cpMin = ttf.chrgText.cpMin + iSelCount;
    if (ttf.chrg.cpMin >= ttf.chrg.cpMax)
      break;
  }

  LocalFree(pszText);
  return;
}

Scintilla

unread,
Jun 4, 2016, 3:01:14 AM6/4/16
to 파이썬문서고
수고하셨습니다.

한 가지 본질적인 문제가 있네요.

현재 창 범위 내에서만 표시를 하기 때문에 스크롤을 하거나 창의 크기를 조절하면 조금만 범위를 벗어나도 표시가 되지 않는군요.
이 부분에 대한 고민이 필요해보입니다...


2016년 6월 4일 토요일 오전 10시 33분 37초 UTC+9, johnsonj 님의 말:

Scintilla

unread,
Jun 4, 2016, 4:56:53 AM6/4/16
to 파이썬문서고
참고로, 저는 이것과 별개로 Mark Occurance count(int iMatchesCount) 값을 status bar에 전시하는 것을 검토하고 있었는데, 이 기능과 묘하게 충동을 일으키네요.
화면에 표시된 갯수만 카운트합니다... ㅡ.ㅡ;


2016년 6월 4일 토요일 오후 4시 1분 14초 UTC+9, Scintilla 님의 말:

Scintilla

unread,
Jun 4, 2016, 5:50:21 AM6/4/16
to 파이썬문서고
두 기능... 그러니까 화면 내에서만 전시하는 것과 일치하는 개수를 전시하는 기능 모두
별도의 선택 기능으로 빼는 것이 옳아보입니다.

스크롤이나 창크기를 변경하면 이후 처리가 너무 복잡해지는 등의 문제가 예상되네요.


2016년 6월 4일 토요일 오후 5시 56분 53초 UTC+9, Scintilla 님의 말:

Scintilla

unread,
Jun 4, 2016, 8:08:21 AM6/4/16
to 파이썬문서고
앞에 얘기한 부분을 반영하기 위해 EditMarkAll()의 인자를 두 개 추가했습니다.
제가 수정한 내용은 아래와 같은데, 한번 검토 바랍니다.

이 내용이 포함된 버전을 일단 블로그에 공개하도록 하겠습니다.


void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase, BOOL bMarkOccurrencesMatchWords,
//BLUEnLIVE
     BOOL bMarkOccurrencesMarkVisibleOnly
, BOOL bMarkOccurrencesDisplayMarkCount
//BLUEnLIVE

)
{
 
struct TextToFind ttf;
 
int iPos;
 
char *pszText;

 
int iTextLenDoc;
 
int iTextStartLine;
 
int iTextEndLine;
 
int iTextStartLineDoc;
 
int iTextEndLineDoc;
 
int iTextStart;
 
int iTextEnd;

 
int iSelStart;
 
int iSelEnd;
 
int iSelCount;

 
 
// extern으로 지정, Edit.c와 Notepad2.c에서 공유
  iMatchesCount
= 0;


 
ZeroMemory(&ttf,sizeof(ttf));
 
 
if (bMarkOccurrencesMarkVisibleOnly) {

    iTextStartLine
= (int)SendMessage(hwnd,SCI_GETFIRSTVISIBLELINE,0,0);
    iTextStartLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextStartLine,0);
    iTextStart
= (int)SendMessage(hwnd,SCI_POSITIONFROMLINE,iTextStartLineDoc, 0);

    iTextEndLine
= iTextStartLine + (int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0);
    iTextEndLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextEndLine,0);
    iTextEnd
= (int)SendMessage(hwnd,SCI_GETLINEENDPOSITION,iTextEndLineDoc, 0);


    ttf
.chrg.cpMin = iTextStart;
    ttf
.chrg.cpMax = iTextEnd;
 
} else {
    ttf
.chrg.cpMin = 0;
    ttf
.chrg.cpMax = iTextLenDoc;

 
}

  ttf
.lpstrText = pszText;

 
// set style
 
SendMessage(hwnd, SCI_INDICSETALPHA, 1, 100);
 
SendMessage(hwnd, SCI_INDICSETFORE, 1, 0xff << ((iMarkOccurrences - 1) << 3));
 
SendMessage(hwnd, SCI_INDICSETSTYLE, 1, INDIC_ROUNDBOX);


 
//iMatchesCount = 0;

 
while ((iPos = (int)SendMessage(hwnd, SCI_FINDTEXT,
     
(bMarkOccurrencesMatchCase ? SCFIND_MATCHCASE : 0) | (bMarkOccurrencesMatchWords ? SCFIND_WHOLEWORD : 0),
     
(LPARAM)&ttf)) != -1
     
&& ++iMatchesCount < 2000)
 
{
   
// mark this match
   
SendMessage(hwnd, SCI_INDICATORFILLRANGE, iPos, iSelCount);
    ttf
.chrg.cpMin = ttf.chrgText.cpMin + iSelCount;
   
if (ttf.chrg.cpMin >= ttf.chrg.cpMax)
     
break;
 
}

 
//display 하지 않는 경우를 대비하여 0으로 초기화
  iMatchesCount
= 0;
 
 
//일치 갯수 전시: BLUEnLIVE
 
if (bMarkOccurrencesDisplayMarkCount) {
   
ZeroMemory(&ttf,sizeof(ttf));

    ttf
.chrg.cpMin = 0;
    ttf
.chrg.cpMax = iTextLenDoc;
    ttf
.lpstrText = pszText;

   
//iMatchesCount = 0;

   
while ((iPos = (int)SendMessage(hwnd, SCI_FINDTEXT,
       
(bMarkOccurrencesMatchCase ? SCFIND_MATCHCASE : 0) | (bMarkOccurrencesMatchWords ? SCFIND_WHOLEWORD : 0),
       
(LPARAM)&ttf)) != -1

       
/* && ++iMatchesCount < 2000 */)
   
{
     
++iMatchesCount;

      ttf
.chrg.cpMin = ttf.chrgText.cpMin + iSelCount;
     
if (ttf.chrg.cpMin >= ttf.chrg.cpMax)
       
break;
   
}

   
UpdateStatusbar();
 
}

 
LocalFree(pszText);
 
return;
}



2016년 6월 4일 토요일 오후 6시 50분 21초 UTC+9, Scintilla 님의 말:

johnsonj

unread,
Jun 4, 2016, 9:58:52 AM6/4/16
to 파이썬문서고
"""현재 창 범위 내에서만 표시를 하기 때문에 스크롤을 하거나 창의 크기를 조절하면 조금만 범위를 벗어나도 표시가 되지 않는군요.""""

"""참고로, 저는 이것과 별개로 Mark Occurance count(int iMatchesCount) 값을 status bar에 전시하는 것을 검토하고 있었는데, 이 기능과 묘하게 충동을 일으키네요.
화면에 표시된 갯수만 카운트합니다... ㅡ.ㅡ;"""

제가 EditMarkAll 조건 처리에 관해서 올리지 않았네요..죄송합니다.
UPDATE_UI 메시지 아래에서 무조건 실행해도 속도에 저하가 없도록 바꾸었습니다.
딱 눈에 보이는 한 화면만 처리합니다. 그러니 원래 의도한대로 입니다.

일단 아래와 같이 해 놓고 테스트해 보시기 바랍니다.
죄송합니다.

        case SCN_UPDATEUI:

          // mark occurrences of text currently selected
          if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL))
            EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);

속도에 별 차이가 없으므로 다음과 같이 해도 별 문제 없습니다.

        case SCN_UPDATEUI:

          // mark occurrences of text currently selected
          EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);

단 키보드로 선택하는 것은 하염없이 기다려야 합니다.
꼭 마우스로 선택해야 합니다.
이 패치의 목적이 대용량 파일을 위한 뷰어라면 목적은 달성한 듯 합니다.

그리고 소스는 연구해 보고 다시 말씀드리겠습니다.

두 변수의 추가는 저도 생각을 해 봤는데..CompleteWord에 꼭 필요할 거 같습니다.
이 함수도 진짜 무슨 대책이 있어야지 너무 비효율적입니다.

어쨌거나 지금은 EditMarkAll() 함수 패치에 몰두....
 

Scintilla

unread,
Jun 4, 2016, 10:25:04 AM6/4/16
to 파이썬문서고
이 수정의 의도는 스크롤만 해도 EditMarkAll()을 호출하는 것 같습니다만,
호출이 되지 않는군요.

코드의 의도는 정확하게 이해했습니다.
단지, 의도 자체가 혼란을 가져올 수 있다는 의미이고, 현재 공개한 정도로 옵션으로 처리하는 정도가 적절할 것 같습니다.


2016년 6월 4일 토요일 오후 10시 58분 52초 UTC+9, johnsonj 님의 말:

johnsonj

unread,
Jun 4, 2016, 10:40:32 AM6/4/16
to 파이썬문서고
백만 라인에서도 전혀 속도 저하가 없습니다. (심지어 워드랩을 활성화해도 그렇습니다)
스크롤할 때마다 정확하게 눈에 보이는 한 화면씩만 처리합니다.

사용자가 전체 문서를 대상으로 하고 싶을지 한 화면만 처리하고 싶을지를 반영하는 옵션이 있는 것은 좋을 거 같습니다.

johnsonj

unread,
Jun 4, 2016, 10:47:04 AM6/4/16
to 파이썬문서고

이 문장 아래가 아닙니다 ->   if (scn->updated & ~(SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL)) {
위에 둡니다.  
 
===============================================================
      case SCN_UPDATEUI:

          // mark occurrences of text currently selected
          if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL))
            EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);

          if (scn->updated & ~(SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL)) {

            UpdateToolbar();
            UpdateStatusbar();


Scintilla

unread,
Jun 4, 2016, 10:54:03 AM6/4/16
to 파이썬문서고
그렇군요.

이렇게 적용해서 거의 정상동작 하는 것 확인했습니다만...

창을 resize 하는 경우는 기대한 대로 동작하지 않네요[...]
창 자체의 크기를 늘리면 스크롤과 달리 표시되지 않습니다...


2016년 6월 4일 토요일 오후 11시 47분 4초 UTC+9, johnsonj 님의 말:

johnsonj

unread,
Jun 4, 2016, 11:00:05 AM6/4/16
to 파이썬문서고
창 크기 마음에도 변경해도 잘 되는데 이상 하네요.. 워드랩을 켜도 잘 됩니다.
워드랩 안키면 무한대로 잘 작동할 거 같습니다.. 진짜 쾌적해요..심지어 키보드도 잘 작동합니다.
그 동안 워드랩 켜고 작동시키느라 정말 힘들었습니다. 워드랩 켜면 랙이 너무 심합니다.

johnsonj

unread,
Jun 4, 2016, 11:04:44 AM6/4/16
to 파이썬문서고

다음 아이디어 참 좋은거 같습니다.
함수 서명을 바꾸는 것을 절대 안되고...
이름처럼 전역 변수로 bMarkOccurenceScreen으로 선언하면 좋을 거 같습니다.
 
 
if (bMarkOccurrencesMarkVisibleOnly) {

    iTextStartLine
= (int)SendMessage(hwnd,SCI_GETFIRSTVISIBLELINE,0,0);
    iTextStartLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextStartLine,0);
    iTextStart
= (int)SendMessage(hwnd,SCI_POSITIONFROMLINE,iTextStartLineDoc, 0);

    iTextEndLine
= iTextStartLine + (int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0);
    iTextEndLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextEndLine,0);
    iTextEnd
= (int)SendMessage(hwnd,SCI_GETLINEENDPOSITION,iTextEndLineDoc, 0);


    ttf
.chrg.cpMin = iTextStart;
    ttf
.chrg.cpMax = iTextEnd;
 
} else {
    ttf
.chrg.cpMin = 0;
    ttf
.chrg.cpMax = iTextLenDoc;

 
}

그리고 제시해 주신 코드에서
앞에 인디케이터 삭제하는 루틴과
선택이 있는지 확인하는 루틴이 빠져 있는데 잘 작동하나요.
어쨋거나 작동은 못시켜 보고 눈으로 해독하는 중입니다.


Scintilla

unread,
Jun 4, 2016, 11:07:13 AM6/4/16
to 파이썬문서고
빠진 코드 없습니다.
"받은 메일 표시" 클릭하면 다 뜹니다.

구글 그룹스 왜 이런 거죠[...]


2016년 6월 5일 일요일 오전 12시 4분 44초 UTC+9, johnsonj 님의 말:
Message has been deleted
Message has been deleted
Message has been deleted

Scintilla

unread,
Jun 4, 2016, 11:17:35 AM6/4/16
to 파이썬문서고
제 PC에서 동작 화면은 첨부와 같습니다.



2016년 6월 5일 일요일 오전 12시 7분 13초 UTC+9, Scintilla 님의 말:
notepad2 mod.mp4
Message has been deleted

Scintilla

unread,
Jun 4, 2016, 11:19:07 AM6/4/16
to 파이썬문서고
반영한 결과도 함께 보냅니다. 같이 확인 부탁드립니다.

확장자를 7에서 7z으로 변경해야 됩니다. (이놈의 구글...)


2016년 6월 5일 일요일 오전 12시 17분 35초 UTC+9, Scintilla 님의 말:
notepad2-mod-977-9.7

johnsonj

unread,
Jun 4, 2016, 11:20:58 AM6/4/16
to 파이썬문서고
아 그렇군요.. 사이에 "받은 메일 표시"가 있었네요.. 긁어 붙여 넣기해서 에디터로 보고 있었는데...실수했습니다..
다시 잘 읽어 보겠습니다.

데모 남깁니다.
https://youtu.be/L1Y_69ntcj4


Scintilla

unread,
Jun 4, 2016, 11:54:13 AM6/4/16
to 파이썬문서고
마침 r980이 릴리즈되어 980에 모든 내용을 반영했습니다.

창 크기 바꿀 때의 동작은 보여주신 상황에선 잘 동작하는데, 제가 보여드린 상황에선 동작하지 않네요.

그리고, EditMarkAll()은 원형을 유지하도록 한번 해보겠습니다.

오늘은 일단 여기까지...



2016년 6월 5일 일요일 오전 12시 20분 58초 UTC+9, johnsonj 님의 말:
notepad2-mod-980.7

johnsonj

unread,
Jun 4, 2016, 12:26:00 PM6/4/16
to 파이썬문서고
제시해 주신 코드로 컴파일 했더니
올려주신 동영상과 똑같이 아래로 크기를 늘렸더니 랜덤하게 작동됨을 확인했습니다.

저의 패치를 반영하여 올려주신 실행파일을 테스트한 결과
제가 올린 동영상과 똑 같이 크기에 즉각 반응함을 확인했습니다.

정식으로 배포된 실행 파일을 확인한 결과..
크기에 제대로 반응은 하나...
너무나 느리게 반응합니다.
배포된 실행 파일은 거의 빈사 상태임....

200만 라인 100메가 이상에서 키보드 마우스와 경쾌하게 잘 작동해야 합니다 (워드랩 끈 상태)

johnsonj

unread,
Jun 4, 2016, 9:38:25 PM6/4/16
to 파이썬문서고
창크기 변환 이벤트에 EditMarkAll이 촉발되지 않음을 확인했습니다.

johnsonj

unread,
Jun 4, 2016, 10:04:51 PM6/4/16
to 파이썬문서고
    case WM_SIZE:
      MsgSize(hwnd,wParam,lParam);
      EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);
      break;

위 이벤트에는 확실하게 반응함을 확인하였습니다.
그러나 다른 방법을 찾아 보아야 할 듯 합니다.

johnsonj

unread,
Jun 5, 2016, 2:28:29 AM6/5/16
to 파이썬문서고
창크기 변환 이벤트 뿐만 아니라 zoom 이벤트에도 대응해야 함을 발견함.
이 문제를 심플하게 해결하는 방법..

  // Target one screen * 10
  iTextEndLine = iTextStartLine + ((int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0) * 10);

그리고
  //일치 갯수 전시: BLUEnLIVE
 
if (bMarkOccurrencesDisplayMarkCount) {
   
ZeroMemory(&ttf,sizeof(ttf));


    ttf
.chrg.cpMin = 0;
    ttf
.chrg.cpMax = iTextLenDoc;
    ttf
.lpstrText = pszText;


일치 갯수를 알기 위해 범위를 문서로 전체로 하는 건,
대용량 파일임이 대상임을 고려할 때 심각한 랙의 원인이 됩니다.
 

Scintilla

unread,
Jun 5, 2016, 1:35:32 PM6/5/16
to 파이썬문서고
1. zoom/resize에 대한 적용

case WM_SIZE: 에 추가하는 것이 맞아보입니다.
iTextEndLine을 이용하는 건 심플한 건 사실이지만, 원하는 것과 다른 결과를 의도적으로 야기할 수 있겠어요.
창의 크기(높이)를 아주 작게 했다가 최대화 한다든가....

2. 일치 개수 세기: 원래로 회귀

일치 개수를 다시 세는 건 기본 취지와 너무 맞지 않아 취소하겠습니다.
랙도 랙이고, 옵션이 2개나 늘어나니 혼란만 가져올 것 같습니다.

대신, 전체를 대상으로 마크 하는 경우에만 개수를 표시하도록 수정했습니다.
2000개가 넘어가면 넘어가는 것만 표시.

즉, 추가로 일치 개수를 더 확인하는 코드는 없습니다.

3. 일치 개수를 2000개와 비교하는 건 오류가 있음

while (++iMatchesCount < 2000)

원래 소스는 위와 같이 되어있는데, 이렇게 하면 1999개까지만 표시합니다.
2000개가 되면 루프 탈출...

그 외에 EditMarkAll()의 인자를 원래 소스로 복원하는 등의 수정을 가한 코드는 아래와 같습니다.
적용한 결과는 첨부를 확인 바랍니다. r980에 올라온 내용을 모두 반영했습니다.

void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase, BOOL bMarkOccurrencesMatchWords)
{
 
struct TextToFind ttf;
 
int iPos;
 
char *pszText;

 
int iTextLenDoc;
 
int iTextStartLine;
 
int iTextEndLine;
 
int iTextStartLineDoc;
 
int iTextEndLineDoc;
 
int iTextStart;
 
int iTextEnd;

 
int iSelStart;
 
int iSelEnd;
 
int iSelCount;

 
 
// extern으로 지정, Edit.c와 Notepad2.c에서 공유

 
 
if (bMarkOccurrencesMarkVisibleOnly) {

    iTextStartLine
= (int)SendMessage(hwnd,SCI_GETFIRSTVISIBLELINE,0,0);
    iTextStartLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextStartLine,0);
    iTextStart
= (int)SendMessage(hwnd,SCI_POSITIONFROMLINE,iTextStartLineDoc, 0);

    iTextEndLine
= iTextStartLine + (int)SendMessage(hwnd,SCI_LINESONSCREEN,0,0);
    iTextEndLineDoc
= (int)SendMessage(hwnd,SCI_DOCLINEFROMVISIBLE,iTextEndLine,0);
    iTextEnd
= (int)SendMessage(hwnd,SCI_GETLINEENDPOSITION,iTextEndLineDoc, 0);

    ttf
.chrg.cpMin = iTextStart;
    ttf
.chrg.cpMax = iTextEnd;
 
} else {

   
//ttf.chrg.cpMin = 0; //ZeroMemory 했으니 불필요

    ttf
.chrg.cpMax = iTextLenDoc;
 
}

  ttf
.lpstrText = pszText;


 
// set style

 
SendMessage(hwnd, SCI_INDICSETALPHA, 1, 100);
 
SendMessage(hwnd, SCI_INDICSETFORE, 1, 0xff << ((iMarkOccurrences - 1) << 3));
 
SendMessage(hwnd, SCI_INDICSETSTYLE, 1, INDIC_ROUNDBOX);

 
//iMatchesCount = 0;
 
while ((iPos = (int)SendMessage(hwnd, SCI_FINDTEXT,
     
(bMarkOccurrencesMatchCase ? SCFIND_MATCHCASE : 0) | (bMarkOccurrencesMatchWords ? SCFIND_WHOLEWORD : 0),
     
(LPARAM)&ttf)) != -1

     
&& ++iMatchesCount <= 2000)

 
{
   
// mark this match
   
SendMessage(hwnd, SCI_INDICATORFILLRANGE, iPos, iSelCount);
    ttf
.chrg.cpMin = ttf.chrgText.cpMin + iSelCount;
   
if (ttf.chrg.cpMin >= ttf.chrg.cpMax)
     
break;
 
}

 
 
// 전체에 대해 표시할 때만 개수 전시
 
if (bMarkOccurrencesMarkVisibleOnly) {
    iMatchesCount
= 0;
 
} else {
   
UpdateStatusbar();
 
}

 
LocalFree(pszText);
 
return;
}








2016년 6월 5일 일요일 오후 3시 28분 29초 UTC+9, johnsonj 님의 말:
notead2-mod-r980.7

Scintilla

unread,
Jun 5, 2016, 3:13:22 PM6/5/16
to 파이썬문서고
구글 그룹스는 소스 올리면 계속 이상하게 동작하네요.
위에서 잘린 부분의 코드는 아래와 같습니다.


  //iMatchesCount = 0;
 
while ((iPos = (int)SendMessage(hwnd, SCI_FINDTEXT,
     
(bMarkOccurrencesMatchCase ? SCFIND_MATCHCASE : 0) | (bMarkOccurrencesMatchWords ? SCFIND_WHOLEWORD : 0),
     
(LPARAM)&ttf)) != -1
     
&& ++iMatchesCount <= 2000)
 
{
   
// mark this match
   
SendMessage(hwnd, SCI_INDICATORFILLRANGE, iPos, iSelCount);
    ttf
.chrg.cpMin = ttf.chrgText.cpMin + iSelCount;
   
if (ttf.chrg.cpMin >= ttf.chrg.cpMax)
     
break;
 
}
 
 
// 전체에 대해 표시할 때만 개수 전시
 
if (bMarkOccurrencesMarkVisibleOnly) {
    iMatchesCount
= 0;
 
} else {
   
UpdateStatusbar();
 
}

 
LocalFree(pszText);
 
return;
}





2016년 6월 6일 월요일 오전 2시 35분 32초 UTC+9, Scintilla 님의 말:

 
while ((iPos = (int)SendMessage(hwnd<span style="color: #660;" class

johnsonj

unread,
Jun 5, 2016, 9:12:40 PM6/5/16
to 파이썬문서고
랙 사라졌습니다.
대용량 파일에서도 키보드와 마우스에 잘 작동합니다 (워드랩 끈 상태).

  // 전체에 대해 표시할 때만 개수 전시
 
if (bMarkOccurrencesMarkVisibleOnly) {
    iMatchesCount
= 0;
 
} else {
   
UpdateStatusbar();
 
}

한화면*10만큼 미리 준비하는 방식이라며 위코드가 좋고..
WM_SIZE 이벤트마다 반응한다면
그냥 UpdateStatusbar() 한 줄이면 더 좋을 거 같습니다.
한 화면 정도면 사용자가 직접 세어볼 수도 있기 때문에 더 안정감이 있을 듯 합니다.

확대와 축소에 (Ctrl ++, Ctrl--)에는 반응하지 않지만..
원래 목적은 충실히 달성한 듯합니다.

수고하셨습니다.

notepa2-blu 의 탄생을 기다리며..

johnsonj

unread,
Jun 5, 2016, 10:54:25 PM6/5/16
to 파이썬문서고
이전에 보여드렸던 동영상입니다.

https://youtu.be/L1Y_69ntcj4

그런데 이걸 보면 분명히 창 사이즈 변환에 응답을 하고 있음을 알 수 있습니다.
이때는  WM_SIZE이벤트도 한화면*10 방법도 전혀 생각하지 않고 있었던 시기였습니다.

다시 구현해 보려고 노력했지만 도저히 구현할 수가 없어서...
미스테리로 남겨 둡니다.

Scintilla

unread,
Jun 6, 2016, 3:56:42 AM6/6/16
to 파이썬문서고
zoom은 case SCN_ZOOM: 에 EditMarkAll()을 추가하면 동작하는군요.
아래와 같이 수정한 것을 현재까지 최종버전으로 배포하겠습니다.

LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam)
{

  LPNMHDR pnmh
= (LPNMHDR)lParam;
 
struct SCNotification* scn = (struct SCNotification*)lParam;

 
switch(pnmh->idFrom)
 
{

   
case IDC_EDIT:

     
switch(pnmh->code)
     
{

       
case SCN_UPDATEUI:

         
// mark occurrences of text currently selected

         
//if (scn->updated & SC_UPDATE_SELECTION)  // BLUEnLIVE

         
if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL))
           
EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);

         
if (scn->updated & ~(SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL)) {

           
UpdateToolbar();
           
UpdateStatusbar();

/////////////////////
// (중간 생략)
/////////////////////

       
case SCN_ZOOM:
         
UpdateLineNumberWidth();
         
EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);    //BLUEnLIVE
         
break;

/////////////////////
// (이하 생략)
/////////////////////






2016년 6월 6일 월요일 오전 11시 54분 25초 UTC+9, johnsonj 님의 말:

johnsonj

unread,
Jun 7, 2016, 9:02:52 PM6/7/16
to 파이썬문서고
컬럼 블록이 지원되는 줄 몰랐다.
캐럿 하나로 컬럼 블록이 될거라는 생각을 하지 못했다.

컬럼 블록은 선택어 강조 기능과 충돌할 것이다.

원본 32BIT에서 크래시 발생..


johnsonj

unread,
Jun 7, 2016, 11:57:55 PM6/7/16
to 파이썬문서고

SCI_FINDTEXT(int searchFlags, Sci_TextToFind *ttf)
이 메시지는 문서 안에서 텍스트를 찾는다. 현재 위치를 사용하거나 이동시키지 않는다. searchFlags 인자는 검색 유형을 제어한다. 여기에는 정규 표현식 검색을 포함한다.

역방향으로 검색해서 앞의 검색 문자열을 찾을 수 있다. 검색 범위에서 시작 위치보다 먼저 끝을 지정하면 된다.

Sci_TextToFind 구조는 Scintilla.h에 정의되어 있다; chrg.cpMinchrg.cpMax를 문서에서 검색할 범위로 설정한다. SCFIND_REGEXP가 이 플래그에 포함되지 않으면, chrg.cpMaxchrg.cpMin보다 작게 설정하여 거꾸로 검색할 수 있다. SCFIND_REGEXP가 포함되면, 검색은 (chrg.cpMaxchrg.cpMin보다 작더라도) 언제나 앞으로 수행된다. Sci_TextToFindlpstrText 멤버를 그 검색 패턴을 보유한 0 종료 텍스트 문자열을 가리키도록 설정한다. 언어에서 Sci_TextToFind를 사용하기가 어렵다면, 대신에 SCI_SEARCHINTARGET을 사용해 보자.

검색에 실패하면 반환 값은 -1이다. 성공하면 발견된 텍스트의 시작 위치를 돌려준다. Sci_TextToFind의 멤버인 chrgText.cpMinchrgText.cpMax는 발견된 텍스트이 시작 위치와 끝 위치로 채워진다.

다음도 참조: SCI_SEARCHINTARGET

Sci_TextToFind
이 구조는 Win32 구조 FINDTEXTEX와 정확하게 같은 모양을 갖도록 정의된다. 예전 코드는 신틸라를 RichEdit 콘트롤로 취급했었다.

struct Sci_TextToFind {
    struct Sci_CharacterRange chrg;     // 검색할 범위;
    char *lpstrText;                    // 검색 패턴 (0 종료)
    struct Sci_CharacterRange chrgText; // 부합한 텍스트의 위치로 반환됨
};


Sci_TextRange 그리고 Sci_CharacterRange
신틸라를 RichEdit으로 취급하는 이전 코드가 작동하도록 이 구조는 정확하게 Win32 TEXTRANGE 그리고 CHARRANGE와 똑같은 모양으로 정의된다.

앞으로 Scintilla가 모든 플랫폼에서 64-비트로 빌드될 때 Sci_PositionCR 유형은 64-비트가 되도록 재정의될 것이다.

struct Sci_CharacterRange {
  Sci_PositionCR cpMin;
  Sci_PositionCR cpMax;
};

struct Sci_TextRange {
  struct Sci_CharacterRange chrg;
  char *lpstrText;
};

====================================================================================================================
새로 안 사실..
1. chrg.cpMaxchrg.cpMin을 비교하는 것은 SCFIND_REGEXP를 반드시 참조해야 한다.
2.
Sci_PositionCR은 현재 32비트로 고정이다.



johnsonj

unread,
Jun 9, 2016, 8:09:18 AM6/9/16
to 파이썬문서고
notepad2-mod 32비트 원본에서도 문제가 있었다..
그런데.. 오늘 다음 보고가 올라 왔다.

https://sourceforge.net/p/scintilla/bugs/1838/

그래서 이거 뭔가 있는 거 같아서 바로 적용함..

void SurfaceGDI::AlphaRectangle(PRectangle rc, int cornerSize, ColourDesired fill, int alphaFill,
...
        if (hbmMem) {
            HBITMAP hbmOld = SelectBitmap(hMemDC, hbmMem);

            DWORD valEmpty = dwordFromBGRA(0,0,0,0);
            DWORD valFill = dwordFromBGRA(
                static_cast<byte>((fill.GetBlue() * alphaFill / 255) & 0xFF),
                static_cast<byte>((fill.GetGreen() * alphaFill / 255) & 0xFF),
                static_cast<byte>((fill.GetRed() * alphaFill / 255) & 0xFF),
                //static_cast<byte>(GetBValue(fill.AsLong()) * alphaFill / 255),
                //static_cast<byte>(GetGValue(fill.AsLong()) * alphaFill / 255),
                //static_cast<byte>(GetRValue(fill.AsLong()) * alphaFill / 255),
                static_cast<byte>(alphaFill));
            DWORD valOutline = dwordFromBGRA(
                static_cast<byte>((outline.GetBlue() * alphaOutline / 255) & 0xFF),
                static_cast<byte>((outline.GetGreen() * alphaOutline / 255) & 0xFF),
                static_cast<byte>((outline.GetRed() * alphaOutline / 255) & 0xFF),
                //static_cast<byte>(GetBValue(outline.AsLong()) * alphaOutline / 255),
                //static_cast<byte>(GetGValue(outline.AsLong()) * alphaOutline / 255),
                //static_cast<byte>(GetRValue(outline.AsLong()) * alphaOutline / 255),
                static_cast<byte>(alphaOutline));
...

32비트 원본에서 버그가 사라짐..
64비트는 테스트 못해 봄.

johnsonj

unread,
Jun 9, 2016, 9:46:15 AM6/9/16
to 파이썬문서고
컬럼 블록 모드 에러 발생 빈도를 정리하면....

32비트 원본 >32비트 수정본> 32비트 한글본

어쨌거나 편집은 고사하고 단순히 컬럼 블록을 이리 저리 잡아 보는 것만으로도 크래시 발생....
어떻게 캐럿 하나로 컬럼 블럭을 잡는 것인가?


 

johnsonj

unread,
Jun 10, 2016, 8:39:44 AM6/10/16
to 파이썬문서고
 case SCN_UPDATEUI: 에 대하여..
이 아래에서는 자기 자신에 대하여 변경이 있으면 자기 자신을 다시 참조하므로 주의해야 한다.
여기에 EditMarkAll() 과 MatchBraces는 자기 자신을 변경하므로 요주의 대상이다.
멀티 캐럿 상태에서는 절대로 호출을 허용하면 안된다.
컬럼 블록에서도 호출되면 안된다.

notepad2.c 파일에서
...

        case SCN_UPDATEUI:

          // mark occurrences of text currently selected
          if (scn->updated & (SC_UPDATE_SELECTION | SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL))
            EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesMatchCase, bMarkOccurrencesMatchWords);

          if (scn->updated & ~(SC_UPDATE_V_SCROLL | SC_UPDATE_H_SCROLL)) {

            UpdateToolbar();
            UpdateStatusbar();

            // Invalidate invalid selections
            // #pragma message("TODO: Remove check for invalid selections once fixed in Scintilla")
            /*if (SendMessage(hwndEdit,SCI_GETSELECTIONS,0,0) > 1 &&
                SendMessage(hwndEdit,SCI_GETSELECTIONMODE,0,0) != SC_SEL_RECTANGLE) {
              int iCurPos = (int)SendMessage(hwndEdit,SCI_GETCURRENTPOS,0,0);
              SendMessage(hwndEdit,WM_CANCELMODE,0,0);
              SendMessage(hwndEdit,SCI_CLEARSELECTIONS,0,0);
              SendMessage(hwndEdit,SCI_SETSELECTION,(WPARAM)iCurPos,(LPARAM)iCurPos);
            }*/

            // Brace Match
            if (bMatchBraces &&
+                (SendMessage(hwndEdit,SCI_GETSELECTIONS,0,0) == 1) &&
+                (SendMessage(hwndEdit,SCI_GETSELECTIONMODE,0,0) == SC_SEL_STREAM) &&
+                (SendMessage(hwndEdit,SCI_GETANCHOR,0,0) == SendMessage(hwndEdit,SCI_GETCURRENTPOS,0,0)))
            {
....

edit.c에서


void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesMatchCase, BOOL bMarkOccurrencesMatchWords)
{
...

  // if nothing selected or multiple lines are selected exit
  if (iSelCount == 0 ||
      (int)SendMessage(hwnd, SCI_LINEFROMPOSITION, iSelStart, 0) !=
      (int)SendMessage(hwnd, SCI_LINEFROMPOSITION, iSelEnd, 0))
    return;

+  if ((SendMessage(hwnd,SCI_GETSELECTIONS,0,0) > 1) ||
+     (SendMessage(hwnd,SCI_GETSELECTIONMODE,0,0) != SC_SEL_STREAM))
+    return;
....

일단 격렬하게 막고 테스트....

Scintilla

unread,
Jun 10, 2016, 5:44:15 PM6/10/16
to 파이썬문서고
엄지척!

계속 수고 부탁드립니다!!


2016년 6월 10일 금요일 오후 9시 39분 44초 UTC+9, johnsonj 님의 말:

johnsonj

unread,
Jun 12, 2016, 6:06:24 AM6/12/16
to 파이썬문서고
32비트 수정본에서는 아직까지 에러 없음..
64비트는 원본에서 선택어 강조와 짝괄호 강조를 끄고 테스트 실시..
격렬한 난타에 아직까지 충돌 없음....

어쩌면 또 문제가 발생할지도 모든다.
계속 주시할 일이다...
길게 가자.


Reply all
Reply to author
Forward
0 new messages