Zach Thibeau님께서 공개하신 AutoHotkey 스킴을 지원토록 수정된 소스를 설명한 글로, Zach님의 허락[footnote]정확히는 Zach님께서 코드를 작성하신 것은 아니라고 함. 다른 분이라는데, 누군지 확인은 못함.[/footnote]하에 올림.
Notepad2 용 AutoHotkey 스킴을 원하시는 분들이 계시던데, AutoHotkey 포럼에 Zach Thibeau님께서 수정된 소스를 공개하셨다.
하지만, 이 소스는 3.0.20 기반으로 되어있으며, 3.1.21.5 기반의 수정은 별도로 공개되어 있지 않다.
그래서 Zach님께서 어떻게 AutoHotkey 스킴을 수정하셨는가하는 방법을 설명하겠다.
이 수정은 (비록 Notepad2 컴파일 삽질기의 일부이지만) 지금까지의 수정을 하나도 하지 않은 상태에서도 적용이 가능하다.
1. SciLexer.h 수정
SciLexer.h는 전체가 #define 문으로 이루어져 있다.
여기에 아래의 내용을 추가한다.
여기에 아래의 내용을 추가한다.
#define SCLEX_AHK1 98
#define SCE_AHK_DEFAULT 0
#define SCE_AHK_COMMENTLINE 1
#define SCE_AHK_COMMENTBLOCK 2
#define SCE_AHK_ESCAPE 3
#define SCE_AHK_SYNOPERATOR 4
#define SCE_AHK_EXPOPERATOR 5
#define SCE_AHK_STRING 6
#define SCE_AHK_NUMBER 7
#define SCE_AHK_IDENTIFIER 8
#define SCE_AHK_VARREF 9
#define SCE_AHK_LABEL 10
#define SCE_AHK_WORD_CF 11
#define SCE_AHK_WORD_CMD 12
#define SCE_AHK_WORD_FN 13
#define SCE_AHK_WORD_DIR 14
#define SCE_AHK_WORD_KB 15
#define SCE_AHK_WORD_VAR 16
#define SCE_AHK_WORD_SP 17
#define SCE_AHK_WORD_UD 18
#define SCE_AHK_VARREFKW 19
#define SCE_AHK_ERROR 20
2. KeyWords.cxx
이 파일의 맨 끝부분은 아래와 같이 문법 스킴들을 링크하는 코드가 들어있다.
이 LINK_LEXER의 맨 아래에 아래와 같을 한 줄을 추가한다.
LINK_LEXER(lmVHDL);
LINK_LEXER(lmXML);
LINK_LEXER(lmYAML);
//--Autogenerated -- end of automatically generated section
return 1;
}
이 LINK_LEXER의 맨 아래에 아래와 같을 한 줄을 추가한다.
LINK_LEXER(lmAHK1);
3. LexAHK1.cxx 파일 추가
Zach님께서 공개하신 소스 파일 중에서 LexAHK1.cxx 파일을 추출해서 같은 폴더에 저장한다.
저장 위치는 소스\scintilla\src.
그리고, Fileview에도 추가한다. 추가 위치는 Scintilla/src.
압축 파일의 해제가 번거로우시면 아래 코드를 사용해도 된다.
저장 위치는 소스\scintilla\src.
그리고, Fileview에도 추가한다. 추가 위치는 Scintilla/src.
압축 파일의 해제가 번거로우시면 아래 코드를 사용해도 된다.
LexAHK1.cxx 소스 보기..
// Scintilla source code edit control
/** @file LexAHK1.cxx
** Lexer for AutoHotkey, simplified version
** Written by Philippe Lhoste (PhiLho)
**/
// Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>
#include "Platform.h"
#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"
static inline bool IsAWordChar(const int ch) {
return ch >= 0x80 || isalnum(ch) ||
ch == '_' || ch == '$' || ch == '[' || ch == ']' ||
ch == '#' || ch == '@' || ch == '?';
}
// Expression operator
// ( ) + - * ** / // ! ~ ^ & << >> . < > <= >= = == != <> && ||
static inline bool IsExpOperator(const int ch) {
if (ch >= 0x80 || isalnum(ch)) // Fast exit
return false;
return ch == '+' || ch == '-' || ch == '*' || ch == '/' ||
ch == '(' || ch == ')' || ch == '.' ||
ch == '=' || ch == '<' || ch == '>' ||
ch == '&' || ch == '|' || ch == '^' || ch == '~' || ch == '!';
}
static void HighlightKeyword(
char currentWord[],
StyleContext &sc,
WordList *keywordlists[],
Accessor &styler) {
WordList &controlFlow = *keywordlists[0];
WordList &commands = *keywordlists[1];
WordList &functions = *keywordlists[2];
WordList &directives = *keywordlists[3];
WordList &keysButtons = *keywordlists[4];
WordList &variables = *keywordlists[5];
WordList &specialParams = *keywordlists[6];
WordList &userDefined = *keywordlists[7];
if (controlFlow.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_CF);
} else if (commands.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_CMD);
} else if (functions.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_FN);
} else if (currentWord[0] == '#' && directives.InList(currentWord + 1)) {
sc.ChangeState(SCE_AHK_WORD_DIR);
} else if (keysButtons.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_KB);
} else if (variables.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_VAR);
} else if (specialParams.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_SP);
} else if (userDefined.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_UD);
} else {
sc.ChangeState(SCE_AHK_DEFAULT);
}
}
static void ColouriseAHK1Doc(
unsigned int startPos,
int length,
int initStyle,
WordList *keywordlists[],
Accessor &styler) {
WordList &keysButtons = *keywordlists[4];
WordList &variables = *keywordlists[5];
char currentWord[256];
// Do not leak onto next line
if (initStyle != SCE_AHK_COMMENTBLOCK &&
initStyle != SCE_AHK_STRING) {
initStyle = SCE_AHK_DEFAULT;
}
int currentState = initStyle;
int nextState = -1;
/* The AutoHotkey syntax is heavily context-dependent.
For example, for each command, the lexer knows if parameter #n
is a string, a variable, a number, an expression, etc.
I won't go this far, but I will try to handle most regular cases.
*/
// True if in a continuation section
bool bContinuationSection = (initStyle == SCE_AHK_STRING);
// Indicate if the lexer has seen only spaces since the start of the line
bool bOnlySpaces = (!bContinuationSection);
// Indicate if since the start of the line, lexer met only legal label chars
bool bIsLabel = false;
// Distinguish hotkeys from hotstring
bool bIsHotkey = false;
bool bIsHotstring = false;
// In an expression
bool bInExpression = false;
// A quoted string in an expression (share state with continuation section string)
bool bInExprString = false;
// To accept A-F chars in a number
bool bInHexNumber = false;
StyleContext sc(startPos, length, initStyle, styler);
for (; sc.More(); sc.Forward()) {
if (nextState >= 0) {
// I need to reset a state before checking new char
sc.SetState(nextState);
nextState = -1;
}
if (sc.state == SCE_AHK_SYNOPERATOR) {
// Only one char (if two detected, we move Forward() anyway)
sc.SetState(SCE_AHK_DEFAULT);
}
if (sc.atLineEnd && (bIsHotkey || bIsHotstring)) {
// I make the hotkeys and hotstrings more visible
// by changing the line end to LABEL style (if style uses eolfilled)
bIsHotkey = bIsHotstring = false;
sc.SetState(SCE_AHK_LABEL);
}
if (sc.atLineStart) {
if (sc.state != SCE_AHK_COMMENTBLOCK &&
!bContinuationSection) {
// Prevent some styles from leaking back to previous line
sc.SetState(SCE_AHK_DEFAULT);
}
bOnlySpaces = true;
bIsLabel = false;
bInExpression = false; // I don't manage multiline expressions yet!
bInHexNumber = false;
}
// Manage cases occuring in (almost) all states (not in comments)
if (sc.state != SCE_AHK_COMMENTLINE &&
sc.state != SCE_AHK_COMMENTBLOCK &&
!IsASpace(sc.ch)) {
if (sc.ch == '`') {
// Backtick, escape sequence
currentState = sc.state;
sc.SetState(SCE_AHK_ESCAPE);
sc.Forward();
nextState = currentState;
continue;
}
if (sc.ch == '%' && !bIsHotstring && !bInExprString &&
sc.state != SCE_AHK_VARREF &&
sc.state != SCE_AHK_VARREFKW &&
sc.state != SCE_AHK_ERROR) {
if (IsASpace(sc.chNext)) {
if (sc.state == SCE_AHK_STRING) {
// Illegal unquoted character!
sc.SetState(SCE_AHK_ERROR);
} else {
// % followed by a space is expression start
bInExpression = true;
}
} else {
// Variable reference
currentState = sc.state;
sc.SetState(SCE_AHK_SYNOPERATOR);
nextState = SCE_AHK_VARREF;
continue;
}
}
if (sc.state != SCE_AHK_STRING && !bInExpression) {
// Management of labels, hotkeys, hotstrings and remapping
// Check if the starting string is a label candidate
if (bOnlySpaces &&
sc.ch != ',' && sc.ch != ';' && sc.ch != ':' &&
sc.ch != '%' && sc.ch != '`') {
// A label cannot start with one of the above chars
bIsLabel = true;
}
// The current state can be IDENTIFIER or DEFAULT,
// depending if the label starts with a word char or not
if (bIsLabel && sc.ch == ':' &&
(IsASpace(sc.chNext) || sc.atLineEnd)) {
// ?l/a|b\e^l!:
// Only ; comment should be allowed after
sc.ChangeState(SCE_AHK_LABEL);
sc.SetState(SCE_AHK_SYNOPERATOR);
nextState = SCE_AHK_DEFAULT;
continue;
} else if (sc.Match(':', ':')) {
if (bOnlySpaces) {
// Hotstring ::aa::Foo
bIsHotstring = true;
sc.SetState(SCE_AHK_SYNOPERATOR);
sc.Forward();
nextState = SCE_AHK_LABEL;
continue;
}
// Hotkey F2:: or remapping a::b
bIsHotkey = true;
// Check if it is a known key
sc.GetCurrentLowered(currentWord, sizeof(currentWord));
if (keysButtons.InList(currentWord)) {
sc.ChangeState(SCE_AHK_WORD_KB);
}
sc.SetState(SCE_AHK_SYNOPERATOR);
sc.Forward();
if (bIsHotstring) {
nextState = SCE_AHK_STRING;
}
continue;
}
}
}
// Check if the current string is still a label candidate
// Labels are much more permissive than regular identifiers...
if (bIsLabel &&
(sc.ch == ',' || sc.ch == '%' || sc.ch == '`' || IsASpace(sc.ch))) {
// Illegal character in a label
bIsLabel = false;
}
// Determine if the current state should terminate.
if (sc.state == SCE_AHK_COMMENTLINE) {
if (sc.atLineEnd) {
sc.SetState(SCE_AHK_DEFAULT);
}
} else if (sc.state == SCE_AHK_COMMENTBLOCK) {
if (bOnlySpaces && sc.Match('*', '/')) {
// End of comment at start of line (skipping white space)
sc.Forward();
sc.ForwardSetState(SCE_C_DEFAULT);
}
} else if (sc.state == SCE_AHK_EXPOPERATOR) {
if (!IsExpOperator(sc.ch)) {
sc.SetState(SCE_AHK_DEFAULT);
}
} else if (sc.state == SCE_AHK_STRING) {
if (bContinuationSection) {
if (bOnlySpaces && sc.ch == ')') {
// End of continuation section
bContinuationSection = false;
sc.SetState(SCE_AHK_SYNOPERATOR);
}
} else if (bInExprString) {
if (sc.ch == '\"') {
if (sc.chNext == '\"') {
// In expression string, double quotes are doubled to escape them
sc.Forward(); // Skip it
} else {
bInExprString = false;
sc.ForwardSetState(SCE_AHK_DEFAULT);
}
} else if (sc.atLineEnd) {
sc.ChangeState(SCE_AHK_ERROR);
}
} else {
if (sc.ch == ';' && IsASpace(sc.chPrev)) {
// Line comments after code must be preceded by a space
sc.SetState(SCE_AHK_COMMENTLINE);
}
}
} else if (sc.state == SCE_AHK_NUMBER) {
if (bInHexNumber) {
if (!IsADigit(sc.ch, 16)) {
bInHexNumber = false;
sc.SetState(SCE_AHK_DEFAULT);
}
} else if (!(IsADigit(sc.ch) || sc.ch == '.')) {
sc.SetState(SCE_AHK_DEFAULT);
}
} else if (sc.state == SCE_AHK_IDENTIFIER) {
if (!IsAWordChar(sc.ch)) {
sc.GetCurrentLowered(currentWord, sizeof(currentWord));
HighlightKeyword(currentWord, sc, keywordlists, styler);
if (strcmp(currentWord, "if") == 0) {
bInExpression = true;
}
sc.SetState(SCE_AHK_DEFAULT);
}
} else if (sc.state == SCE_AHK_VARREF) {
if (sc.ch == '%') {
// End of variable reference
sc.GetCurrentLowered(currentWord, sizeof(currentWord));
if (variables.InList(currentWord)) {
sc.ChangeState(SCE_AHK_VARREFKW);
}
sc.SetState(SCE_AHK_SYNOPERATOR);
nextState = currentState;
continue;
} else if (!IsAWordChar(sc.ch)) {
// Oops! Probably no terminating %
sc.ChangeState(SCE_AHK_ERROR);
}
} else if (sc.state == SCE_AHK_LABEL) {
// Hotstring -- modifier or trigger string :*:aa::Foo or ::aa::Foo
if (sc.ch == ':') {
sc.SetState(SCE_AHK_SYNOPERATOR);
if (sc.chNext == ':') {
sc.Forward();
}
nextState = SCE_AHK_LABEL;
continue;
}
}
// Determine if a new state should be entered
if (sc.state == SCE_AHK_DEFAULT) {
if (sc.ch == ';' &&
(bOnlySpaces || IsASpace(sc.chPrev))) {
// Line comments are alone on the line or are preceded by a space
sc.SetState(SCE_AHK_COMMENTLINE);
} else if (bOnlySpaces && sc.Match('/', '*')) {
// Comment at start of line (skipping white space)
sc.SetState(SCE_AHK_COMMENTBLOCK);
sc.Forward();
} else if (sc.ch == '{' || sc.ch == '}') {
// Code block or special key {Enter}
sc.SetState(SCE_AHK_SYNOPERATOR);
} else if (bOnlySpaces && sc.ch == '(') {
// Continuation section
bContinuationSection = true;
sc.SetState(SCE_AHK_SYNOPERATOR);
nextState = SCE_AHK_STRING; // !!! Can be an expression!
} else if (sc.Match(':', '=') ||
sc.Match('+', '=') ||
sc.Match('-', '=') ||
sc.Match('/', '=') ||
sc.Match('*', '=')) {
// Expression assignment
bInExpression = true;
sc.SetState(SCE_AHK_SYNOPERATOR);
sc.Forward();
nextState = SCE_AHK_DEFAULT;
} else if (IsExpOperator(sc.ch)) {
sc.SetState(SCE_AHK_EXPOPERATOR);
} else if (sc.ch == '\"') {
bInExprString = true;
sc.SetState(SCE_AHK_STRING);
} else if (sc.ch == '0' && (sc.chNext == 'x' || sc.chNext == 'X')) {
// Hexa, skip forward as we don't accept any other alpha char (beside A-F) inside
bInHexNumber = true;
sc.SetState(SCE_AHK_NUMBER);
sc.Forward(2);
} else if (isdigit(sc.ch) || (sc.ch == '.' && isdigit(sc.chNext))) {
sc.SetState(SCE_AHK_NUMBER);
} else if (IsAWordChar(sc.ch)) {
sc.SetState(SCE_AHK_IDENTIFIER);
} else if (sc.ch == ',') {
sc.SetState(SCE_AHK_SYNOPERATOR);
nextState = SCE_AHK_DEFAULT;
} else if (sc.ch == ':') {
if (bOnlySpaces) {
// Start of hotstring :*:foo::Stuff or ::btw::Stuff
bIsHotstring = true;
sc.SetState(SCE_AHK_SYNOPERATOR);
if (sc.chNext == ':') {
sc.Forward();
}
nextState = SCE_AHK_LABEL;
}
} else if (IsAWordChar(sc.ch)) {
sc.SetState(SCE_AHK_IDENTIFIER);
}
}
if (!IsASpace(sc.ch)) {
bOnlySpaces = false;
}
}
// End of file: complete any pending changeState
if (sc.state == SCE_AHK_IDENTIFIER) {
sc.GetCurrentLowered(currentWord, sizeof(currentWord));
HighlightKeyword(currentWord, sc, keywordlists, styler);
} else if (sc.state == SCE_AHK_STRING && bInExprString) {
sc.ChangeState(SCE_AHK_ERROR);
} else if (sc.state == SCE_AHK_VARREF) {
sc.ChangeState(SCE_AHK_ERROR);
}
sc.Complete();
}
static void FoldAHK1Doc(unsigned int startPos, int length, int initStyle,
WordList *[], Accessor &styler) {
bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
unsigned int endPos = startPos + length;
bool bOnlySpaces = true;
int lineCurrent = styler.GetLine(startPos);
int levelCurrent = SC_FOLDLEVELBASE;
if (lineCurrent > 0) {
levelCurrent = styler.LevelAt(lineCurrent - 1) & SC_FOLDLEVELNUMBERMASK;
}
int levelNext = levelCurrent;
char chNext = styler[startPos];
int styleNext = styler.StyleAt(startPos);
int style = initStyle;
for (unsigned int i = startPos; i < endPos; i++) {
char ch = chNext;
chNext = styler.SafeGetCharAt(i + 1);
int stylePrev = style;
style = styleNext;
styleNext = styler.StyleAt(i + 1);
bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
if (foldComment && style == SCE_AHK_COMMENTBLOCK) {
if (stylePrev != SCE_AHK_COMMENTBLOCK) {
levelNext++;
} else if ((styleNext != SCE_AHK_COMMENTBLOCK) && !atEOL) {
// Comments don't end at end of line and the next character may be unstyled.
levelNext--;
}
}
if (style == SCE_AHK_SYNOPERATOR) {
if (ch == '(' || ch == '{') {
levelNext++;
} else if (ch == ')' || ch == '}') {
levelNext--;
}
}
if (atEOL) {
int level = levelCurrent;
if (bOnlySpaces && foldCompact) {
// Empty line
level |= SC_FOLDLEVELWHITEFLAG;
}
if (!bOnlySpaces && levelNext > levelCurrent) {
level |= SC_FOLDLEVELHEADERFLAG;
}
if (level != styler.LevelAt(lineCurrent)) {
styler.SetLevel(lineCurrent, level);
}
lineCurrent++;
levelCurrent = levelNext;
bOnlySpaces = true;
}
if (!isspacechar(ch)) {
bOnlySpaces = false;
}
}
}
static const char * const ahkWordListDesc[] = {
"Flow of control",
"Commands",
"Functions",
"Directives",
"Keys & buttons",
"Variables",
"Special Parameters (keywords)",
"User defined",
0
};
LexerModule lmAHK1(SCLEX_AHK1, ColouriseAHK1Doc, "ahk1", FoldAHK1Doc, ahkWordListDesc);
4. Styles.h의 수정
문법 스킴의 개수가 적힌 줄을 찾는다
아래와 같은 모양이다.
여기 적힌 개수를 하나 증가시킨다.
여기서는 27+1 = 28, 28을 적는다.
결과는 아래와 같다.
아래와 같은 모양이다.
// Number of Lexers in pLexArray
#define NUMLEXERS 27
여기 적힌 개수를 하나 증가시킨다.
여기서는 27+1 = 28, 28을 적는다.
결과는 아래와 같다.
#define NUMLEXERS 28
5. Styles.c의 수정 1/2
Zach님께서 공개하신 소스 파일 중에서 Styles.c 파일에서 KEYWORDLIST KeyWords_AHK = { ... } 부분과 EDITLEXER lexAHK1 = { ... } 부분을 같은 위치에 추가한다.
정확한 추가 위치는 아래 코드의 앞부분이다.
역시 압축 파일의 해제가 번거로우면 아래 코드를 사용해도 된다.
정확한 추가 위치는 아래 코드의 앞부분이다.
// This array holds all the lexers...
PEDITLEXER pLexArray[NUMLEXERS] =
역시 압축 파일의 해제가 번거로우면 아래 코드를 사용해도 된다.
more..
KEYWORDLIST KeyWords_AHK = {
"break continue else exit exitapp gosub goto if ifequal ifexist ifgreater "
"ifgreaterorequal ifinstring ifless iflessorequal ifmsgbox ifnotequal "
"ifnotexist ifnotinstring ifwinactive ifwinexist ifwinnotactive ifwinnotexist "
"loop onexit pause repeat return setbatchlines settimer sleep suspend "
"static global local byref "
"autotrim blockinput clipwait control controlclick controlfocus "
"controlget controlgetfocus controlgetpos controlgettext controlmove "
"controlsend controlsendraw controlsettext coordmode critical detecthiddentext "
"detecthiddenwindows drive driveget drivespacefree edit endrepeat envadd "
"envdiv envget envmult envset envsub envupdate fileappend filecopy "
"filecopydir filecreatedir filecreateshortcut filedelete filegetattrib "
"filegetshortcut filegetsize filegettime filegetversion fileinstall filemove "
"filemovedir fileread filereadline filerecycle filerecycleempty fileremovedir "
"fileselectfile fileselectfolder filesetattrib filesettime formattime "
"getkeystate groupactivate groupadd groupclose groupdeactivate gui "
"guicontrol guicontrolget hideautoitwin hotkey "
"imagesearch inidelete iniread iniwrite input inputbox keyhistory keywait "
"listhotkeys listlines listvars menu mouseclick mouseclickdrag mousegetpos "
"mousemove msgbox outputdebug pixelgetcolor pixelsearch "
"postmessage process progress random regdelete regread regwrite reload "
"run runas runwait "
"send sendevent sendinput sendmessage sendmode sendplay sendraw "
"setcapslockstate setcontroldelay setdefaultmousespeed setenv setformat "
"setkeydelay setmousedelay setnumlockstate setscrolllockstate "
"setstorecapslockmode settitlematchmode setwindelay setworkingdir "
"shutdown sort soundbeep soundget soundgetwavevolume soundplay soundset "
"soundsetwavevolume splashimage splashtextoff splashtexton splitpath "
"statusbargettext statusbarwait stringcasesense stringgetpos stringleft "
"stringlen stringlower stringmid stringreplace stringright stringsplit "
"stringtrimleft stringtrimright stringupper sysget thread tooltip "
"transform traytip urldownloadtofile winactivate winactivatebottom winclose "
"winget wingetactivestats wingetactivetitle wingetclass wingetpos wingettext "
"wingettitle winhide winkill winmaximize winmenuselectitem winminimize "
"winminimizeall winminimizeallundo winmove winrestore winset winsettitle "
"winshow winwait winwaitactive winwaitclose winwaitnotactive "
"abs acos asc asin atan ceil chr cos dllcall exp fileexist floor getkeystate "
"il_add il_create il_destroy instr islabel ln log lv_add lv_delete lv_deletecol "
"lv_getcount lv_getnext lv_gettext lv_insert lv_insertcol lv_modify "
"lv_modifycol lv_setimagelist mod onmessage round "
"regexmatch regexreplace "
"sb_seticon sb_setparts sb_settext sin sqrt strlen substr tan "
"tv_add tv_delete tv_getchild tv_getcount tv_getnext tv_get tv_getparent "
"tv_getprev tv_getselection tv_gettext tv_modify "
"varsetcapacity winactive winexist "
"allowsamelinecomments clipboardtimeout commentflag errorstdout escapechar "
"hotkeyinterval hotkeymodifiertimeout hotstring ifwinactive ifwinexist include "
"includeagain installkeybdhook installmousehook keyhistory ltrim "
"maxhotkeysperinterval maxmem maxthreads maxthreadsbuffer maxthreadsperhotkey "
"noenv notrayicon persistent singleinstance usehook winactivateforce "
"shift lshift rshift alt lalt ralt control lcontrol rcontrol "
"ctrl lctrl rctrl lwin rwin appskey "
"altdown altup shiftdown shiftup ctrldown ctrlup "
"lwindown lwinup rwindown rwinup "
"lbutton rbutton mbutton wheelup wheeldown xbutton1 xbutton2 "
"joy1 joy2 joy3 joy4 joy5 joy6 joy7 joy8 joy9 joy10 joy11 joy12 joy13 joy14 "
"joy15 joy16 joy17 joy18 joy19 joy20 joy21 joy22 joy23 joy24 joy25 joy26 joy27 "
"joy28 joy29 joy30 joy31 joy32 "
"joyx joyy joyz joyr joyu joyv joypov joyname joybuttons joyaxes joyinfo "
"space tab enter escape esc backspace bs delete del insert ins pgup pgdn "
"home end up down left right "
"printscreen ctrlbreak pause scrolllock capslock numlock "
"numpad0 numpad1 numpad2 numpad3 numpad4 numpad5 numpad6 numpad7 numpad8 numpad9 "
"numpadmult numpadadd numpadsub numpaddiv numpaddot numpaddel numpadins "
"numpadclear numpadup numpaddown numpadleft numpadright numpadhome numpadend "
"numpadpgup numpadpgdn numpadenter "
"f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 "
"f13 f14 f15 f16 f17 f18 f19 f20 f21 f22 f23 f24 "
"browser_back browser_forward browser_refresh browser_stop browser_search "
"browser_favorites browser_home volume_mute volume_down volume_up "
"media_next media_prev media_stop media_play_pause "
"launch_mail launch_media launch_app1 launch_app2 "
"blind click raw "
"a_ahkpath a_ahkversion a_appdata a_appdatacommon a_autotrim a_batchlines "
"a_caretx a_carety a_computername a_controldelay a_cursor "
"a_dd a_ddd a_dddd a_defaultmousespeed a_desktop a_desktopcommon "
"a_detecthiddentext a_detecthiddenwindows a_endchar "
"a_eventinfo a_exitreason a_formatfloat a_formatinteger a_gui a_guievent "
"a_guicontrol a_guicontrolevent a_guiheight a_guiwidth a_guix a_guiy a_hour "
"a_iconfile a_iconhidden a_iconnumber a_icontip a_index "
"a_ipaddress1 a_ipaddress2 a_ipaddress3 a_ipaddress4 a_isadmin a_iscompiled "
"a_issuspended a_keydelay a_language a_lasterror a_linefile a_linenumber "
"a_loopfield a_loopfileattrib a_loopfiledir a_loopfileext a_loopfilefullpath "
"a_loopfilelongpath a_loopfilename a_loopfileshortname a_loopfileshortpath "
"a_loopfilesize a_loopfilesizekb a_loopfilesizemb a_loopfiletimeaccessed "
"a_loopfiletimecreated a_loopfiletimemodified a_loopreadline a_loopregkey "
"a_loopregname a_loopregsubkey a_loopregtimemodified a_loopregtype "
"a_mday a_min a_mm a_mmm a_mmmm a_mon a_mousedelay a_msec a_mydocuments "
"a_now a_nowutc a_numbatchlines a_ostype a_osversion a_priorhotkey "
"a_programfiles a_programs a_programscommon a_screenheight a_screenwidth "
"a_scriptdir a_scriptfullpath a_scriptname a_sec a_space a_startmenu "
"a_startmenucommon a_startup a_startupcommon a_stringcasesense a_tab a_temp "
"a_thishotkey a_thismenu a_thismenuitem a_thismenuitempos a_tickcount "
"a_timeidle a_timeidlephysical a_timesincepriorhotkey a_timesincethishotkey "
"a_titlematchmode a_titlematchmodespeed a_username a_wday a_windelay a_windir "
"a_workingdir a_yday a_year a_yweek a_yyyy "
"clipboard clipboardall comspec errorlevel programfiles "
"true false "
"ltrim rtrim join "
"ahk_id ahk_pid ahk_class ahk_group "
"processname minmax controllist statuscd filesystem setlabel "
"alwaysontop mainwindow nomainwindow useerrorlevel "
"altsubmit hscroll vscroll imagelist wantctrla wantf2 vis visfirst "
"wantreturn backgroundtrans "
"minimizebox maximizebox sysmenu toolwindow exstyle "
"check3 checkedgray readonly notab "
"lastfound lastfoundexist "
"alttab shiftalttab alttabmenu alttabandmenu alttabmenudismiss "
"controllisthwnd hwnd"
"deref pow bitnot bitand bitor bitxor bitshiftleft bitshiftright "
"sendandmouse mousemove mousemouveoff "
"hkey_local_machine hkey_users hkey_current_user hkey_classes_root "
"hkey_current_config hklm hku hkcu hkcr hkcc "
"reg_sz reg_expand_sz reg_multi_sz reg_dword reg_qword reg_binary "
"reg_link reg_resource_list reg_full_resource_descriptor "
"reg_resource_requirements_list reg_dword_big_endian "
"regex "
"pixel mouse screen relative rgb "
"low belownormal normal abovenormal high realtime "
"between contains in is integer float number digit xdigit "
"alpha upper lower alnum time date "
"not or and "
"topmost top bottom transparent transcolor redraw region id idlast "
"count list capacity eject lock unlock "
"label serial type status "
"seconds minutes hours days "
"read parse "
"logoff close error single shutdown menu exit reload "
"tray add rename check uncheck togglecheck enable disable toggleenable default "
"nodefault standard nostandard color delete deleteall icon noicon tip click "
"show "
"edit progress hotkey text picture pic groupbox button "
"checkbox radio dropdownlist ddl combobox statusbar treeview "
"listbox listview datetime monthcal updown slider tab "
"iconsmall tile report sortdesc nosort nosorthdr grid hdr autosize range "
"xm ym ys xs xp yp "
"font resize owner submit nohide minimize maximize restore noactivate na "
"cancel destroy center "
"margin owndialogs guiescape guiclose guisize guicontextmenu guidropfiles "
"tabstop section wrap border top bottom buttons "
"expand first lines "
"number uppercase lowercase limit password multi group background "
"bold italic strike underline norm theme caption delimiter "
"flash style checked "
"password hidden left right center section move "
"focus hide choose choosestring text pos enabled disabled visible "
"notimers interrupt priority waitclose unicode "
"yes no ok cancel abort retry ignore "
"on off all send ",
"", "", "", "", "", "", "", "" };
// Zach Thibeau - 12th November 2008
EDITLEXER lexAHK1 = { SCLEX_AHK1, L"AutoHotKey Script", L"ahk", L"", &KeyWords_AHK, {
{ STYLE_DEFAULT, L"Default", L"fore:#C0C0C0; bold", L"" },
//{ SCE_AHK_DEFAULT, L"Default", L"", L"" },
{ SCE_AHK_COMMENTLINE, L"Comment", L"italics; fore:#008000", L"" },
{ SCE_AHK_COMMENTBLOCK, L"Comment Block", L"italics; fore:#008040", L"" },
{ SCE_AHK_ESCAPE, L"Escape", L"fore:#FF8000; bold", L"" },
{ SCE_AHK_SYNOPERATOR, L"Syntax Operator", L"Bold; fore:#008000", L"" },
{ SCE_AHK_EXPOPERATOR, L"Expression operator", L"Bold; fore:#FF0000", L"" },
{ SCE_AHK_STRING, L"String", L"bold; fore:#C0C0C0", L"" },
{ SCE_AHK_NUMBER, L"Number", L"bold; fore:#0000FF", L"" },
{ SCE_AHK_IDENTIFIER, L"Identifier", L"bold; fore:#C80000", L"" },
{ SCE_AHK_VARREF, L"Variable dereferencing", L"bold; fore:#C80000; back:#F0F0FF", L"" },
{ SCE_AHK_LABEL, L"Label", L"fore:#000000; back:#FFFFD1; bold", L"" },
{ SCE_AHK_WORD_CF, L"Flow of control", L"fore:#0000C8; bold", L"" },
{ SCE_AHK_WORD_CMD, L"Commands", L"fore:#0000A0; bold", L"" },
{ SCE_AHK_WORD_FN, L"Functions", L"fore:#0000FF; bold", L"" },
{ SCE_AHK_WORD_DIR, L"Directives", L"fore:#008000; bold", L"" },
{ SCE_AHK_WORD_KB, L"Keys & buttons", L"fore:#FF00FF; bold", L"" },
{ SCE_AHK_WORD_VAR, L"Built-in Variables", L"back:#F0F0FF; bold", L"" },
{ SCE_AHK_WORD_SP, L"Special", L"fore:#FF00FF; bold; italics", L"" },
{ SCE_AHK_WORD_UD, L"User Defined", L"bold; fore:#800020", L"" },
{ SCE_AHK_VARREFKW, L"Variable keyword", L"fore:#FF00FF; bold; back:#F0F0FF", L"" },
{ SCE_AHK_ERROR, L"Error", L"back:#FFC0C0", L"" },
{ -1, L"", L"", L"" } } };
6. Styles.c의 수정 2/2
앞의 5항에서 추가한 위치의 코드는 아래와 같은 모양이다.
이 내용의 끝에 &lexAHK1을 추가한다. 아래와 같은 모양이 된다.
// This array holds all the lexers...
PEDITLEXER pLexArray[NUMLEXERS] =
{
&lexDefault,
&lexHTML,
// :
//중간 생략
// :
&lexASCII
};
이 내용의 끝에 &lexAHK1을 추가한다. 아래와 같은 모양이 된다.
&lexASCII, // 앞의 코드 끝에 컴마(,)를 추가함
&lexAHK1
};
이렇게 수정된 결과는 아래와 같다.
짜잔~ 이제 3.1.21.5-rc4에서도 AutoHotkey 스킴을 깔끔하게 지원한다
결국 오토핫키까지... 사실 최초로 이거 해달라고 했던 분은 걍 지나가다 슬쩍 던진 말이었는데 결국 이렇게 되는군요ㅋ 이렇게 될 줄 알았다능ㅋㅋ
답글삭제이모티콘을 보니까 갑자기 아이디어가 하나 생각났습니다. 나중에 정리해서 한방에 질문 올리도록 하지요:P
@okto - 2009/06/09 09:09
답글삭제필요는 발명의 어머니라능~