Notepad2 4.2.25 패치 준비#1: 코드 폴딩 추가

Notepad2 4.1.24까지는 코드 폴딩 기능을 위해 Kai Liu 님의 패치를 적용했다.
하지만, 4.2.25에서는 약간 다르게 패치해야 된다.

패치 대상은 아래와 같다.

1. Editor.cxx (scintilla\src\)

KeyDefault() 함수를 찾는다. 아래와 같은 모습이다.

int Editor::KeyDefault(int, int) {
    return 0;
}

이것을 통째로 아래와 같이 바꾼다.

/* notepad2-mod custom code start */
int Editor::KeyDefault(int key, int modifiers) {
    // SCN_KEY is normally not sent for key codes >= 256 or on Windows; but this
    // notification is needed for the code folding keyboard commands, and this
    // is by far the best way to do this (making an accelerator for every
    // possible hotkey combo--remember the Ctrl modifier for child nodes--is
    // unwieldy, and manually handling the Windows messages would mean that we
    // have to duplicate all the processing work that Scintilla does
    if (modifiers & SCI_ALT && key >= SCK_DOWN && key <= SCK_RIGHT)
    {
        SCNotification scn = {0};
        scn.nmhdr.code = SCN_KEY;
        scn.ch = key;
        scn.modifiers = modifiers;
        NotifyParent(scn);
    }
/* notepad2-mod custom code end */
    return 0;
}


2. SciCall.h (src\)

이 파일은 원래 소스에는 없다. 새로 만드는 것이다.
아래와 같은 코드를 편집기로 입력해서 SciCall.h라는 파일명으로 저장한다.


다음으로, 아래와 같은 #include 문을 Styles.c, Notepad2.c에 추가한다.
두 파일은 모두 src 폴더에 있다.

또한, 프로젝트 파일에도 이 내용을 추가해야 된다.

#include "SciCall.h"


3. Styles.c (src\)

Style_SetLexer() 함수에서 아래와 같은 내용을 찾아서

// Add KeyWord Lists
for (i = 0; i < 9; i++)

그 앞에 아래와 같은 내용을 추가한다.

// Code folding
SciCall_SetProperty("fold", "1");
SciCall_SetProperty("fold.compact", "0");
SciCall_SetProperty("fold.comment", "1");
SciCall_SetProperty("fold.html", "1");
SciCall_SetProperty("fold.preprocessor", "1");


같은 함수 내에서 아래와 같은 부분을 찾아서

if (SendMessage(hwnd,SCI_GETINDENTATIONGUIDES,0,0) != SC_IV_NONE)
  Style_SetIndentGuides(hwnd,TRUE);

그 앞에 아래와 같은 내용을 추가한다.

{ // set folding style; braces are for scoping only
  static const int iMarkerIDs[] =
  {
    SC_MARKNUM_FOLDEROPEN,
    SC_MARKNUM_FOLDER,
    SC_MARKNUM_FOLDERSUB,
    SC_MARKNUM_FOLDERTAIL,
    SC_MARKNUM_FOLDEREND,
    SC_MARKNUM_FOLDEROPENMID,
    SC_MARKNUM_FOLDERMIDTAIL
  };

  int i;

  COLORREF clrFore = SciCall_StyleGetFore(STYLE_DEFAULT);
  COLORREF clrBack = SciCall_StyleGetBack(STYLE_DEFAULT);

  SciCall_SetFoldMarginColour(TRUE, clrBack);
  SciCall_SetFoldMarginHiColour(TRUE, clrBack);

  // Set marker color to the average of clrFore and clrBack
  clrFore = (((clrFore & 0xFF0000) + (clrBack & 0xFF0000)) >> 1 & 0xFF0000) |
            (((clrFore & 0x00FF00) + (clrBack & 0x00FF00)) >> 1 & 0x00FF00) |
            (((clrFore & 0x0000FF) + (clrBack & 0x0000FF)) >> 1 & 0x0000FF);

  // Rounding hack for pure white against pure black
  if (clrFore == 0x7F7F7F) clrFore = 0x808080;

  for (i = 0; i < COUNTOF(iMarkerIDs); ++i)
  {
    SciCall_MarkerSetBack(iMarkerIDs[i], clrFore);
    SciCall_MarkerSetFore(iMarkerIDs[i], clrBack);
  }
} // end set folding style


4. Notepad2.c (src\)

아래와 같은 내용을 찾아서

#define NUMTOOLBITMAPS  23
#define NUMINITIALTOOLS 24

이 내용을 이렇게 수정한다.

#define NUMTOOLBITMAPS  24
#define NUMINITIALTOOLS 24
#define MARGIN_FOLD_INDEX 2


다음으로 아래와 같은 내용을 찾아서

{22,IDT_FILE_ADDTOFAV,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0} };

내용을 아래와 같이 수정한다.

{22,IDT_FILE_ADDTOFAV,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0},
{23,IDT_VIEW_TOGGLEFOLDS,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0} };


다음으로 선언부에다 다음과 같은 내용을 추가한다. (C++가 아닌 C 코드라는 점을 잊지말 것)

BOOL      bShowCodeFolding;
HANDLE g_hScintilla;


다음으로, 아래와 같은 내용을 찾아서

//=============================================================================
//
//  WinMain()

그 앞에 아래와 같은 내용을 추가한다.



다음으로 아래와 같은 내용을 찾아서

// Setup edit control
hwndEdit = EditCreate(hwnd);

그 뒤에 다음과 같은 내용을 추가한다.

InitScintillaHandle(hwndEdit);


또, 아래와 같은 내용을 찾아서

// Nonprinting characters
SendMessage(hwndEdit,SCI_SETVIEWWS,(bViewWhiteSpace)?SCWS_VISIBLEALWAYS:SCWS_INVISIBLE,0);

그 앞에 아래와 같은 내용을 추가한다.

// Code folding
SciCall_SetMarginType(MARGIN_FOLD_INDEX, SC_MARGIN_SYMBOL);
SciCall_SetMarginMask(MARGIN_FOLD_INDEX, SC_MASK_FOLDERS);
SciCall_SetMarginWidth(MARGIN_FOLD_INDEX, (bShowCodeFolding) ? 11 : 0);
SciCall_SetMarginSensitive(MARGIN_FOLD_INDEX, TRUE);
SciCall_MarkerDefine(SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS);
SciCall_MarkerDefine(SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS);
SciCall_MarkerDefine(SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE);
SciCall_MarkerDefine(SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER);
SciCall_MarkerDefine(SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED);
SciCall_MarkerDefine(SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED);
SciCall_MarkerDefine(SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER);
SciCall_SetFoldFlags(16);


다음으로 아래와 같은 내용을 찾아서

CheckCmd(hmenu,IDM_VIEW_MARGIN,bShowSelectionMargin);

그 뒤에 아래와 같은 내용을 추가한다.

CheckCmd(hmenu,IDM_VIEW_FOLDING,bShowCodeFolding);
EnableCmd(hmenu,IDM_VIEW_TOGGLEFOLDS,bShowCodeFolding);


다음으로 아래와 같은 내용을 찾아서

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

  switch(LOWORD(wParam))
  {

그 뒤에 아래와 같은 case문 3개를 추가한다.

case IDM_VIEW_FOLDING:
  bShowCodeFolding = (bShowCodeFolding) ? FALSE : TRUE;
  SciCall_SetMarginWidth(MARGIN_FOLD_INDEX, (bShowCodeFolding) ? 11 : 0);
  UpdateToolbar();
  if (!bShowCodeFolding)
    FoldToggleAll(EXPAND);
  break;

case IDM_VIEW_TOGGLEFOLDS:
  FoldToggleAll(SNIFF);
  break;

case IDT_VIEW_TOGGLEFOLDS:
if (IsCmdEnabled(hwnd,IDM_VIEW_TOGGLEFOLDS))
SendMessage(hwnd,WM_COMMAND,MAKELONG(IDM_VIEW_TOGGLEFOLDS,1),0);
else
MessageBeep(0);
break;


다음으로 아래와 같은 내용을 찾아서

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문 2개를 추가한다.

case SCN_MARGINCLICK:
if (scn->margin == MARGIN_FOLD_INDEX)
FoldClick(SciCall_LineFromPosition(scn->position), scn->modifiers);
break;

case SCN_KEY:
// Also see the corresponding patch in scintilla\src\Editor.cxx
FoldAltArrow(scn->ch, scn->modifiers);
break;


다음으로 아래와 같은 내용을 찾아서

bShowLineNumbers = IniSectionGetInt(pIniSection,L"ShowLineNumbers",1);
if (bShowLineNumbers) bShowLineNumbers = 1;

그 뒤에 아래와 같은 내용을 추가한다.

bShowCodeFolding = IniSectionGetInt(pIniSection,L"ShowCodeFolding",1);
if (bShowCodeFolding) bShowCodeFolding = 1;


다음으로 아래와 같은 내용을 찾아서

IniSectionSetInt(pIniSection,L"ShowLineNumbers",bShowLineNumbers);

그 뒤에 아래와 같은 내용을 추가한다.

IniSectionSetInt(pIniSection,L"ShowCodeFolding",bShowCodeFolding);


다음으로 아래와 같은 내용을 찾아서

EnableTool(IDT_EDIT_CLEAR,i /*&& !bReadOnly*/);

그 뒤에 아래와 같은 내용을 추가한다.

EnableTool(IDT_VIEW_TOGGLEFOLDS,bShowCodeFolding);


5. Notepad2.rc (src\)

아래와 같은 내용을 찾아서

MENUITEM "Line &Numbers\tCtrl+Shift+N", IDM_VIEW_LINENUMBERS
MENUITEM "Selection &Margin\tCtrl+Shift+M", IDM_VIEW_MARGIN
MENUITEM SEPARATOR

그 뒤에 아래와 같은 내용을 추가한다.

MENUITEM "Code &Folding\tCtrl+Shift+Alt+F", IDM_VIEW_FOLDING
MENUITEM "&Toggle All Folds\tCtrl+Shift+F", IDM_VIEW_TOGGLEFOLDS
MENUITEM SEPARATOR


그리고, 아래와 같은 내용을 찾아서

"E",            IDM_EDIT_URLENCODE,     VIRTKEY, SHIFT, CONTROL, 
NOINVERT
"F", IDM_EDIT_FIND, VIRTKEY, CONTROL, NOINVERT

그 뒤에 아래와 같은 내용을 추가한다.

"F",            IDM_VIEW_FOLDING,       VIRTKEY, SHIFT, CONTROL, ALT, 
NOINVERT
"F", IDM_VIEW_TOGGLEFOLDS, VIRTKEY, SHIFT, CONTROL,
NOINVERT


마지막으로 아래와 같은 내용을 찾아서

IDT_FILE_OPENFAV        "Favorites"
IDT_FILE_ADDTOFAV "Add to Favorites"

그 뒤에 아래와 같은 내용을 추가한다.

IDT_VIEW_TOGGLEFOLDS    "Toggle All Folds"


6. resource.h (src\)

이 파일은 #define 문으로만 구성되어있다.
여기에 아래와 같은 내용을 추가한다.
추가할 때 파일 마지막 부근의 내용도 필요에 따라 수정한다.

#define IDM_VIEW_FOLDING                40445
#define IDM_VIEW_TOGGLEFOLDS            40446
#define IDT_VIEW_TOGGLEFOLDS            40723


7. Toolbar.bmp (res\)

Toolbar.bmp의 크기는 368x16이다.
이 이미지의 맨 오른쪽에 16x16의 코드 폴딩용 아이콘을 하나 추가해서 384x16으로 만들어야 한다.