// ==UserScript==
// @name ahkcn代码块增强
// @namespace http://tampermonkey.net/
// @version 0.3
// @description 使用highlight.js为ahkcn高亮代码, 使用highlightjs-line-numbers.js和highlightjs-copy提供行号和一键复制功能
// @author Tebayaki
// @match https://www.autoahk.com/archives/*
// @grant GM_addStyle
// @grant unsafeWindow
// @run-at document-start
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/highlight.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/python.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/cpp.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.6.0/languages/javascript.min.js
// @license MIT
// ==/UserScript==
(function () {
"use strict";
// 增加一个空值判断, 避免在某些情况报错
// https://unpkg.com/[email protected]/dist/highlightjs-copy.min.js
class CopyButtonPlugin{constructor(options={}){self.hook=options.hook;self.callback=options.callback}"after:highlightElement"({el,text}){let button=Object.assign(document.createElement("button"),{innerHTML:"Copy",className:"hljs-copy-button"});button.dataset.copied=false;if(!el.parentElement){return}el.parentElement.classList.add("hljs-copy-wrapper");el.parentElement.appendChild(button);el.parentElement.style.setProperty("--hljs-theme-background",window.getComputedStyle(el).backgroundColor);button.onclick=function(){if(!navigator.clipboard)return;let newText=text;if(hook&&typeof hook==="function"){newText=hook(text,el)||text}navigator.clipboard.writeText(newText).then(function(){button.innerHTML="Copied!";button.dataset.copied=true;let alert=Object.assign(document.createElement("div"),{role:"status",className:"hljs-copy-alert",innerHTML:"Copied to clipboard"});el.parentElement.appendChild(alert);setTimeout(()=>{button.innerHTML="Copy";button.dataset.copied=false;el.parentElement.removeChild(alert);alert=null},2e3)}).then(function(){if(typeof callback==="function")return callback(newText,el)})}}};
// this lib need some change to prevent "highlight.js not detected!" error
// https://cdnjs.cloudflare.com/ajax/libs/highlightjs-line-numbers.js/2.8.0/highlightjs-line-numbers.min.js
!function(r,o){"use strict";var e,i="hljs-ln",l="hljs-ln-line",h="hljs-ln-code",s="hljs-ln-numbers",c="hljs-ln-n",m="data-line-number",a=/\r\n|\r|\n/g;function u(e){for(var n=e.toString(),t=e.anchorNode;"TD"!==t.nodeName;)t=t.parentNode;for(var r=e.focusNode;"TD"!==r.nodeName;)r=r.parentNode;var o=parseInt(t.dataset.lineNumber),a=parseInt(r.dataset.lineNumber);if(o==a)return n;var i,l=t.textContent,s=r.textContent;for(a<o&&(i=o,o=a,a=i,i=l,l=s,s=i);0!==n.indexOf(l);)l=l.slice(1);for(;-1===n.lastIndexOf(s);)s=s.slice(0,-1);for(var c=l,u=function(e){for(var n=e;"TABLE"!==n.nodeName;)n=n.parentNode;return n}(t),d=o+1;d<a;++d){var f=p('.{0}[{1}="{2}"]',[h,m,d]);c+="\n"+u.querySelector(f).textContent}return c+="\n"+s}function n(e){try{var n=o.querySelectorAll("code.hljs,code.nohighlight");for(var t in n)n.hasOwnProperty(t)&&(n[t].classList.contains("nohljsln")||d(n[t],e))}catch(e){r.console.error("LineNumbers error: ",e)}}function d(e,n){"object"==typeof e&&r.setTimeout(function(){e.innerHTML=f(e,n)},0)}function f(e,n){var t,r,o=(t=e,{singleLine:function(e){return!!e.singleLine&&e.singleLine}(r=(r=n)||{}),startFrom:function(e,n){var t=1;isFinite(n.startFrom)&&(t=n.startFrom);var r=function(e,n){return e.hasAttribute(n)?e.getAttribute(n):null}(e,"data-ln-start-from");return null!==r&&(t=function(e,n){if(!e)return n;var t=Number(e);return isFinite(t)?t:n}(r,1)),t}(t,r)});return function e(n){var t=n.childNodes;for(var r in t){var o;t.hasOwnProperty(r)&&(o=t[r],0<(o.textContent.trim().match(a)||[]).length&&(0<o.childNodes.length?e(o):v(o.parentNode)))}}(e),function(e,n){var t=g(e);""===t[t.length-1].trim()&&t.pop();if(1<t.length||n.singleLine){for(var r="",o=0,a=t.length;o<a;o++)r+=p('<tr><td class="{0} {1}" {3}="{5}"><div class="{2}" {3}="{5}"></div></td><td class="{0} {4}" {3}="{5}">{6}</td></tr>',[l,s,c,m,h,o+n.startFrom,0<t[o].length?t[o]:" "]);return p('<table class="{0}">{1}</table>',[i,r])}return e}(e.innerHTML,o)}function v(e){var n=e.className;if(/hljs-/.test(n)){for(var t=g(e.innerHTML),r=0,o="";r<t.length;r++){o+=p('<span class="{0}">{1}</span>\n',[n,0<t[r].length?t[r]:" "])}e.innerHTML=o.trim()}}function g(e){return 0===e.length?[]:e.split(a)}function p(e,t){return e.replace(/\{(\d+)\}/g,function(e,n){return void 0!==t[n]?t[n]:e})}hljs?(hljs.initLineNumbersOnLoad=function(e){"interactive"===o.readyState||"complete"===o.readyState?n(e):r.addEventListener("DOMContentLoaded",function(){n(e)})},hljs.lineNumbersBlock=d,hljs.lineNumbersValue=function(e,n){if("string"!=typeof e)return;var t=document.createElement("code");return t.innerHTML=e,f(t,n)},(e=o.createElement("style")).type="text/css",e.innerHTML=p(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[i,c,m]),o.getElementsByTagName("head")[0].appendChild(e)):r.console.error("highlight.js not detected!"),document.addEventListener("copy",function(e){var n,t=window.getSelection();!function(e){for(var n=e;n;){if(n.className&&-1!==n.className.indexOf("hljs-ln-code"))return 1;n=n.parentNode}}(t.anchorNode)||(n=-1!==window.navigator.userAgent.indexOf("Edge")?u(t):t.toString(),e.clipboardData.setData("text/plain",n),e.preventDefault())})}(window,document);
///////////////////////////
GM_addStyle(`
pre {
color: #dcdcdc;
background: #1e1e1e;
padding-top: 10px;
padding-bottom: 10px;
padding-left: 5px;
padding-right: 5px;
}
.hljs-ln-line {
background: #1e1e1e;
border: 0px !important;
padding-top: 0px !important;
padding-bottom: 0px !important;
font-family: -webkit-body !important;
font-size: small !important
}
.hljs-ln-numbers {
padding-left: 5px !important;
padding-right: 10px !important;
border-right: 1px solid #CCC !important;
text-align: center !important;
width: 20px !important;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none
}
.hljs-ln-code {
padding-left: 10px !important;
-webkit-user-select: text;
-ms-user-select: text;
user-select: text
}
.hljs {
background: #1e1e1e;
color: #dcdcdc
}
.hljs-params,
.hljs-symbol,
.hljs-object,
.hljs-array,
.hljs-expr,
.hljs-punctuation {
color: #dcdcdc
}
.hljs-char.escape_ {
color: #d7ba7d
}
.hljs-class {
color: #41c9a2
}
.hljs-keyword {
color: #bd63c5
}
.hljs-literal,
.hljs-built_in,
.hljs-type {
color: #569cd6
}
.hljs-number {
color: #b8d7a3
}
.hljs-command,
.hljs-meta .hljs-string,
.hljs-string {
color: #d69d85
}
.hljs-regexp,
.hljs-template-tag {
color: #9a5334
}
.hljs-formula,
.hljs-function,
.hljs-subst,
.hljs-title {
color: #dcdcaa
}
.hljs-comment,
.hljs-quote {
color: #57a64a;
font-style: italic
}
.hljs-doctag {
color: #608b4e
}
.hljs-punctuation2,
.hljs-meta,
.hljs-meta .hljs-keyword,
.hljs-tag {
color: #9b9b9b
}
.hljs-template-variable,
.hljs-ref,
.hljs-variable {
color: #9cdcfe
}
.hljs-property,
.hljs-attr,
.hljs-doubleRef,
.hljs-attribute {
color: #008cff
}
.hljs-section {
color: gold
}
.hljs-bullet,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #d7ba7d
}
.hljs-addition {
background-color: #144212;
display: inline-block;
width: 100%
}
.hljs-deletion {
background-color: #600;
display: inline-block;
width: 100%
}
.hljs-copy-wrapper {
position: relative;
overflow: auto
}
.hljs-copy-wrapper:hover .hljs-copy-button,
.hljs-copy-button[data-copied="true"] {
opacity: 1
}
.hljs-copy-button {
position: absolute;
top: 1em;
right: 1em;
width: 2rem;
height: 2rem;
padding: 2px;
text-indent: -9999px;
color: #fff;
border-radius: .25rem;
border: 1px solid #ffffff22;
background-color: #2d2b57;
background-color: var(--hljs-theme-background);
background-image: url('data:image/svg+xml;utf-8,<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 5C5.73478 5 5.48043 5.10536 5.29289 5.29289C5.10536 5.48043 5 5.73478 5 6V20C5 20.2652 5.10536 20.5196 5.29289 20.7071C5.48043 20.8946 5.73478 21 6 21H18C18.2652 21 18.5196 20.8946 18.7071 20.7071C18.8946 20.5196 19 20.2652 19 20V6C19 5.73478 18.8946 5.48043 18.7071 5.29289C18.5196 5.10536 18.2652 5 18 5H16C15.4477 5 15 4.55228 15 4C15 3.44772 15.4477 3 16 3H18C18.7956 3 19.5587 3.31607 20.1213 3.87868C20.6839 4.44129 21 5.20435 21 6V20C21 20.7957 20.6839 21.5587 20.1213 22.1213C19.5587 22.6839 18.7957 23 18 23H6C5.20435 23 4.44129 22.6839 3.87868 22.1213C3.31607 21.5587 3 20.7957 3 20V6C3 5.20435 3.31607 4.44129 3.87868 3.87868C4.44129 3.31607 5.20435 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6Z" fill="white"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3C7 1.89543 7.89543 1 9 1H15C16.1046 1 17 1.89543 17 3V5C17 6.10457 16.1046 7 15 7H9C7.89543 7 7 6.10457 7 5V3ZM15 3H9V5H15V3Z" fill="white"/></svg>');
background-repeat: no-repeat;
background-position: center;
opacity: 0;
transition: all 200ms ease
}
.hljs-copy-button:hover {
border-color: #ffffff44
}
.hljs-copy-button:active {
transform: scale(0.8, 0.8)
}
.hljs-copy-button[data-copied="true"] {
background-image: url('data:image/svg+xml;utf-8,<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M6 5C5.73478 5 5.48043 5.10536 5.29289 5.29289C5.10536 5.48043 5 5.73478 5 6V20C5 20.2652 5.10536 20.5196 5.29289 20.7071C5.48043 20.8946 5.73478 21 6 21H18C18.2652 21 18.5196 20.8946 18.7071 20.7071C18.8946 20.5196 19 20.2652 19 20V6C19 5.73478 18.8946 5.48043 18.7071 5.29289C18.5196 5.10536 18.2652 5 18 5H16C15.4477 5 15 4.55228 15 4C15 3.44772 15.4477 3 16 3H18C18.7956 3 19.5587 3.31607 20.1213 3.87868C20.6839 4.44129 21 5.20435 21 6V20C21 20.7957 20.6839 21.5587 20.1213 22.1213C19.5587 22.6839 18.7957 23 18 23H6C5.20435 23 4.44129 22.6839 3.87868 22.1213C3.31607 21.5587 3 20.7957 3 20V6C3 5.20435 3.31607 4.44129 3.87868 3.87868C4.44129 3.31607 5.20435 3 6 3H8C8.55228 3 9 3.44772 9 4C9 4.55228 8.55228 5 8 5H6Z" fill="violet"/><path fill-rule="evenodd" clip-rule="evenodd" d="M7 3C7 1.89543 7.89543 1 9 1H15C16.1046 1 17 1.89543 17 3V5C17 6.10457 16.1046 7 15 7H9C7.89543 7 7 6.10457 7 5V3ZM15 3H9V5H15V3Z" fill="violet"/></svg>')
}
@media(prefers-reduced-motion) {
.hljs-copy-button {
transition: none
}
}
.hljs-copy-alert {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px
}
`);
const gramr_autohotkey = e => {
const reg = {
ltrim: "^[ \\t]*",
space: "[ \\t]+",
space_opt: "[ \\t]*",
name: "(?<![\\w\\u0080-\\uffff])[\\w\\u0080-\\uffff]+(?![\\w\\u0080-\\uffff])"
},
com = {
scope: "comment",
variants: [
{ begin: /;/, end: /$/ },
{ begin: /^\s*\/\*/, end: /^\s*\*\// },
{ match: /(?<=\n)\*\// }
],
contains: [{ scope: "doctag", match: /@\S+/ }]
},
keyword1 = { beginKeywords: "and byref case default else finally for in new not or return switch throw try until while" },
built_in = { scope: "built_in", match: /\b(A_AhkPath|A_AhkVersion|A_AppData|A_AppDataCommon|A_Args|A_AutoTrim|A_BatchLines|A_CaretX|A_CaretY|A_ComputerName|A_ComSpec|A_ControlDelay|A_CoordModeCaret|A_CoordModeMenu|A_CoordModeMouse|A_CoordModePixel|A_CoordModeToolTip|A_Cursor|A_DD|A_DDD|A_DDDD|A_DefaultGui|A_DefaultListView|A_DefaultMouseSpeed|A_DefaultTreeView|A_Desktop|A_DesktopCommon|A_DetectHiddenText|A_DetectHiddenWindows|A_EndChar|A_EventInfo|A_ExitReason|A_FileEncoding|A_FormatFloat|A_FormatInteger|A_Gui|A_GuiControl|A_GuiControlEvent|A_GuiEvent|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_Is64bitOS|A_IsAdmin|A_IsCompiled|A_IsCritical|A_IsPaused|A_IsSuspended|A_IsUnicode|A_KeyDelay|A_KeyDelayPlay|A_KeyDuration|A_KeyDurationPlay|A_Language|A_LastError|A_LineFile|A_LineNumber|A_ListLines|A_LoopField|A_LoopFileAttrib|A_LoopFileDir|A_LoopFileExt|A_LoopFileFullPath|A_LoopFileLongPath|A_LoopFileName|A_LoopFilePath|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_MouseDelayPlay|A_MSec|A_MyDocuments|A_Now|A_NowUTC|A_NumBatchLines|A_OSType|A_OSVersion|A_PriorHotkey|A_PriorKey|A_ProgramFiles|A_Programs|A_ProgramsCommon|A_PtrSize|A_RegView|A_ScreenDPI|A_ScreenHeight|A_ScreenWidth|A_ScriptDir|A_ScriptFullPath|A_ScriptHwnd|A_ScriptName|A_Sec|A_SendLevel|A_SendMode|A_Space|A_StartMenu|A_StartMenuCommon|A_Startup|A_StartupCommon|A_StoreCapsLockMode|A_StringCaseSense|A_Tab|A_Temp|A_ThisFunc|A_ThisHotkey|A_ThisLabel|A_ThisMenu|A_ThisMenuItem|A_ThisMenuItemPos|A_TickCount|A_TimeIdle|A_TimeIdleKeyboard|A_TimeIdleMouse|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|False|ProgramFiles|True|this)\b/ },
num = hljs.C_NUMBER_MODE,
esc = { scope: "char.escape", match: /`[\s\S]/ },
esc2 = { scope: "char.escape", match: /""/ },
variable = { scope: "variable", match: reg.name },
ref = {
variants: [
{ begin: [/%/, built_in.match, /%/], beginScope: { 1: "punctuation", 2: "built_in", 3: "punctuation" } },
{ begin: [/%/, reg.name, /%/], beginScope: { 1: "punctuation", 2: "variable", 3: "punctuation" } },
]
},
doubleRef = {
variants: [
{ begin: [/%/, built_in.match, /%/], beginScope: { 1: "punctuation2", 2: "built_in", 3: "punctuation2" } },
{ begin: [/%/, reg.name, /%/], beginScope: { 1: "punctuation2", 2: "variable", 3: "punctuation2" } },
]
},
func = { begin: [reg.name, reg.space_opt, /(?=\()/], beginScope: { 1: "function" } },
str = {}, obj = {}, arr = {}, parenExpr = {},
exprs = [com, num, keyword1, built_in, str, func, doubleRef, obj, arr, parenExpr, variable];
Object.assign(str, {
scope: "string",
end: /"/,
variants: [
{
begin: /"(?=[^"]*\n)/,
contains: [com, esc, esc2,
{
scope: "string",
begin: /^\s*\)/,
end: /"/,
contains: [esc, esc2],
endsParent: 1
},
{
scope: "punctuation",
begin: [/^\s*\(/, /.*$/],
beginScope: { 1: "string", 2: "meta" },
end: /(?=\n\s*\).*")/,
excludeEnd: 1,
contains: [
{
scope: "string",
begin: /^|"/,
end: /$|"/,
contains: [esc, esc2]
},
num, func, doubleRef, parenExpr, built_in, variable,
]
}
]
},
{
begin: /"/,
contains: [esc, esc2]
},
],
});
Object.assign(obj, {
scope: "object",
begin: /\{(?![\s\S]*\n\s*})/,
end: /\}/,
contains: [{
begin: [reg.name, reg.space_opt, /:/],
beginScope: { 1: "variable" }
}, ...exprs]
});
Object.assign(arr, {
scope: "array",
begin: /\[/,
end: /\]/,
contains: exprs
});
Object.assign(obj, {
scope: "object",
begin: /\{(?![\s\S]*\n\s*})/,
end: /\}/,
contains: [{
begin: [reg.name, reg.space_opt, /:/],
beginScope: { 1: "variable" }
}, ...exprs]
});
Object.assign(arr, {
scope: "array",
begin: /\[/,
end: /\]/,
contains: exprs
});
Object.assign(parenExpr, {
scope: "expr",
begin: /\(/,
end: /\)/,
contains: exprs
});
const cmdExpr = {
scope: "command",
begin: /[^]/,
end: /$(?!\n\s*(,|\(|;|\/\*))/,
contains: [
{ scope: "punctuation", match: /,/ },
{
scope: "string",
begin: [reg.ltrim, /\(/, /.*$/],
beginScope: { 3: "meta" },
end: /^\s*\)/,
contains: [esc, ref]
},
{
scope: "punctuation",
begin: /%[ \t]+/,
end: /$|,/,
contains: exprs
},
ref,
com,
esc,
]
},
keyword2 = {
scope: "keyword",
match: /\b(break|catch|continue|goto|gosub)\b/,
starts: cmdExpr
},
exprAssign = {
begin: /:=/,
end: /$(?!\n\s*(?:,|;|\/\*))/,
contains: [com, num, func, keyword1, built_in, variable, doubleRef, str]
},
varDecl = {
beginKeywords: "global local static",
end: exprAssign.end,
contains: exprAssign.contains
},
cmdAssign = {
begin: [reg.name, reg.space_opt, /=/],
beginScope: { 1: "variable" },
starts: { scope: cmdExpr.scope, begin: cmdExpr.begin, end: cmdExpr.end, contains: cmdExpr.contains.slice(1) }
},
cmd = {
scope: "function",
variants: [
{
begin: /\b(AutoTrim|BlockInput|Click|ClipWait|Control|ControlClick|ControlFocus|ControlGet|ControlGetFocus|ControlGetPos|ControlGetText|ControlMove|ControlSend|ControlSendRaw|ControlSetText|CoordMode|Critical|DetectHiddenText|DetectHiddenWindows|Drive|DriveGet|DriveSpaceFree|Edit|EnvAdd|EnvDiv|EnvGet|EnvMult|EnvSet|EnvSub|EnvUpdate|Exit|ExitApp|FileAppend|FileCopy|FileCopyDir|FileCreateDir|FileCreateShortcut|FileDelete|FileEncoding|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|Hotkey|ImageSearch|IniDelete|IniRead|IniWrite|Input|InputBox|InputBox|KeyHistory|KeyWait|ListHotkeys|ListLines|ListVars|Menu|MouseClick|MouseClickDrag|MouseGetPos|MouseMove|MsgBox|OnExit|OutputDebug|Pause|PixelGetColor|PixelSearch|PostMessage|Process|Progress|Random|RegDelete|RegRead|RegWrite|Reload|Run|RunAs|RunWait|Send|SendEvent|SendInput|SendLevel|SendMessage|SendMode|SendPlay|SendRaw|SetBatchLines|SetCapsLockState|SetControlDelay|SetDefaultMouseSpeed|SetEnv|SetFormat|SetKeyDelay|SetMouseDelay|SetNumLockState|SetRegView|SetScrollLockState|SetStoreCapsLockMode|SetTimer|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|Suspend|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|If(Not)?Exist|IfWin(Not)?Exist|IfWin(Not)?Active|IfMsgBox|IfEqual|IfNotEqual|IfLess|IfLessOrEqual|IfGreater|IfGreaterOrEqual)(?=(,|\s|$))/,
starts: cmdExpr
},
{ begin: /\b(Sleep)(?=(,|\s|$))/ }
]
},
loopStatement = {
beginKeywords: "loop",
starts: {
scope: cmdExpr.scope,
begin: cmdExpr.begin,
end: /(?={.*\n)|$(?!\n\s*(,|\(|;|\/\*))/,
contains: cmdExpr.contains
}
},
ifStatement = {
variants: [
{
scope: "string",
begin: [/\bif/, reg.space, reg.name, reg.space_opt, />=|<=|!=|<|>|=/],
beginScope: { 1: "keyword", 3: "variable", 5: "punctuation" },
starts: loopStatement.starts
},
{
scope: "string",
begin: [/\bif/, reg.space, /%/, reg.name, /%/, reg.space_opt, />=|<=|!=|>|<|=/],
beginScope: { 1: "keyword", 3: "punctuation", 4: "doubleRef", 5: "punctuation", 7: "punctuation" },
starts: loopStatement.starts
},
{
begin: [/\bif/, reg.space, reg.name, reg.space, /(not[ \t]+)?(in|contains)\b/],
beginScope: { 1: "keyword", 3: "variable", 5: "keyword" },
starts: cmdExpr
},
{
begin: [/\bif/, reg.space, reg.name, reg.space, /is([ \t]not)?/, reg.space, reg.name],
beginScope: { 1: "keyword", 3: "variable", 5: "keyword", 7: "class" }
},
{
begin: [/\bif/, reg.space, reg.name, reg.space, /(not[ \t]+)?between/],
beginScope: { 1: "keyword", 3: "variable", 5: "keyword" },
starts: { scope: cmdExpr.scope, begin: cmdExpr.begin, end: cmdExpr.end, contains: [{ scope: "keyword", match: /\band\b/ }, ...cmdExpr.contains.slice(1)] }
},
{ beginKeywords: "if" }
]
},
directives = {
scope: "meta",
variants: [
{
begin: /#(AllowSameLineComments|ClipboardTimeout|CommentFlag|ErrorStdOut|EscapeChar|HotkeyInterval|HotkeyModifierTimeout|Hotstring|IfWin(Not)?Active|IfWin(Not)?Exist|IfTimeout|Include(Again)?|InputLevel|InstallKeybdHook|InstallMouseHook|KeyHistory|MaxHotkeysPerInterval|MaxMem|MaxThreads|MaxThreadsBuffer|MaxThreadsPerHotkey|MenuMaskKey|NoEnv|NoTrayIcon|Persistent|Requires|SingleInstance|UseHook|Warn|WinActivateForce)\b/,
starts: cmdExpr
},
{ begin: /#(If)/ }
]
},
hotkey = {
scope: "label",
variants: [
// hotstring
{
begin: [reg.ltrim, /:/, /.*/, /:(?=.+::)/],
beginScope: { 3: "meta" },
end: /::/,
contains: [
{
scope: "string",
begin: /(?<=:)/,
end: /(?=::)/,
contains: [esc]
}
],
starts: {
scope: "string",
end: /$/,
contains: [esc]
}
},
// hotkey
{ match: [reg.ltrim, /[#!^+&<>*~$]*([a-z0-9]+|[\x21-\x7e ])([ \t]+&[ \t]+[#!^+&<>*~$]*([a-z0-9]+|[\x21-\x7e ]))*([ \t]+UP)*::/], beginScope: {} },
]
},
lable = {
scope: "label",
match: [reg.ltrim, reg.name + ":(?!=)"],
beginScope: {}
},
classDecl = {
variants: [
{
begin: [/\bclass/, reg.space, reg.name, reg.space, /extends/, reg.space, reg.name],
beginScope: { 1: "keyword", 3: "class", 5: "keyword", 7: "class" }
},
{
begin: [/\bclass/, reg.space, reg.name],
beginScope: { 1: "keyword", 3: "class" }
}
]
},
block = {
variants: [
{ begin: /{(?=\s*\n)/ },
{ begin: /(?<=^\s*){/ }
],
end: /^\s*}/,
contains: [lable, cmd, ifStatement, loopStatement, varDecl, classDecl, exprAssign, cmdAssign, keyword2, "self", {
begin: [/get|set/, reg.space_opt, /(?=\{)/], beginScope: { 1: "function" }
}, ...exprs]
};
return {
name: "AutoHotkey",
case_insensitive: true,
contains: [hotkey, lable, cmd, directives, ifStatement, loopStatement, varDecl, classDecl, exprAssign, cmdAssign, block, keyword2, ...exprs]
}
}
Object.defineProperty(unsafeWindow, "PR_SHOULD_USE_CONTINUATION", {
get: () => 1,
set: (v) => { unsafeWindow.b2_global.prettify_load = 0 }
});
hljs.registerLanguage("autohotkey", gramr_autohotkey);
hljs.addPlugin(new CopyButtonPlugin());
hljs.highlightAll();
hljs.initLineNumbersOnLoad();
})();