Scintilla icon SciTE 확장 인터페이스

목적

SciTE 편집기를 개선하고 싶으면서도, 여전히 새로운 SciTE 특징을 맛보고 싶다. 게임 개발 같은 특별한 환경을 위하여 설계된 편집기의 경우가 그럴텐데, 스크립트 능력을 SciTE 안에 넣거나 SciTE를 IPC 메커니즘 같은 다른 프로세스에서 제어할 수 있다.

두 가지 예제 확장이 있다. SciTE 감독관 인터페이스는 SciTE를 프로젝트 관리자 같은 외부 어플리케이션으로 제어할 수 있다. SciTE 루아 스크립트 확장은 루아 스크립트 언어를 SciTE 안으로 통합해 넣어서, 그 확장 인터페이스를 사용하여 제어한다.

확장 인터페이스

bool Initialise(ExtensionAPI *host_);
bool Finalise();
bool Clear();
bool Load(const char *filename);
bool InitBuffer(int index);
bool ActivateBuffer(int index);
bool RemoveBuffer(int index);
bool OnOpen(const char *path);
bool OnSwitchFile(const char *path);
bool OnBeforeSave(const char *path);
bool OnSave(const char *path);
bool OnChar(char ch);
bool OnExecute(const char *s);
bool OnSavePointReached();
bool OnSavePointLeft();
bool OnStyle(unsigned int, int, int, Accessor *);
bool OnDoubleClick();
bool OnUpdateUI();
bool OnMarginClick();
bool OnMacro(const char *, const char *);
bool SendProperty(const char *);
bool OnKey(int keyval, int modifiers);
bool OnDwellStart(int pos, const char *word);
bool OnClose(const char *filename);

확장은 scite/src/Extender.h에 정의된 확장 인터페이스를 구현해야 한다. 앞의 네 가지 메쏘드만 구현되면 된다. 그렇지만 구현은 그냥 거짓을 돌려주는 것처럼 단순하다. 다른 메쏘드들은 기본으로 구현이 비어 있다. 나중에 이 인터페이스에 추가된 메쏘드들은 기존의 확장들이 계속 컴파일될 수 있도록 기본을 구현하여야 한다.

각 메쏘드는 그 메쏘드가 모든 처리를 완료했고 그래서 추가 처리가 필요하지 않다고 알려주는 불리언 값을 돌려준다. 보통, 처리가 더 남아 있음을 알리기 위해 false가 반환된다.

확장은 Initialise 메쏘드와 Finalise 메쏘드를 사용하여 자원을 할당하고 해제해야 한다. ExtensionAPI 포인터는 Initialise 메쏘드에 저장되어야 한다. 그래야 그 확장이 다시 SciTE와 통신할 수 있다.

Clear 메쏘드와 Load 메쏘드는 파일이 열릴 때 스크립트와 같은 자원을 적재하는데 필요한 확장을 지원하는데 사용된다. SciTE에서 파일이 열리면, 먼저 그 확장에게 앞의 파일과 연관된 데이터를 Clear 메쏘드로 청소하라고 요구한다. 다음 SciTE는 그 파일 이름에 부합하는 "extension"이라고 부르는 특성을 점검한다. 그래서 x.cpp이라면, extension.*.cpp를 찾는다. 이 이름을 가진 파일이 표준 특성 파일 위치에서 검색되고 발견되면 그 경로를 인자로 하여 Load가 호출된다.

InitBuffer, ActivateBuffer, 그리고 RemoveBuffer 메쏘드는 필수적인 고리를 제공한다. 그래서 확장이 데이터를 특정한 버퍼와 연관짓는 메커니즘을 가질 수 있다. SciTE 자체가 각 버퍼에 대하여 monospace 설정을 기억하는 것과 비슷한 메커니즘이다. InitBuffer는 새로 문서가 버퍼에 열릴 때마다 호출된다. 버퍼는 새로 할당된 것일 수도 있고, 아니면 최대 버퍼에 도달했다면 재사용될 수도 있다. 버퍼가 초기화되면, 활성 버퍼가 된다. 그 다음부터는 사용자가 또다른 버퍼로 전환할 때마다 ActivateBuffer 메쏘드가 호출된다. RemoveBuffer는 기본의 버퍼가 닫히면 호출된다. 그 다음부터, 제거된 버퍼 다음에 오는 버퍼의 인덱스는 하나씩 줄어든다. RemoveBuffer 다음, 확장은 InitBuffer 또는 ActivateBuffer를 받아서 새로운 활성 버퍼를 확립한다.

OnExecute 메쏘드는 확장 명령어가 실행될 때만 호출된다. 특성에 subsystem 3으로 표현된다.

OnBeforeSave는 파일을 저장하기 전에 호출된다. 확장은 파일 저장을 스스로 구현할 수도 있고 참값을 돌려주어 기본 파일 저장 코드가 실행되는 것을 막을 수도 있다.

다른 메쏘드들은 SciTE에서 이벤트가 일어날 때 호출되어서 확장은 그런 이벤트에 반응할 수 있다.

ExtensionAPI 인터페이스.

enum Pane { paneEditor=1, paneOutput=2, paneFindOutput=3 };
sptr_t Send(Pane p, unsigned int msg, uptr_t wParam=0, sptr_t lParam=0);
std::string Range(Pane p, int start, int end);
void Remove(Pane p, int start, int end);
void Insert(Pane p, int pos, const char *s);
void Trace(const char *s);
std::string Property(const char *key);
void SetProperty(const char *key, const char *val);
uptr_t GetInstance();
void ShutDown();
void Perform(const char *actions);
void DoMenuCommand(int cmdID);
void UpdateStatusBar(bool bUpdateSlowData);

확장은 이런 인터페이스를 사용하여 SciTE를 역호출할 수 있다. SciTE의 기능에 간단하게 접근하는 방법이다.

보통의 편집판과 출력판은 물론이고, 이 인터페이스는 앞으로 세번째 판이 사용될 때를 대비한다. 이 판은 검색 명령어의 출력에 사용될 것이며 현재는 출력판에 짝짓기 되어 있다.

Send는 각 판에 포함된 Scintilla 콘트롤에 메시지를 보낸다.

Range는 그 판에서 텍스트를 열람한다. Remove와 Insert는 판에서 텍스트를 제거하고 삽입하는데 사용된다.

Trace는 문자열을 출력판의 끝에 보여준다.

SciTE의 특성은 Property와 SetProperty로 읽고 쓸 수 있다.

GetInstance는 윈도우즈 종속적이며 어플리케이션의 HINSTANCE를 돌려준다. 이는 플랫폼의 편의 기능에 접근할 때 필요하다.

ShutDown는 사용자가 종료 메뉴 아이템을 선택했을 경우와 같다. 저장되지 않은 파일이 파일이 있다면, 사용자에게 저장할 지 아니면 취소할지 물어본다. 그래서 어떤 경우, 어플리케이션은 계속해서 ShutDown이 호출되 후에도 실행된다.

Perform은 조치가 포함된 문자열을 받는다. ':' 문자와 인자를 받는다. 현재는 알려진 조치만 열리고 그 인자는 경로이다. 이는 Director 확장에서 다른 어플리케이션으로부터 온 명령어를 전달하는데 사용한다. 앞으로 이 메쏘드를 통하여 더 많은 조치를 사용할 수 있을 것이다.

확장 붙이기.

확장은 현재 명시적으로 시작 함수에 코드로 붙는다. 윈도우즈에서 다음과 같은 예와 비슷하게 DirectorExtension이 코드로 붙는다:

DirectorExtension director;
Extension *extender = &director;
//...
SciTEWin MainWind(extender);

묵시적으로 부착하는 메커니즘이라면 더 좋을 것이다. 마치 단순히 객체 파일을 SciTE 안에 연결해 넣음으로써 어느 확장이 사용되는지 결정하여, 구문분석기가 Scintilla에 부착되는 것처럼 말이다. 확장을 DLL 또는 공유 객체 라이브러리 안에 넣어놓고 실행-시간에 부착하는 것도 좋을 것이다.

다중 처리.

SciTE는 한 번에 다중 확장을 지원한다. 다중 확장은 확장 리스트를 관리하면서 각 메소드에 대하여 하나씩 차례로 호출한다. 확장이 참값을 돌려주어 처리가 멈추어야 한다고 알려주면, 다중화자는 나머지 리스트 멤버를 순회하지 않고 반환된다. 그렇지만, Initialise와 Finalise 같은 메쏘드는 나머지 확장을 앞 확장의 반환 값에 상관없이 순회한다.

쓰레드 안전성.

일반적으로 SciTE는 단일 쓰레드 어플리케이션이다. 그렇지만, 윈도우즈에서 명령어 도구는 별도의 작업 쓰레드에서 OnExecute를 호출한다. OnExecute 호출이 잘 정돈되어 메인 쓰레드에 들어가도록 확장을 싸는데 SingleThreadExtension 어뎁터 클래스가 사용된다. 물론, 확장이 쓰레드에 안전하거나 OnExecute를 구현하지 않았거나, 또는 GTK-종속적 확장이라면 이 클래스는 필요없다.