이 블로그는 방문자 통계를 위해 티스토리 기본 기능과 Woopra를 사용합니다. 원하지 않으신다면 사용하시는 웹 브라우저에 내장된 DNT 헤더를 켜고, JavaScript를 끄셔도 무방합니다.
이 블로그 방문자의 약 60%는 네이버 검색을 사용하십니다. 을 이용하시면 더 유용한 정보를 쉽게 얻게 되실 수도 있습니다. [mediatoday]
« 2020/8 »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
블로그 이미지
제가 주제인 블로그... 그냥 주제 없는 블로그입니다. 전공 분야나 예전 관심 분야 등등에 관한 글이 우선입니다만, 두어 문단을 넘길 만한 글이라면 대강 정리해 기록합니다. 학부생입니다. 트위터에서 볼 수 있습니다. http://aurynj.net/ 어­리


블루앤라이브 님의 Notepad2 4.2.25 패치 중 Notepad2-mod에서 차용된 것이 있으니,
Notepad2 4.2.25 패치 준비#4: Mark Occurrences 기능 추가
링크된 블로그 글에도 있다시피, 다음과 같이 선택된 부분과 일치하는 단어를 강조해 주는 기능이다.
(Notepad2 4,2,25 original w/ Scintilla 2.25 + 'Mark Occurrences' original)
이 기능을 조금 바꾸어, 아래와 같이 대소문자에 무관하게 동작할 수 있도록 했다.
어셈블리어 소스 코드라든지, 같은 단어가 대소문자를 달리해 나타나는 보통의 글 등에서 쓸 수 있다.
물론 메뉴에서 적용 여부를 선택 가능하며, 기본값은 대소문자 구분이다.
참고로, 대부분의 언어에서 식별자는 대소문자를 구분하기 때문에, 이를 빼 버리는 건 미친 짓이다.



블루앤라이브 님과 같은 순서로 설명하며, 기존 패치와 달라진 줄을 강조했다.

1. resource.h

적당한 위치에 아래와 같은 내용을 추가한다. 40445~40449가 사용 중이면 적당히 수정한다.

#define IDM_VIEW_MARKOCCURRENCES_CASE   40445
#define IDM_VIEW_MARKOCCURRENCES_RED    40446
#define IDM_VIEW_MARKOCCURRENCES_GREEN  40447
#define IDM_VIEW_MARKOCCURRENCES_BLUE   40448
#define IDM_VIEW_MARKOCCURRENCES_OFF    40449
* 적당한 위치: 번호 순으로 정렬되어 있으므로 번호 순서에 맞게 넣어야 위험하지 않다.
* 적당히 수정: 사용되지 않는 번호.


2. Notepad2.rc

다음과 같은 내용을 찾아

MENUITEM "Selection &Margin\tCtrl+Shift+M", IDM_VIEW_MARGIN
바로 아래에 다음 내용을 추가한다.
  POPUP "Mar&k Occurrences"
  BEGIN
      MENUITEM "Matc&h case",                 IDM_VIEW_MARKOCCURRENCES_CASE
      MENUITEM SEPARATOR
      MENUITEM "&Red",                        IDM_VIEW_MARKOCCURRENCES_RED
      MENUITEM "&Green",                      IDM_VIEW_MARKOCCURRENCES_GREEN
      MENUITEM "&Blue",                       IDM_VIEW_MARKOCCURRENCES_BLUE
      MENUITEM "&Off",                        IDM_VIEW_MARKOCCURRENCES_OFF
  END


3. Edit.h

다음과 같은 내용을 적당한 위치에 추가한다.

void  EditMarkAll(HWND,int,BOOL);


4. Edit.c

다음과 같은 내용을 적당한 위치에 추가한다.

//=============================================================================
//
//  EditMarkAll()
//  Mark all occurrences of the text currently selected (by Aleksandar Lekov / slightly modified by Un-i-que)
//
void EditMarkAll(HWND hwnd, int iMarkOccurrences, BOOL bMarkOccurrencesCaseSensitive)
{
  struct TextToFind ttf;
  int iPos;
  char  *pszText;
  int iTextLen;
  int iSelStart;
  int iSelEnd;
  int iSelCount;
  int iMatchesCount;
 
  // feature is off
  if (!iMarkOccurrences)
  {
      return;
  }
 
  iTextLen = (int)SendMessage(hwnd,SCI_GETLENGTH,0,0);
 
  // get current selection
  iSelStart = (int)SendMessage(hwnd,SCI_GETSELECTIONSTART,0,0);
  iSelEnd = (int)SendMessage(hwnd,SCI_GETSELECTIONEND,0,0);
  iSelCount = iSelEnd - iSelStart;
 
  // clear existing indicator
  SendMessage(hwnd, SCI_SETINDICATORCURRENT, 1, 0);
  SendMessage(hwnd, SCI_INDICATORCLEARRANGE, 0, iTextLen);
 
  // 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);
 
  ZeroMemory(&ttf,sizeof(ttf));
 
  ttf.chrg.cpMin = 0;
  ttf.chrg.cpMax = iTextLen;
  ttf.lpstrText = pszText;
 
  // set style, green should be greener not to confuse with bookmarks' style
  SendMessage(hwnd, SCI_INDICSETALPHA, 1, iMarkOccurrences == 2 ? 100 : 30);
  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, (bMarkOccurrencesCaseSensitive ? (SCFIND_MATCHCASE | SCFIND_WHOLEWORD) : SCFIND_WHOLEWORD), (LPARAM)&ttf)) != -1
      && ++iMatchesCount < 1000)
  {
    // 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에 넘기는 인자가 bMarkOccurrencesCaseSensitive에 따라 바뀐다.


5. Notepad2.c

소스의 앞부분, 다른 전역변수들과 함께 다음 두 변수 선언을 추가한다.

int       iMarkOccurrences;
BOOL      bMarkOccurrencesCaseSensitive;

void MsgInitMenu(HWND hwnd,WPARAM wParam,LPARAM lParam) 내의 다음 두 줄 사이에,
  CheckCmd(hmenu,IDM_VIEW_MARGIN,bShowSelectionMargin);
  CheckCmd(hmenu,IDM_VIEW_SHOWWHITESPACE,bViewWhiteSpace);
다음과 같은 내용을 추가한다.
  CheckCmd(hmenu,IDM_VIEW_MARKOCCURRENCES_CASE,bMarkOccurrencesCaseSensitive);
  switch (iMarkOccurrences)
  {
    case 0: i = IDM_VIEW_MARKOCCURRENCES_OFF;break;
    case 1: i = IDM_VIEW_MARKOCCURRENCES_RED;break;
    case 2: i = IDM_VIEW_MARKOCCURRENCES_GREEN;break;
    case 3: i = IDM_VIEW_MARKOCCURRENCES_BLUE;break;
  }
  CheckMenuRadioItem(hmenu,IDM_VIEW_MARKOCCURRENCES_RED,IDM_VIEW_MARKOCCURRENCES_OFF,i,MF_BYCOMMAND);

LRESULT MsgCommand(HWND hwnd,WPARAM wParam,LPARAM lParam) 내의 case IDM_VIEW_MARGIN: ~ break;과 case IDM_VIEW_SHOWWHITESPACE: ~ break; 사이에 다음과 같은 내용을 추가한다.
    case IDM_VIEW_MARKOCCURRENCES_CASE:
      bMarkOccurrencesCaseSensitive = (bMarkOccurrencesCaseSensitive) ? FALSE : TRUE;
      // clear all marks and remark with changed case sensitivity
      SendMessage(hwndEdit, SCI_SETINDICATORCURRENT, 1, 0);
      SendMessage(hwndEdit, SCI_INDICATORCLEARRANGE, 0, (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0));
      EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesCaseSensitive);
      break;
    
    case IDM_VIEW_MARKOCCURRENCES_OFF:
      iMarkOccurrences = 0;
      // clear all marks
      SendMessage(hwndEdit, SCI_SETINDICATORCURRENT, 1, 0);
      SendMessage(hwndEdit, SCI_INDICATORCLEARRANGE, 0, (int)SendMessage(hwndEdit,SCI_GETLENGTH,0,0));
      break;
 
    case IDM_VIEW_MARKOCCURRENCES_RED:
      iMarkOccurrences = 1;
      EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesCaseSensitive);
      break;
 
    case IDM_VIEW_MARKOCCURRENCES_GREEN:
      iMarkOccurrences = 2;
      EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesCaseSensitive);
      break;
 
    case IDM_VIEW_MARKOCCURRENCES_BLUE:
      iMarkOccurrences = 3;
      EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesCaseSensitive);
      break;

LRESULT MsgNotify(HWND hwnd,WPARAM wParam,LPARAM lParam) 내에서 다음 내용을 찾아서,
// Brace Match
if (bMatchBraces)
이 바로 위에 다음과 같은 내용을 추가한다.
// mark occurrences of text currently selected
EditMarkAll(hwndEdit, iMarkOccurrences, bMarkOccurrencesCaseSensitive);

void LoadSettings() 내에서 다음 내용을 찾아서,
bViewWhiteSpace = IniSectionGetInt(pIniSection,L"ViewWhiteSpace",0);
이 바로 위에 다음과 같은 내용을 추가한다.
  bMarkOccurrencesCaseSensitive = IniSectionGetInt(pIniSection,L"MarkOccurrencesCaseSensitively",1);
  if (bMarkOccurrencesCaseSensitive) bMarkOccurrencesCaseSensitive = 1;

  iMarkOccurrences = IniSectionGetInt(pIniSection,L"MarkOccurrences",3);

마지막으로 void SaveSettings() 내의 다음 두 줄 사이에,
  IniSectionSetInt(pIniSection,L"ShowLineNumbers",bShowLineNumbers);
  IniSectionSetInt(pIniSection,L"ViewWhiteSpace",bViewWhiteSpace);
다음 두 줄을 추가한다.
  IniSectionSetInt(pIniSection,L"MarkOccurrencesCaseSensitively",bMarkOccurrencesCaseSensitive);
  IniSectionSetInt(pIniSection,L"MarkOccurrences",iMarkOccurrences);


시험적으로 구상한 패치 소스 패치(!)였지만 놀랍게도 성공적으로 작동했다.(?)
나도 이제 소스 패치 변태야 엉엉 ㅠㅠ 하라는 과제는 안 하고

앞으로 몇 가지 패치를 더 만들어 낼지도 모르겠습니다. :)


다음 글. 한글은 전영역에서 찾는다든지 하는 옵션이 추가되어 있는데 정신 건강에 좋지는 않습니다.

댓글을 달아 주세요

  1. 타르토 2011.05.25 01:53  댓글주소  수정/삭제  댓글쓰기

    과제하세요 헤헤

  2. BLUEnLIVE 2011.08.09 23:47 신고  댓글주소  수정/삭제  댓글쓰기

    오옷! 이런 깨알같은!
    저도 슬쩍 반영해야겠습니다. ㅎㅎㅎ

  3. BLUEnLIVE 2011.08.14 10:08 신고  댓글주소  수정/삭제  댓글쓰기

    참, 얼마전 원작자인 Florian 씨와 잠시 메일을 주고받았는데,
    Notepad2에는 치명적인 문제가 있습니다.

    모든 기능이 SBCS의 글자폭을 기준으로 만들어졌다는 점입니다.
    이건 물론 Scintilla 라이브러리 자체의 문제입니다.
    이 문제를 시스템 전체에서 해결할 방법을 고민하고 있다고 합니다.

    대략 필요한 것이
    1. 어떤 어떤 기능들이 글자폭의 영향을 받는가
    2. 글자폭을 일괄적으로 파악할 방법이 있는가 (물론, 없습니다. 많은 토론과 검색을 했습니다)

    등입니다. 혹시 생각나시는 게 있으면 알려주시면 안 잡아먹겠습… (응?)

    • 어­리 2011.08.14 23:28 신고  댓글주소  수정/삭제

      지난번 양쪽 정렬 문제로 시작된 토론이 아직도[?] 이어지나 보군요. 한 가지 생각나는 건 text mode를 insert가 아닌 overwrite로 설정했을 때 Scintilla가 처리해 주는 글자 밑줄인데... 출현 강조 처리도 글자폭 신경쓸 것 없이 Scintilla에서 처리해 주고요. Scintilla 내부에서 쓰이는 함수가 있지 않을까요 ㅠㅠ / 근데 SBCS 기준으로 만들어져서 문제가 되는 기능이 뭔가요? 제가 패치 2번(...)을 하면서 느낀 건 인코딩 지원이 안 되는 게 사람 돌게 만들 수 있다는 것이었지만요...

  4. BLUEnLIVE 2011.08.15 00:44 신고  댓글주소  수정/삭제  댓글쓰기

    글자 폭을 기준으로 하는 기능들은 전부입니다.
    기능 자체는 동작하지만, 정확하지 않습니다.

    문제는, 고정폭 글꼴 기준으로 글자의 폭을 정확하게 지정할 수 있는 기준이 없다는 겁니다.
    http://blogs.msdn.com/b/michkap/archive/2007/04/23/2250029.aspx