2014-12-21 22:07:22 +00:00
;;; ahk-mode.el --- Major mode for editing AHK (AutoHotkey and AutoHotkey_L)
2014-12-11 04:58:27 +00:00
;; Author: Rich Alesi
2014-12-21 22:07:22 +00:00
;; Author: Xah Lee ( http://xahlee.org/ ) - 2012
;; Author: Robert Widhopf-Fenk
2014-12-11 04:58:27 +00:00
;; Keywords: ahk, AutoHotkey, hotkey, keyboard shortcut, automation
;; You can redistribute this program and/or modify it under the terms of the GNU
;; General Public License as published by the Free Software Foundation; either
;; GPL version 2 or 3.
;;; Commentary:
;; A major mode for editing AutoHotkey (AHK) script. Taken from snippets
;; supplied by the above authors in addition to the latest syntax files from the
;; latest build of SCITE for download location and documentation, see:
;;; INSTALL
;; Open the file, then type “Alt+x eval-buffer”. You are done. Open
;; any ahk script, then type “Alt+x ahk-mode”, you'll see the
;; source code syntax colored.
;; To have emacs automatically load the file when it restarts, and
;; automatically use the mode when opening files ending in “.ahk”, do this:
;; ① Put the file 〔 ahk-mode.el〕 in the dir 〔 ~/.emacs.d/〕
;; ② Put the following lines in your emacs init file (usually at 〔 ~/.emacs〕 ).
;; (autoload 'ahk-mode "ahk-mode" "Load ahk-mode for editing AutoHotkey scripts." t)
;;; FEATURES
;; When opening a script file you will get:
;; - syntax highlighting
2014-12-21 22:07:22 +00:00
;; - indention, completion and command help
2014-12-11 04:58:27 +00:00
;;; HISTORY
2014-12-21 22:07:22 +00:00
;; version 1.5, 2014-12-14 improved auto complete to work with ac and company-mode
2014-12-11 04:58:27 +00:00
;; version 1.4, 2014_07_18 latest merge with syntax tables
;; version 1.2.2, 2012-05-21 modified syntax table so “_” is part of word.
;; version 1.2.1, 2011-10-15 Minor changes. No visible behavior change.
;; version 1.2, 2010-02-17 fixed a defect where if source contains “"C:\"”, everything after is badly syntax colored. Thanks to “xinlu.h” and “iain.tuddenham”. Detail at http://code.google.com/p/ergoemacs/issues/detail?id=66
;; version 1.1, 2010-01-14 Added indentation feature. (press Tab to indent.)
;; version 1.0, 2010-01-09 First version.
( eval-when-compile
( require 'font-lock )
( require 'cl ) )
;;; Code:
( defconst ahk-mode-version " " )
2014-12-21 22:07:22 +00:00
( setq ahk-mode-version " 1.5 " )
2014-12-11 04:58:27 +00:00
( defgroup ahk-mode nil
" Major mode for editing AutoHotkey script. "
:group 'languages
:prefix " ahk- " )
( defvar ahk-mode-command-name-face 'ahk-mode-command-name-face " Face name to use for AHK command names. " )
( defcustom ahk-mode-hook ' ( ahk-mode-hook-activate-filling )
" Hook functions run by `ahk-mode' . "
:type 'hook
:group 'ahk-mode )
( defcustom ahk-indentation 2
" The indentation level. "
:type 'integer
:group 'ahk-mode )
( defvar ahk-path-exe-optional nil )
( defvar ahk-registry " HKEY_CLASSES_ROOT \\ AutoHotkeyScript \\ Shell \\ Open \\ Command " )
( defvar ahk-path-exe-installed
( let ( ( reg-data ( shell-command-to-string ( format " reg query \" %s \" " ahk-registry ) ) ) )
;; from
;; "C:\\Program Files (x86)\\AutoHotkey\\AutoHotkey.exe"
;; to
;; "C:/Program Files (x86)/AutoHotkey/AutoHotkey.exe"
( replace-regexp-in-string " \\ \\ " " / " ( cadr ( split-string reg-data " \\ \" " ) ) ) ) )
( defvar ahk-path-exe-installed-p
( file-exists-p ahk-path-exe-installed ) )
;;;###autoload
;; (add-to-list 'auto-mode-alist '("\\.ahk$" . ahk-mode))
( defvar ahk-mode-map nil " Keymap for ahk-mode " )
( progn
( setq ahk-mode-map ( make-sparse-keymap ) )
( define-key ahk-mode-map ( kbd " C-c C-r " ) 'ahk-lookup-ahk-ref )
2014-12-21 22:07:22 +00:00
( define-key ahk-mode-map ( kbd " C-c C-c " ) 'ahk-comment-region )
2014-12-11 04:58:27 +00:00
)
( easy-menu-define ahk-menu ahk-mode-map " AHK Mode Commands "
' ( " AHK "
2014-12-21 22:07:22 +00:00
[ " Lookup webdocs on command " ahk-lookup-ahk-ref ]
[ " Execute script " run-this-ahk-script ] ) )
2014-12-11 04:58:27 +00:00
;;; syntax table
( defvar ahk-mode-syntax-table nil " Syntax table for `ahk-mode' . " )
( setq ahk-mode-syntax-table
( let ( ( synTable ( make-syntax-table ) ) )
;; these are also allowed in variable names
( modify-syntax-entry ?# " w " synTable )
( modify-syntax-entry ?_ " w " synTable )
( modify-syntax-entry ?@ " w " synTable )
( modify-syntax-entry ?[ " w " synTable )
2014-12-21 22:07:22 +00:00
( modify-syntax-entry ?] " w " synTable )
2014-12-11 04:58:27 +00:00
;; some additional characters used in paths and switches
( modify-syntax-entry ?\\ " w " synTable )
;; (modify-syntax-entry ?/ "w" synTable)
( modify-syntax-entry ?. " . " synTable )
( modify-syntax-entry ?: " . " synTable )
( modify-syntax-entry ?- " . " synTable )
;; for multiline comments (taken from cc-mode)
( modify-syntax-entry ?/ " . 14 " synTable )
( modify-syntax-entry ?* " . 23 " synTable )
;; Give CR the same syntax as newline, for selective-display
( modify-syntax-entry ?\^ m " > b " synTable )
( modify-syntax-entry ?\n " > b " synTable )
( modify-syntax-entry ?` " \\ " synTable ) ; ` is escape
( modify-syntax-entry ?\; " < b " synTable )
( modify-syntax-entry ?! " . " synTable )
( modify-syntax-entry ?$ " . " synTable )
( modify-syntax-entry ?% " . " synTable )
( modify-syntax-entry ?^ " . " synTable )
( modify-syntax-entry ?& " . " synTable )
( modify-syntax-entry ?~ " . " synTable )
( modify-syntax-entry ?' " . " synTable )
( modify-syntax-entry ?| " . " synTable )
( modify-syntax-entry ?? " . " synTable )
( modify-syntax-entry ?< " . " synTable )
( modify-syntax-entry ?> " . " synTable )
( modify-syntax-entry ?, " . " synTable )
synTable )
2014-12-21 22:07:22 +00:00
)
2014-12-11 04:58:27 +00:00
;;; functions
( defun run-this-ahk-script ( )
( interactive )
( lexical-let*
( ( file ( shell-quote-argument ( buffer-file-name ) ) )
( optional-ahk-exe ( and ( stringp ahk-path-exe-optional )
( file-exists-p ahk-path-exe-optional ) ) )
( ahk-exe-path ( shell-quote-argument ( if optional-ahk-exe
ahk-path-exe-optional
ahk-path-exe-installed ) ) ) )
( if ( and ( stringp ahk-path-exe-optional )
( not optional-ahk-exe ) )
( error " Error: optional-ahk-exe is not found. " )
( save-window-excursion
( async-shell-command ( format " %s %s " ahk-exe-path file ) ) ) ) ) )
( defun ahk-lookup-ahk-ref ( )
" Look up current word in AutoHotkey's reference doc.
If a there is a text selection ( a phrase ) , lookup that phrase.
Launches default browser and opens the doc 's url. "
2014-12-21 22:07:22 +00:00
( interactive )
( let ( myword myurl )
( setq myword
( if ( region-active-p )
( buffer-substring-no-properties ( region-beginning ) ( region-end ) )
( thing-at-point 'symbol ) ) )
( setq myword ( replace-regexp-in-string " " " %20 " myword ) )
( setq myurl ( concat " http://www.autohotkey.com/docs/commands/ " myword " .htm " ) )
( browse-url myurl )
) )
2014-12-11 04:58:27 +00:00
( defun ahk-mode-hook-activate-filling ( )
" Activates `auto-fill-mode' and `filladapt-mode' . "
( auto-fill-mode 1 )
( if ( locate-library " filladapt " )
( filladapt-mode 1 ) ) )
;;;; indentation
( defun ahk-calc-indention ( str &optional offset )
( let ( ( i ( * ( or offset 0 ) ahk-indentation ) ) )
( while ( string-match " \t " str )
( setq i ( + i tab-width )
str ( replace-match " " nil t str ) ) )
( setq i ( + i ( length str ) ) )
i ) )
2014-12-21 22:07:22 +00:00
; the follwing regexp is used to detect if a condition is a one line statement or not,
; i.e. it matches one line statements but should not match those where the THEN resp.
; ELSE body is on its own line ...
2014-12-11 04:58:27 +00:00
( defvar ahk-one-line-if-regexp
( concat " ^ \\ ([ \t ]* \\ ) " ;; this is used for indention
" \\ ( "
" If \\ (Not \\ )? \\ ( "
2014-12-21 22:07:22 +00:00
( regexp-opt ' ( " InString " " InStr "
" Less " " Greater " " Equal "
" LessOrEqual " " GreaterOrEqual "
) )
" \\ )[^, \n ]*,[^, \n ]*,[^, \n ]*, "
2014-12-11 04:58:27 +00:00
" \\ | "
" If \\ (Not \\ )?Exist[^, \n ]*,[^, \n ]*, "
" \\ | "
" Else[ \t ]+ \\ ([^I \n ][^f \n ][^ \n ] \\ ) "
" \\ ) " ) )
( defun ahk-indent-line ( )
" Indent the current line. "
( interactive )
( let ( ( indent 0 )
( opening-brace nil ) ( else nil ) ( closing-brace ) ( block-skip nil )
( case-fold-search t ) )
;; do a backward search to determine the indention level
( save-excursion
( beginning-of-line )
( if ( looking-at " ^; " )
( setq indent 0 )
;; save type of current line
( setq opening-brace ( looking-at " ^ \\ ([ \t ]* \\ )[{(] " ) )
( setq else ( looking-at " ^ \\ ([ \t ]* \\ )Else[ \r \n ] " ) )
( setq closing-brace ( looking-at " ^ \\ ([ \t ]* \\ )[)}] " ) )
;; check previous non-empty line
( skip-chars-backward " \r \t \n " )
( beginning-of-line )
( when ( looking-at " ^ \\ ([ \t ]* \\ )[)}] " )
( goto-char ( match-end 0 ) )
( backward-list )
( skip-chars-backward " \r \t \n " )
( beginning-of-line )
( setq block-skip t ) )
;; skip commented lines backward
( while ( and ( looking-at " ^; " ) ( not ( bobp ) ) )
( forward-line -1 ) )
;; is it a label
( if ( looking-at " ^[^: \n ]+: " )
( if ( and ( not opening-brace )
( not block-skip )
( looking-at " ^[^: ]+: \\ ([^: \n ]*: \\ )?[ \t ]*$ " ) )
( setq indent ahk-indentation )
( setq indent 0 ) )
;; is it an opening { or (
( if ( looking-at " ^ \\ ([ \t ]* \\ )[{(] " )
( setq indent ( ahk-calc-indention ( match-string 1 ) 1 ) )
;; is it a Return at the first level?
( if ( and ( looking-at " ^ \\ ([ \t ]* \\ )[rR]eturn " )
( = ( ahk-calc-indention ( match-string 1 ) ) ahk-indentation ) )
( setq indent ( ahk-calc-indention ( match-string 1 ) -1 ) )
;; If/Else with body on next line, but not opening { or (
( if ( and ( not opening-brace )
( not block-skip )
( looking-at " ^ \\ ([ \t ]* \\ ) \\ (If \\ |Else \\ ) " )
( not ( looking-at ahk-one-line-if-regexp ) ) )
( setq indent ( ahk-calc-indention ( match-string 1 ) 1 ) )
;; two lines back was a If/Else thus indent like it
( if ( and ( not opening-brace )
2014-12-21 22:07:22 +00:00
;; (not else)
2014-12-11 04:58:27 +00:00
( save-excursion
( beginning-of-line )
( skip-chars-backward " \r \t \n " )
( beginning-of-line )
( setq indent nil )
;; backtrace nested Ifs
( while ( and ( looking-at " ^ \\ ([ \t ]* \\ ) \\ (If \\ |Else \\ ) " )
( not ( looking-at ahk-one-line-if-regexp ) ) )
( setq indent ( ahk-calc-indention ( match-string 1 ) ) )
( beginning-of-line )
( skip-chars-backward " \r \t \n " )
( beginning-of-line ) )
indent ) )
( setq indent indent )
;; the last resort, indent as the last line
( if ( looking-at " ^ \\ ([ \t ]* \\ ) " )
( setq indent ( ahk-calc-indention ( match-string 1 ) ) ) ) ) ) ) ) ) ) )
;; check for special tokens
( save-excursion
( beginning-of-line )
( if ( looking-at " ^ \\ ([ \t ]* \\ )[})] " )
( setq indent ( - indent ahk-indentation ) )
( if ( or ( looking-at " ^[ \t ]*[^,: \t \n ]*: " )
( looking-at " ^;;; " ) )
( setq indent 0 ) ) ) )
;; set negative indention to 0
( if ( < indent 0 )
( setq indent 0 ) )
( let ( ( point ( point-marker ) ) )
( beginning-of-line )
( if ( looking-at " ^[ \t ]+ " )
( replace-match " " ) )
( indent-to indent )
( if ( not ( marker-position point ) )
( if ( re-search-forward " [^ \t ] " ( point-max ) t )
( goto-char ( 1- ( point ) ) ) )
( goto-char point )
( set-marker point nil ) ) )
( if ( bolp )
( goto-char ( + ( point ) indent ) ) ) ) )
( defun ahk-indent-region ( start end )
( interactive " r " )
( save-excursion
( goto-char end )
( setq end ( point-marker ) )
( goto-char start )
( while ( < ( point ) end )
( end-of-line )
( ahk-indent-line )
( forward-line 1 ) )
( ahk-indent-line )
( set-marker end nil ) ) )
;;;; commenting
2014-12-21 22:07:22 +00:00
( defun ahk-comment-region ( start end &optional arg )
" Comment or uncomment entire block "
( interactive ( if ( region-active-p )
( list
( region-end )
current-prefix-arg )
( let ( start end )
( beginning-of-line )
( setq start ( point ) )
( forward-line )
( setq end ( point ) )
( list start end current-prefix-arg ) ) ) )
( save-excursion
( comment-region start end arg ) ) )
( defun ahk-comment-block ( start end &optional arg )
" Comment or uncomment entire block "
( interactive ( if ( region-active-p )
( list
( region-end )
current-prefix-arg )
( let ( start end )
( beginning-of-line )
( setq start ( point ) )
( forward-line )
( setq end ( point ) )
( list start end current-prefix-arg ) ) ) )
( comment-dwim )
( save-excursion
( comment-region start end arg ) ) )
2014-12-11 04:58:27 +00:00
;;; font-lock
( defvar ahk-commands
' ( " AllowSameLineComments " " ClipboardTimeout " " CommentFlag " " ErrorStdOut " " EscapeChar " " HotkeyInterval " " HotkeyModifierTimeout " " Hotstring " " IfWinActive " " IfWinExist " " IfWinNotActive " " IfWinNotExist " " Include " " IncludeAgain " " InstallKeybdHook " " InstallMouseHook " " KeyHistory " " LTrim " " MaxHotkeysPerInterval " " MaxMem " " MaxThreads " " MaxThreadsBuffer " " MaxThreadsPerHotkey " " NoEnv " " NoTrayIcon " " Persistent " " SingleInstance " " UseHook " " WinActivateForce " " AutoTrim " " BlockInput " " Break " " Click " " ClipWait " " Continue " " Control " " ControlClick " " ControlFocus " " ControlGet " " ControlGetFocus " " ControlGetPos " " ControlGetText " " ControlMove " " ControlSend " " ControlSendRaw " " ControlSetText " " CoordMode " " Critical " " DetectHiddenText " " DetectHiddenWindows " " Drive " " DriveGet " " DriveSpaceFree " " Edit " " Else " " EnvAdd " " EnvDiv " " EnvGet " " EnvMult " " EnvSet " " EnvSub " " EnvUpdate " " Exit " " ExitApp " " 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 " " Gosub " " Goto " " GroupActivate " " GroupAdd " " GroupClose " " GroupDeactivate " " Gui " " GuiControl " " GuiControlGet " " Hotkey " " If " " IfEqual " " IfExist " " IfGreater " " IfGreaterOrEqual " " IfInString " " IfLess " " IfLessOrEqual " " IfMsgBox " " IfNotEqual " " IfNotExist " " IfNotInString " " IfWinActive " " IfWinExist " " IfWinNotActive " " IfWinNotExist " " ImageSearch " " IniDelete " " IniRead " " IniWrite " " Input " " InputBox " " KeyHistory " " KeyWait " " ListHotkeys " " ListLines " " ListVars " " Loop " " Menu " " MouseClick " " MouseClickDrag " " MouseGetPos " " MouseMove " " MsgBox " " OnExit " " OutputDebug " " Pause " " PixelGetColor " " PixelSearch " " PostMessage " " Process " " Progress " " Random " " RegDelete " " RegRead " " RegWrite " " Reload " " Repeat " " Return " " Run " " RunAs " " RunWait " " Send " " SendEvent " " SendInput " " SendMessage " " SendMode " " SendPlay " " SendRaw " " SetBatchLines " " SetCapslockState " " SetControlDelay " " SetDefaultMouseSpeed " " SetEnv " " SetFormat " " SetKeyDelay " " SetMouseDelay " " SetNumlockState " " SetScrollLockState " " SetStoreCapslockMode " " SetTimer " " SetTitleMatchMode " " SetWinDelay " " SetWorkingDir " " Shutdown " " Sleep " " 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 " " Suspend " " SysGet " " Thread " " ToolTip " " Transform " " TrayTip " " URLDownloadToFile " " While " " 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 " )
" AHK keywords. " )
( defvar ahk-functions
' ( " Abs " " ACos " " Asc " " ASin " " ATan " " Ceil " " Chr " " Cos " " DllCall " " Exp " " FileExist " " Floor " " GetKeyState " " IL_Add " " IL_Create " " IL_Destroy " " InStr " " IsFunc " " 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 " " NumGet " " NumPut " " OnMessage " " RegExMatch " " RegExReplace " " RegisterCallback " " Round " " 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 " )
" AHK functions. " )
( defvar ahk-keywords
2014-12-21 22:07:22 +00:00
' ( " ACos " " ASin " " ATan " " Abort " " AboveNormal " " Abs " " Add " " All " " Alnum " " Alpha " " AltSubmit " " AltTab " " AltTabAndMenu " " AltTabMenu " " AltTabMenuDismiss " " AlwaysOnTop " " And " " Asc " " AutoSize " " Background " " BackgroundTrans " " BelowNormal " " Between " " BitAnd " " BitNot " " BitOr " " BitShiftLeft " " BitShiftRight " " BitXOr " " Border " " Bottom " " Bottom " " Button " " Buttons " " ByRef " " Cancel " " Cancel " " Capacity " " Caption " " Ceil " " Center " " Center " " Check " " Check3 " " Checkbox " " Checked " " CheckedGray " " Choose " " ChooseString " " Chr " " Click " " Close " " Close " " Color " " ComboBox " " Contains " " ControlList " " Cos " " Count " " DDL " " Date " " DateTime " " Days " " Default " " Delete " " DeleteAll " " Delimiter " " Deref " " Destroy " " Digit " " Disable " " Disabled " " DropDownList " " Eject " " Enable " " Enabled " " Error " " ExStyle " " Exist " " Exp " " Expand " " FileSystem " " First " " Flash " " Float " " FloatFast " " Floor " " Focus " " Font " " Grid " " Group " " GroupBox " " GuiClose " " GuiContextMenu " " GuiDropFiles " " GuiEscape " " GuiSize " " HKCC " " HKCR " " HKCU " " HKEY_CLASSES_ROOT " " HKEY_CURRENT_CONFIG " " HKEY_CURRENT_USER " " HKEY_LOCAL_MACHINE " " HKEY_USERS " " HKLM " " HKU " " HScroll " " Hdr " " Hidden " " Hide " " High " " Hours " " ID " " IDLast " " Icon " " IconSmall " " Ignore " " ImageList " " In " " Integer " " IntegerFast " " Interrupt " " Is " " Join " " LTrim " " Label " " Label " " LastFound " " LastFoundExist " " Left " " Limit " " Lines " " List " " ListBox " " ListView " " Ln " " Lock " " Log " " Logoff " " Low " " Lower " " Lowercase " " MainWindow " " Margin " " MaxSize " " Maximize " " MaximizeBox " " MinMax " " MinSize " " Minimize " " MinimizeBox " " Minutes " " Mod " " MonthCal " " Mouse " " Move " " Multi " " NA " " No " " NoActivate " " NoDefault " " NoHide " " NoIcon " " NoMainWindow " " NoSort " " NoSortHdr " " NoStandard " " NoTab " " NoTimers " " Normal " " Not " " Number " " Number " " Off " " Ok " " On " " Or " " OwnDialogs " " Owner " " Parse " " Password " " Password " " Pic " " Picture " " Pixel " " Pos " " Pow " " Priority " " ProcessName " " REG_BINARY " " REG_DWORD " " REG_EXPAND_SZ " " REG_MULTI_SZ " " REG_SZ " " RGB " " RTrim " " Radio " " Range " " Read " " ReadOnly " " Realtime " " Redraw " " Region " " Relative " " Rename " " Report " " Resize " " Restore " " Retry " " Right " " Round " " Screen " " Seconds " " Section " " Section " " Serial " " SetLabel " " ShiftAltTab " " Show " " Sin " " Single " " Slider " " SortDesc " " Sqrt " " Standard " " Status " " StatusBar " " StatusCD " " Style " " Submit " " SysMenu " " Tab " " Tab2 " " TabStop " " Tan " " Text " " Text " " T;;;heme " " Tile " " Time " " Tip " " ToggleCheck " " ToggleEnable " " ToolWindow " " Top " " Top " " Topmost " " TransColor " " Transparent " " Tray " " TreeView " " TryAgain " " Type " " UnCheck " " Unicode " " Unlock " " UpDown " " Upper " " Uppercase " " UseErrorLevel " " VScroll " " Vis " " VisFirst " " Visible " " Wait " " WaitClose " " WantCtrlA " " WantF2 " " WantReturn " " Wrap " " Xdigit " " Yes " " ahk_class " " ahk_group " " ahk_id " " ahk_pid " " bold " " global " " italic " " local " " norm " " static " " strike " " underline " " xm " " xp " " xs " " ym " " yp " " ys " " {AltDown} " " {AltUp} " " {Blind} " " {Click} " " {CtrlDown} " " {CtrlUp} " " {LWinDown} " " {LWinUp} " " {RWinDown} " " {RWinUp} " " {Raw} " " {ShiftDown} " " {ShiftUp} " )
2014-12-11 04:58:27 +00:00
" AHK lang keywords. " )
( defvar ahk-variables
' ( " 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_IsCritical " " A_IsPaused " " 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_ThisFunc " " A_ThisHotkey " " A_ThisLabel " " 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 " )
" AHK variables. " )
( defvar ahk-keys
' ( " Alt " " AltDown " " AltUp " " AppsKey " " BS " " BackSpace " " Browser_Back " " Browser_Favorites " " Browser_Forward " " Browser_Home " " Browser_Refresh " " Browser_Search " " Browser_Stop " " CapsLock " " Control " " Ctrl " " CtrlBreak " " CtrlDown " " CtrlUp " " Del " " Delete " " Down " " End " " Enter " " Esc " " Escape " " F1 " " F10 " " F11 " " F12 " " F13 " " F14 " " F15 " " F16 " " F17 " " F18 " " F19 " " F2 " " F20 " " F21 " " F22 " " F23 " " F24 " " F3 " " F4 " " F5 " " F6 " " F7 " " F8 " " F9 " " Home " " Ins " " Insert " " Joy1 " " Joy10 " " Joy11 " " Joy12 " " Joy13 " " Joy14 " " Joy15 " " Joy16 " " Joy17 " " Joy18 " " Joy19 " " Joy2 " " Joy20 " " Joy21 " " Joy22 " " Joy23 " " Joy24 " " Joy25 " " Joy26 " " Joy27 " " Joy28 " " Joy29 " " Joy3 " " Joy30 " " Joy31 " " Joy32 " " Joy4 " " Joy5 " " Joy6 " " Joy7 " " Joy8 " " Joy9 " " JoyAxes " " JoyButtons " " JoyInfo " " JoyName " " JoyPOV " " JoyR " " JoyU " " JoyV " " JoyX " " JoyY " " JoyZ " " LAlt " " LButton " " LControl " " LCtrl " " LShift " " LWin " " LWinDown " " LWinUp " " Launch_App1 " " Launch_App2 " " Launch_Mail " " Launch_Media " " Left " " MButton " " Media_Next " " Media_Play_Pause " " Media_Prev " " Media_Stop " " NumLock " " Numpad0 " " Numpad1 " " Numpad2 " " Numpad3 " " Numpad4 " " Numpad5 " " Numpad6 " " Numpad7 " " Numpad8 " " Numpad9 " " NumpadAdd " " NumpadClear " " NumpadDel " " NumpadDiv " " NumpadDot " " NumpadDown " " NumpadEnd " " NumpadEnter " " NumpadHome " " NumpadIns " " NumpadLeft " " NumpadMult " " NumpadPgdn " " NumpadPgup " " NumpadRight " " NumpadSub " " NumpadUp " " PGDN " " PGUP " " Pause " " PrintScreen " " RAlt " " RButton " " RControl " " RCtrl " " RShift " " RWin " " RWinDown " " RWinUp " " Right " " ScrollLock " " Shift " " ShiftDown " " ShiftUp " " Space " " Tab " " Up " " Volume_Down " " Volume_Mute " " Volume_Up " " WheelDown " " WheelLeft " " WheelRight " " WheelUp " " XButton1 " " XButton2 " )
" AHK keywords for keys. " )
( defvar ahk-operators
' ( " , "
" \\ \\ "
" \\ ^= " " \\ != " " && " " &= "
" \\ * \\ * " " \\ *= " " \\ * " " // " " //= " " /= " " / "
" \\ + \\ + " " \\ += " " \\ + " " -- " " -= " " - "
" \\ .= " " := " " : "
" << " " <<= " " <= " " < " " == " " = " " >= " " >> " " >>= " " > "
" \\ ? "
)
" AHK operators. " )
2014-12-21 22:07:22 +00:00
( defvar ahk-commands-regexp ( regexp-opt ahk-commands 'words ) )
( defvar ahk-functions-regexp ( regexp-opt ahk-functions 'words ) )
( defvar ahk-keywords-regexp ( regexp-opt ahk-keywords 'words ) )
( defvar ahk-variables-regexp ( regexp-opt ahk-variables 'words ) )
( defvar ahk-keys-regexp ( regexp-opt ahk-keys 'words ) )
( defvar ahk-operators-regexp ( regexp-opt ahk-operators 'words ) )
2014-12-11 04:58:27 +00:00
( defvar ahk-font-lock-keywords nil )
( setq ahk-font-lock-keywords
` (
2014-12-21 22:07:22 +00:00
( " \\ s-*;.*$ " . font-lock-comment-face )
( " ^/ \\ * \\ (.* \r ? \n \\ )* \\ ( \\ */ \\ )? " . font-lock-comment-face )
( " ^ \\ ([^ \t \n :^=]+ \\ ): " . ( 1 font-lock-builtin-face ) )
( " %[^% ]+% " . font-lock-variable-name-face )
( , ahk-commands-regexp . font-lock-type-face )
( , ahk-functions-regexp . font-lock-function-name-face )
( , ahk-keywords-regexp . font-lock-keyword-face )
( , ahk-variables-regexp . font-lock-variable-name-face )
( , ahk-keys-regexp . font-lock-constant-face )
( , ahk-operators-regexp . font-lock-warning-face )
2014-12-11 04:58:27 +00:00
;; note: order matters
) )
;; keyword completion
( defvar ahk-kwdList nil " AHK keywords. " )
( defvar ahk-all-keywords nil " list of all ahk keywords " )
( setq ahk-all-keywords ( append ahk-commands ahk-functions ahk-keywords ahk-variables ) )
( setq ahk-kwdList ( make-hash-table :test 'equal ) )
( mapc ( lambda ( x ) ( puthash x t ahk-kwdList ) ) ahk-commands )
( mapc ( lambda ( x ) ( puthash x t ahk-kwdList ) ) ahk-functions )
( mapc ( lambda ( x ) ( puthash x t ahk-kwdList ) ) ahk-keywords )
( mapc ( lambda ( x ) ( puthash x t ahk-kwdList ) ) ahk-variables )
( mapc ( lambda ( x ) ( puthash x t ahk-kwdList ) ) ahk-keys )
( put 'ahk-kwdList 'risky-local-variable t )
( defun ahk-completion-at-point ( )
" Complete the current work using the list of all syntax's. "
( interactive )
( let ( ( pt ( point ) ) )
( if ( and ( or ( save-excursion ( re-search-backward " \\ < \\ w+ " ) )
( looking-at " \\ < \\ w+ " ) )
( = ( match-end 0 ) pt ) )
( let ( ( start ( match-beginning 0 ) )
( prefix ( match-string 0 ) )
( completion-ignore-case t )
completions )
( list start pt ( all-completions prefix ahk-all-keywords ) :exclusive 'no ) ) ) ) )
;; clear memory
( setq ahk-commands nil )
( setq ahk-functions nil )
( setq ahk-keywords nil )
( setq ahk-variables nil )
( setq ahk-keys nil )
( define-derived-mode ahk-mode prog-mode " Autohotkey Mode "
" Major mode for editing AutoHotkey script (AHK).
The hook functions in ` ahk-mode-hook ' are run after mode initialization.
Key Bindings
\\{ahk-mode-map} "
( interactive )
( kill-all-local-variables )
2014-12-21 22:07:22 +00:00
;; (c-mode) ; for indentation
2014-12-11 04:58:27 +00:00
( set-syntax-table ahk-mode-syntax-table )
( setq major-mode 'ahk-mode
mode-name " AHK "
2014-12-21 22:07:22 +00:00
local-abbrev-table ahk-mode-abbrev-table )
2014-12-11 04:58:27 +00:00
2014-12-21 22:07:22 +00:00
;; ui
2014-12-11 04:58:27 +00:00
( use-local-map ahk-mode-map )
( easy-menu-add ahk-menu )
2014-12-21 22:07:22 +00:00
;; font-lock
2014-12-11 04:58:27 +00:00
( make-local-variable 'font-lock-defaults )
( setq font-lock-defaults ' ( ( ahk-font-lock-keywords ) nil t ) )
;; clear memory
( setq ahk-commands-regexp nil )
( setq ahk-functions-regexp nil )
( setq ahk-keywords-regexp nil )
( setq ahk-variables-regexp nil )
( setq ahk-keys-regexp nil )
2014-12-21 22:07:22 +00:00
;; set options
( setq-local comment-start " ; "
comment-end " "
comment-start-skip " ;+ * " )
( setq-local block-comment-start " /* "
block-comment-end " */ "
block-comment-left " * "
block-comment-right " * "
block-comment-top-right " "
block-comment-bot-left " "
block-comment-char ?* )
( setq-local indent-line-function 'ahk-indent-line
indent-region-function 'ahk-indent-region )
( setq-local parse-sexp-ignore-comments t
parse-sexp-lookup-properties t
paragraph-start ( concat " $ \\ | " page-delimiter )
paragraph-separate paragraph-start
paragraph-ignore-fill-prefix t )
2014-12-11 04:58:27 +00:00
( add-hook 'completion-at-point-functions 'ahk-completion-at-point nil t )
( run-mode-hooks 'ahk-mode-hook ) )
( add-to-list 'auto-mode-alist ' ( " \\ .ahk \\ ' " . ahk-mode ) )
( provide 'ahk-mode )
;;; ahk-mode.el ends here