Commits

Anonymous committed 1a2ef1a

Added ahk mode

  • Participants
  • Parent commits 98fffb5

Comments (0)

Files changed (2)

files/emacs-custom.el

  ;; If you edit it by hand, you could mess it up, so be careful.
  ;; Your init file should contain only one such instance.
  ;; If there is more than one, they won't work right.
+ '(ahk-bin "d:\\progs\\AutoHotkey\\AutoHotkey.exe")
+ '(ahk-syntax-directory "d:/progs/AutoHotkey/Extras/Editors/Syntax/")
  '(ange-ftp-ftp-program-name "d:\\progs\\ftp.exe")
  '(ansi-color-names-vector ["#212526" "#ff4b4b" "#b4fa70" "#fce94f" "#729fcf" "#ad7fa8" "#8cc4ff" "#eeeeec"])
  '(background-color "#002b36")

vendor/ahk-mode/ahk-mode.el

+;;; ahk-mode.el --- major mode for editing AutoHotKey scripts for X/GNU Emacs
+
+;; Copyright (C) 2005 Robert Widhopf-Fenk
+
+;; Author:   Robert Widhopf-Fenk
+;; Keywords: AutoHotKey, major mode
+;; X-URL:    http://www.robf.de/Hacking/elisp
+;; arch-tag: 1ae180cb-002e-4656-bd9e-a209acd4a3d4
+;; Version:  $Id: ahk-mode--main--1.0--patch-13$
+
+;; This code is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+
+;;; Commentary:
+;;
+;; AutoHotKey: Automation, Hotkeys and Scripting for Windows at
+;; http://www.autohotkey.com/ is a cool tool to make daily life
+;; with Windows easier or even fun!
+;;
+;; This is a X/GNU Emacs mode for editing AutoHotKey scripts.
+;;
+;; Place this file somewhere in your load-path, byte-compile it and add the
+;; following line to your ~/.xemacs/init.el resp. ~/.emacs:
+;;
+;; (setq ahk-syntax-directory "PATHTO/AutoHotkey/Extras/Editors/Syntax/")
+;; (add-to-list 'auto-mode-alist '("\\.ahk$" . ahk-mode))
+;; (autoload 'ahk-mode "ahk-mode")
+;;
+;; The first time ahk-mode.el is started it will ask you for the path to the
+;; Syntax directory if not set already.  You will find it as a subdirectory
+;; of your AHK installation.
+;;
+;; For example if you installed AHK at C:\Programms\AutoHotKey it will be
+;; C:/Programms/AutoHotKey/Extras/Editors/Syntax or a corresponding cygwin
+;; path!
+;;
+;; When opening a script file you will get:
+;; - syntax highlighting
+;; - indention, completion and command help (bound to "TAB")
+;; - insertion of command templates (bound to "C-c C-i")
+;; - electric braces (typing "{" will also insert "}" and place point in
+;;   between)
+;; - lookup the docs on a command via w3 (place point on command and type
+;;   "C-c C-h")
+;;
+;; Please send bug-reports or feature suggestions to hackATrobfDOTde.
+
+;;; Bugs:
+;;
+;; - completions is not really context aware
+;; - multi-line comments are not fontified correctly while editing,
+;;   but only when fontifying the whole buffer.  If you know how to
+;;   fix this, please let me know!
+
+;;; History:
+;;
+;; The CHANGELOG is stored in my arch repository.
+;;
+;; If you wonder what arch is, take a look at http://wiki.gnuarch.org/ !
+
+(eval-when-compile
+  (require 'font-lock)
+  (if (locate-library "w3") (require 'w3))
+  (require 'cl))
+
+;;; Code:
+(defgroup ahk-mode nil
+  "A mode for AutoHotKey"
+  :group 'languages
+  :prefix "ahk-")
+
+(defcustom ahk-mode-hook nil
+  "Hook functions run by `ahk-mode'."
+  :type 'hook
+  :group 'ahk-mode)
+
+(defcustom ahk-indetion 2
+  "The indetion level."
+  :type 'integer
+  :group 'ahk-mode)
+
+(defcustom ahk-syntax-directory nil
+  "The indetion level."
+  :type 'directory
+  :group 'ahk-mode)
+
+(defcustom ahk-bin nil
+  "The binary to run AHK script."
+  :type 'string
+  :group 'ahk-mode)
+
+;;;###autoload
+(add-to-list 'auto-mode-alist
+             '("\\.ahk$"  . ahk-mode))
+
+(defvar ahk-mode-syntax-table
+  (let ((table (make-syntax-table)))
+    ;; these are also allowed in variable names
+    (modify-syntax-entry ?#  "w" table)
+    (modify-syntax-entry ?_  "w" table)
+    (modify-syntax-entry ?@  "w" table)
+    (modify-syntax-entry ?$  "w" table)
+    (modify-syntax-entry ??  "w" table)
+    (modify-syntax-entry ?[  "w" table)
+    (modify-syntax-entry ?]  "w" table)
+    ;; some additional characters used in paths and switches
+    (modify-syntax-entry ?\\  "w" table)
+;    (modify-syntax-entry ?/  "w" table)
+    (modify-syntax-entry ?-  "w" table)
+    (modify-syntax-entry ?:  "w" table)
+    (modify-syntax-entry ?.  "w" table)
+    ;; for multiline comments (taken from cc-mode)
+    (modify-syntax-entry ?/  ". 14" table)
+    (modify-syntax-entry ?*  ". 23"   table)
+    ;; Give CR the same syntax as newline, for selective-display
+    (modify-syntax-entry ?\^m "> b" table)
+    (modify-syntax-entry ?\n "> b"  table)
+    table)
+  "Syntax table used in `ahk-mode' buffers.")
+
+(defvar ahk-mode-abbrev-table
+  (let ((a (make-abbrev-table)))
+    a)
+  "Abbreviation table used in `ahk-mode' buffers.")
+
+(defvar ahk-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\C-c\C-h" 'ahk-www-help-at-point)
+    (define-key map "\C-c\C-c" 'ahk-comment-region)
+    (define-key map "\C-c\C-i" 'ahk-insert-command-template)
+    (define-key map (kbd "C-c C-r") 'ahk-reload-file)
+    ;(define-key map "\t" 'ahk-indent-line-and-complete)
+    (define-key map "{" 'ahk-electric-brace)
+    (define-key map "}" 'ahk-electric-brace)
+    (define-key map "\r" 'ahk-electric-return)
+    map)
+  "Keymap used in `ahk-mode' buffers.")
+
+(defun ahk-reload-file ()
+  "Reload this file.  If not saved, save first"
+  (interactive)
+  (save-buffer)
+  (let ((cmd (concat ahk-bin " reload.ahk \"" (buffer-file-name) "\"")))
+    (shell-command cmd)))
+
+(defvar ahk-Commands-list nil
+  "A list of ahk commands and parameters.
+Will be initialized by `ahk-init'")
+
+(defvar ahk-Keys-list nil
+  "A list of ahk key names.
+Will be initialized by `ahk-init'")
+
+(defvar ahk-Keywords-list nil
+  "A list of ahks keywords.
+Will be initialized by `ahk-init'")
+
+(defvar ahk-Variables-list nil
+  "A list of ahks variables.
+Will be initialized by `ahk-init'")
+
+(defvar ahk-mode-font-lock-keywords nil
+  "Syntax highlighting for `ahk-mode'.
+Will be initialized by `ahk-init'")
+
+(defvar ahk-completion-list nil
+  "A list of all symbols available for completion
+Will be initialized by `ahk-init'")
+
+(easy-menu-define ahk-menu ahk-mode-map "AHK Mode Commands"
+          '("AHK"
+                    ["Insert Command Template" ahk-insert-command-template]
+                    ["Lookup webdocs on command" ahk-www-help-at-point]
+                    ))
+
+(defun ahk-init ()
+  "Initialize ahk-mode variables.
+An AHK installation provides a subdirectory \"Extras/Editors/Syntax\"
+containing a list of keywords, variables, commands and keys.
+
+This directory must be specified in the variable `ahk-syntax-directory'."
+  (interactive)
+
+  (message "Initializing ahk-mode variables ...")
+  (when (null ahk-syntax-directory)
+    (customize-save-variable
+     'ahk-syntax-directory
+     (read-file-name "Please give the AHK-Syntax directory: "))
+    (custom-save-all))
+
+  (save-excursion
+    (set-buffer (get-buffer-create " *ahk-mode-temp*"))
+
+    ;; read commands
+    (erase-buffer)
+    (insert-file-contents (expand-file-name "Commands.txt"
+                                            ahk-syntax-directory))
+    (setq ahk-Commands-list nil)
+    (goto-char 0)
+    (while (not (eobp))
+      (if (not (looking-at "\\([^;\r\n][^(\t\r\n, ]+\\)\\([^\r\n]*\\)"))
+          nil;; (error "Unknown file syntax")
+        (setq ahk-Commands-list (cons (list
+                                       (match-string 1)
+                                       (match-string 2))
+                                      ahk-Commands-list)))
+      (forward-line 1))
+
+    ;; read keys
+    (erase-buffer)
+    (insert-file-contents (expand-file-name "Keys.txt"
+                                            ahk-syntax-directory))
+    (setq ahk-Keys-list nil)
+    (goto-char 0)
+    (while (not (eobp))
+      (if (not (looking-at "\\([^;\r\n][^\t\r\n ]+\\)"))
+          nil;; (error "Unknown file syntax of Keys.txt")
+        (setq ahk-Keys-list (cons (match-string 1) ahk-Keys-list)))
+      (forward-line 1))
+
+    ;; read keywords
+    (erase-buffer)
+    (insert-file-contents (expand-file-name "Keywords.txt"
+                                            ahk-syntax-directory))
+    (setq ahk-Keywords-list nil)
+    (goto-char 0)
+    (while (not (eobp))
+      (if (not (looking-at "\\([^;\r\n][^\t\r\n ]+\\)"))
+          nil;; (error "Unknown file syntax of Keywords.txt")
+        (setq ahk-Keywords-list (cons (match-string 1) ahk-Keywords-list)))
+      (forward-line 1))
+    ;; read variables
+    (erase-buffer)
+    (insert-file-contents (expand-file-name "Variables.txt"
+                                            ahk-syntax-directory))
+    (setq ahk-Variables-list nil)
+    (goto-char 0)
+    (while (not (eobp))
+      (if (not (looking-at "\\([^;\r\n][^\t\r\n]+\\)"))
+          nil;; (error "Unknown file syntax of Variables.txt")
+        (setq ahk-Variables-list (cons (match-string 1) ahk-Variables-list)))
+      (forward-line 1))
+
+    ;; built completion list
+    (setq ahk-completion-list
+          (mapcar (lambda (c) (list c))
+                  (append (mapcar 'car ahk-Commands-list)
+                          ahk-Keywords-list
+                          ahk-Variables-list
+                          ahk-Keys-list)))
+
+    (setq ahk-mode-font-lock-keywords
+          (list
+           '("\\s-*;.*$" .
+             font-lock-comment-face)
+           '("^/\\*\\(.*\r?\n\\)*\\(\\*/\\)?" .
+;           '(ahk-fontify-comment .
+             font-lock-comment-face)
+           '("^\\([^ \t\n:]+\\):" .
+             (1 font-lock-builtin-face))
+           '("[^, %\"]*%[^% ]+%" .
+             font-lock-variable-name-face)
+           ;; I get an error when using regexp-opt instead of simply
+           ;; concatenating the keywords and I do not understand why ;-(
+           ;; (warning/warning) Error caught in `font-lock-pre-idle-hook': (invalid-regexp Invalid preceding regular expression)
+           (cons
+            (concat "\\b\\("
+                    (mapconcat 'regexp-quote ahk-Variables-list "\\|")
+                    "\\)\\b")
+            'font-lock-variable-name-face)
+           (list
+            (concat "\\(^[ \t]*\\|::[ \t]*\\)\\("
+                    ;; special tokens must come first
+                    "Else[ \t]+If[A-Za-z]*"
+                    "\\|"
+                    (mapconcat 'regexp-quote (mapcar 'car ahk-Commands-list) "\\|")
+                    "\\)")
+            2
+            'font-lock-function-name-face)
+           (cons
+            (concat "\\b\\("
+                    (mapconcat 'regexp-quote ahk-Keywords-list "\\|")
+                    "\\)\\b")
+            'font-lock-keyword-face)
+           (cons
+            (concat "\\b\\("
+                    (mapconcat 'regexp-quote ahk-Keys-list "\\|")
+                    "\\)\\b")
+            'font-lock-constant-face)
+           )))
+
+  (message "Initializing ahk-mode variables done."))
+
+;; this was an attempt to get multi-line comments correctly highlighted, I
+;; tried to understand how cc-mode is doing it, but I have to admit I do not
+;; understand it!
+(defun ahk-fontify-comment (limit)
+;  (setq limit (point-max))
+  (save-excursion
+    (let (start end)
+;      (setq bstart (save-excursion
+;                     (re-search-backward "^/\\*" (point-min) t)))
+;      (setq bend (save-excursion
+;                   (re-search-backward "^\\*/" (point-min) t)))
+;      (if (and bstart bend (< bend bstart))
+;          (goto-char bstart))
+      (setq start (save-excursion
+                    (re-search-forward "^/\\*" limit t)))
+      (setq end (save-excursion
+                  (re-search-forward "^\\*/" limit t)))
+
+      (cond
+       ((and start end (< end start))
+        (save-excursion
+          (re-search-forward "^\\*/" limit t)
+          t))
+       ((and start end (< start end))
+        (save-excursion
+          (re-search-forward "^/\\*\\(.*\r?\n\\)*\\*/" limit t)
+          t))
+       ((and start (not end))
+        (save-excursion
+          (re-search-forward "^/\\*\\(.*\r?\n\\)*" limit t)
+          t))
+       ))))
+
+(defun ahk-mode-hook-activate-filling ()
+  "Activates `auto-fill-mode' and `filladapt-mode'."
+  (auto-fill-mode 1)
+  (if (locate-library "filladapt")
+      (filladapt-mode 1)))
+
+;;;###autoload
+(defun ahk-mode ()
+  "Major mode for editing AutoHotKey Scripts.
+
+The hook functions in `ahk-mode-hook' are run after mode initialization.
+
+Key bindings:
+\\{ahk-mode-map}"
+  (interactive)
+  (if (null ahk-Commands-list)
+      (ahk-init))
+  (kill-all-local-variables)
+  (set-syntax-table ahk-mode-syntax-table)
+  (setq major-mode 'ahk-mode
+    mode-name "AHK"
+    local-abbrev-table ahk-mode-abbrev-table)
+  (make-local-variable 'indent-region-function)
+  (setq indent-region-function 'ahk-indent-region)
+  (make-local-variable 'indent-line-function)
+  (setq indent-line-function 'ahk-indent-line)
+  (put 'ahk-mode 'font-lock-defaults '(ahk-mode-font-lock-keywords t))
+  (put 'ahk-mode 'font-lock-keywords-case-fold-search t)
+
+  (when (not (featurep 'xemacs))
+    (setq font-lock-defaults '(ahk-mode-font-lock-keywords))
+    (setq font-lock-keywords-case-fold-search t))
+
+  (use-local-map ahk-mode-map)
+  (easy-menu-add ahk-menu)
+  (setq comment-start ";")
+  (font-lock-mode 1)
+  (force-mode-line-update)
+  (run-hooks 'ahk-mode-hook))
+
+(defun ahk-calc-indention (str &optional offset)
+  (let ((i (* (or offset 0) ahk-indetion)))
+    (while (string-match "\t" str)
+      (setq i (+ i tab-width)
+            str (replace-match "" nil t str)))
+    (setq i (+ i (length str)))
+    i))
+
+; 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 ...
+(defvar ahk-one-line-if-regexp
+  (concat "^\\([ \t]*\\)" ;; this is used for indention
+          "\\("
+          "If\\(Not\\)?\\("
+            (regexp-opt '("InString" "InStr"
+                          "Less" "Greater" "Equal"
+                          "LessOrEqual" "GreaterOrEqual"
+                          ))
+            "\\)[^,\n]*,[^,\n]*,[^,\n]*,"
+          "\\|"
+          "If\\(Not\\)?Exist[^,\n]*,[^,\n]*,"
+          "\\|"
+          "Else[ \t]+\\([^I\n][^f\n][^ \n]\\)"
+          "\\)"))
+
+;; TODO write a unit test for indetion
+(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 determin 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-indetion)
+              (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]*\\)Return")
+                     (= (ahk-calc-indention (match-string 1)) ahk-indetion))
+                (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)
+;                         (not else)
+                         (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-indetion))
+        (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)
+  "Indent lines in region START to 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)))
+
+(defun ahk-complete ()
+  "Indent current line when at the beginning or complete current command."
+  (interactive)
+
+  (if (looking-at "\\w+")
+      (goto-char (match-end 0)))
+
+  (let ((end (point)))
+    (if (and (or (save-excursion (re-search-backward "\\<\\w+"))
+                 (looking-at "\\<\\w+"))
+             (= (match-end 0) end))
+        (let ((start (match-beginning 0))
+              (prefix (match-string 0))
+              (completion-ignore-case t)
+              completions)
+          (setq completions (all-completions prefix ahk-completion-list))
+          (if (eq completions nil)
+              nil;(error "Unknown command prefix <%s>!" prefix)
+            (if (> (length completions) 1)
+                (setq completions
+                      (completing-read "Complete command: "
+                                       (mapcar (lambda (c) (list c))
+                                               completions)
+                                       nil t prefix)))
+            (if (stringp completions)
+                ;; this is a trick to upcase "If" and other prefixes
+                (let ((c (try-completion completions ahk-completion-list)))
+                  (if (stringp c)
+                      (setq completions c))))
+
+            (delete-region start end)
+            (if (listp completions) (setq completions (car completions)))
+            (insert completions)
+            (let ((help (assoc completions ahk-Commands-list)))
+              (if help (message "%s" (mapconcat 'identity help ""))))
+            )))))
+
+(defun ahk-indent-line-and-complete ()
+  "Combines indetion and completion."
+  (interactive)
+  (ahk-indent-line)
+  (ahk-complete))
+
+(defun ahk-electric-brace (arg)
+  "Insert character ARG and correct line's indentation."
+  (interactive "p")
+  (if (save-excursion
+        (skip-chars-backward " \t")
+        (bolp))
+      nil
+    (ahk-indent-line)
+    (newline))
+  (self-insert-command arg)
+  (ahk-indent-line)
+  (newline)
+  (ahk-indent-line)
+
+  (let ((event  last-input-event))
+    (setq event (if (featurep 'xemacs)
+            (event-to-character event)
+          (setq event (if (stringp event) (aref event 0) event))))
+
+    (when (equal event ?{)
+      (newline)
+      (ahk-indent-line)
+      (insert ?})
+      (ahk-indent-line)
+      (forward-line -1)
+      (ahk-indent-line))))
+
+(defun ahk-electric-return ()
+  "Insert newline and indent."
+  (interactive)
+  (ahk-indent-line)
+  (newline)
+  (ahk-indent-line))
+
+(defun ahk-insert-command-template ()
+  "Insert a command template."
+  (interactive)
+  (let ((completions (mapcar (lambda (c) (list (mapconcat 'identity c "")))
+                             ahk-Commands-list))
+        (completion-ignore-case t)
+        (start (point))
+        end
+        command)
+    (setq command (completing-read "AHK command template: " completions))
+    (insert command)
+    (ahk-indent-line)
+    (setq end (point-marker))
+    (goto-char start)
+    (while (re-search-forward "[`][nt]" end t)
+      (if (string= (match-string 0) "`n")
+      (replace-match "\n")
+    (replace-match "")))
+    (ahk-indent-region start end)
+    (goto-char (1+ start))
+    ;; jump to first parameter
+    (re-search-forward "\\<" end nil)
+    (set-marker end nil)))
+
+(defun ahk-comment-region (start end &optional arg)
+  "Comment or uncomment each line in the region from START to END.
+If no region is active use the current line."
+  (interactive (if (region-active-p)
+                   (list (region-beginning)
+                         (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-www-help-at-point ()
+  (interactive)
+  (save-excursion
+    (re-search-backward "\\<\\w+")
+    (if (looking-at "\\<\\w+")
+        (ahk-www-help (match-string 0)))))
+
+(defvar ahk-www-help-alist '()
+  "Mapping of command to regexp for commands which are not unique.")
+
+(defun ahk-www-help (command)
+  "Display online help for the given command"
+  (interactive (list
+                (completing-read "AHK command: "
+                                 ahk-completion-list nil t)))
+  (require 'w3)
+  (w3-fetch "http://www.autohotkey.com/docs/commands.htm")
+  (goto-char (point-min))
+  (when (re-search-forward (concat "^|" (regexp-quote command)))
+    (goto-char (+ (match-beginning 0) 1))
+    (save-excursion
+      (if (re-search-forward (concat "^|" (regexp-quote command))
+                             (point-max) t)
+          (message "There is more than one occurrence of %s. Stopping at first match" command)
+        (widget-button-press (point))))))
+
+(provide 'ahk-mode)
+
+;;; ahk-mode.el ends here