UNPKG

coffee-ahk

Version:
661 lines (533 loc) 14.2 kB
# 文档 你可以把`Coffee-AHK`看作是`CoffeeScript`的一种方言,它可以编译为 AutoHotkey v1 脚本。它兼容现有的`AHK`代码,并增加了类、模块、函数式编程、赋值解构、丰富语法糖、部分 npm 包管理等现代特性。配合插件还可支持 TypeScript 静态类型系统。注意:AutoHotkey 不区分大小写。 最新版本:**0.0.61** ## 概览 上方为`Coffee-AHK`代码,下方为翻译后的`AHK`代码。 ```coffeescript # assignment: number = 42 opposite = true # conditions: if opposite then number = -42 # functions: square = (x) -> x * x # arrays: list = [1, 2, 3, 4, 5] # object: math = root: Math.sqrt square: square cube: (x) -> x * square x # splats: race = (winner, runners...) -> print winner, runners ``` ```ahk global number := 42 global opposite := true if (opposite) { number := -42 } global square := Func("ahk_3") global list := [1, 2, 3, 4, 5] global math := {root: Math.sqrt, square: square, cube: Func("ahk_2")} global race := Func("ahk_1").Bind(print) ahk_1(print, winner, runners*) { print.Call(winner, runners) } ahk_2(x) { return x * square.Call(x) } ahk_3(x) { return x * x } ``` ## 安装 ```shell # install locally for a project: pnpm install coffee-ahk ``` ## 语言参考 首先,`Coffee-AHK`使用有语义的空格和换行。你可以直接通过换行来终止表达式,而不需要显式书写`;`(除非你需要将多个表达式写在同一行)。而在函数、`if`语句、`switch`语句或`try`/`catch`中,你需要使用缩进替代包围代码块的`{}`来划分代码块。 在执行函数时,你不需要显式使用`()`来包裹参数。隐式调用会自动帮你处理好这些。 `console.log sys.inspect object``console.log(sys.inspect(object));` ## 函数 函数由括号中的参数、箭头和函数体三部分构成。一个最简单的空函数长这样:`->`。 注意,所有以大写字母开头的函数都被视作内置函数。 ```coffeescript square = (x) -> x * x cube = (x) -> square(x) * x ``` ```ahk global square := Func("ahk_2") global cube := Func("ahk_1") ahk_1(x) { return square.Call(x) * x } ahk_2(x) { return x * x } ``` 函数参数可以设置默认值,当参数不传时(即为`undefined`时),其将被置为该值。 ```coffeescript fill = (container, liquid = 'coffee') -> return "Filling the #{container} with #{liquid}..." ``` ```ahk global fill := Func("ahk_1") ahk_1(container, liquid := "coffee") { return "Filling the " . (container) . " with " . (liquid) . "..." } ``` ## 字符串 如同`JavaScript`和其他许多语言一样,`Coffee-AHK`同时支持`'``"``Coffee-AHK`也支持使用`#{ ... }`的形式,在`"`包裹的字符串中进行字符串插值,甚至在对象的键名中你也可以这么做。 ```coffeescript author = 'Wittgenstein' quote = "A picture is a fact. -- #{ author }" sentence = "#{ 22 / 7 } is a decent approximation of π" ``` ```ahk global author := "Wittgenstein" global quote := "A picture is a fact. -- " . (author) . "" global sentence := "" . (22 / 7) . " is a decent approximation of π" ``` `Coffee-AHK`中可以使用多行字符串。换行会被转为一个空格,而缩进则被忽略。 ```coffeescript mobyDick = 'Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...' ``` ```ahk global mobyDick := "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world..." ``` ```coffeescript html = ''' <strong> cup of coffee-ahk </strong> ''' ``` ```ahk global html := "<strong>cup of coffee-ahk</strong>" ``` 双引号包括的块状字符串也可以进行插值。 ## 对象与数组 `Coffee-AHK`中的对象与数组看起来同`JavaScript`非常相似。当每个属性都单独成行时,句末的`,`是可以省略的。你也可以使用缩进代替`{}`来创建对象,就像在`YAML`中那样。 ```coffeescript song = ['do', 're', 'mi', 'fa', 'so'] singers = {Jagger: 'Rock', Elvis: 'Roll'} bitlist = [ 1, 0, 1 0, 0, 1 1, 1, 0 ] kids = brother: name: 'Max' age: 11 sister: name: 'Ida' age: 9 ``` ```ahk global song := ["do", "re", "mi", "fa", "so"] global singers := {Jagger: "Rock", Elvis: "Roll"} global bitlist := [1, 0, 1, 0, 0, 1, 1, 1, 0] global kids := {brother: {name: "Max", age: 11}, sister: {name: "Ida", age: 9}} ``` 在用同名变量来设置键时,你可以使用如下简便写法。注意,此时必须显式写下`{``}````coffeescript name = 'Michelangelo' mask = 'orange' weapon = 'nunchuks' turtle = {name, mask, weapon} output = "#{turtle.name} wears an #{turtle.mask} mask. Watch out for his #{turtle.weapon}!" ``` ```ahk global name := "Michelangelo" global mask := "orange" global weapon := "nunchuks" global turtle := {name: name, mask: mask, weapon: weapon} global output := "" . (turtle.name) . " wears an " . (turtle.mask) . " mask. Watch out for his " . (turtle.weapon) . "!" ``` ## 注释 `Coffee-AHK`中使用`#`来表示行注释,使用`###`来表示块注释。 ## If, Else, Unless, and Conditional Assignment `if`/`else`可以不使用`{}`包裹。你可以同其他块状表达式一样,使用缩进来划分它们。 ```coffeescript if singing then mood = greatlyImproved if happy and knowsIt clapsHands() chaChaCha() else showIt() if friday date = sue else date = jill ``` ```ahk if (singing) { mood := greatlyImproved } if (happy && knowsIt) { clapsHands.Call() chaChaCha.Call() } else { showIt.Call() } if (friday) { date := sue } else { date := jill } ``` ## Splats, or Rest Parameters ```coffeescript gold = 'unknown' silver = 'unknown' rest = 'unknown' awardMedals = (first, second, others...) -> gold = first silver = second rest = others contenders = [ 'Michael Phelps' 'Liu Xiang' 'Yao Ming' 'Allyson Felix' 'Shawn Johnson' 'Roman Sebrle' 'Guo Jingjing' 'Tyson Gay' 'Asafa Powell' 'Usain Bolt' ] awardMedals contenders... alert " Gold: #{gold} Silver: #{silver} The Field: #{rest.join ', '} " ``` ```ahk global gold := "unknown" global silver := "unknown" global rest := "unknown" global awardMedals := Func("ahk_1") global contenders := ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"] awardMedals.Call(contenders*) alert.Call(" Gold: " . (gold) . " Silver: " . (silver) . " The Field: " . (rest.join.Call(", ")) . " ") ahk_1(first, second, others*) { gold := first silver := second rest := others } ``` ## 循环 ```coffeescript # Eat lunch. eat = (food) -> "#{food} eaten." for food in ['toast', 'cheese', 'wine'] eat food # Fine five course dining. courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'] menu = (i, dish) -> "Menu Item #{i}: #{dish}" for dish, i in courses menu i + 1, dish # Health conscious meal. foods = ['broccoli', 'spinach', 'chocolate'] for food in foods if food isnt 'chocolate' then eat food ``` ```ahk global eat := Func("ahk_2") for __index_for__, food in ["toast", "cheese", "wine"] { eat.Call(food) } global courses := ["greens", "caviar", "truffles", "roast", "cake"] global menu := Func("ahk_1") for i, dish in courses { i := i - 1 menu.Call(i + 1, dish) } global foods := ["broccoli", "spinach", "chocolate"] for __index_for__, food in foods { if (food != "chocolate") { eat.Call(food) } } ahk_1(i, dish) { return "Menu Item " . (i) . ": " . (dish) . "" } ahk_2(food) { return "" . (food) . " eaten." } ``` 当循环对象时,使用`of`来替代`in````coffeescript yearsOld = max: 10, ida: 9, tim: 11 ages = [] for child, age of yearsOld ages.Push "#{child} is #{age}" ``` ```ahk global yearsOld := {max: 10, ida: 9, tim: 11} global ages := [] for child, age in yearsOld { ages.Push("" . (child) . " is " . (age) . "") } ``` ```coffeescript # Econ 101 if @studyingEconomics while supply > demand buy() until supply > demand sell() # Nursery Rhyme num = 6 lyrics = [] while num num = num - 1 lyrics.Push "#{num} little monkeys, jumping on the bed. One fell out and bumped his head." ``` ```ahk if (this.studyingEconomics) { while (supply > demand) { buy.Call() } while !(supply > demand) { sell.Call() } } global num := 6 global lyrics := [] while (num) { num := num - 1 lyrics.Push("" . (num) . " little monkeys, jumping on the bed. One fell out and bumped his head.") } ``` `until`相当于`while not``loop`相当于`while true`## 操作符与别名`Coffee-AHK``is`相当于`==``isnt`相当于`!=``not`相当于`!`的别名。 `and`相当于`&&``or`相当于`||`。 在`while``if`/`else``switch`/`when`语句中,`then`可以代替换行或分号,用于分隔表达式中的条件。 如同在`YAML`中那样,`on``yes`相当于`true``off``no`则相当于`false``unless`可以视作`if not`。 你可以使用`@property`作为`this.property`的缩写。 为了简化数学表达式,你也可以使用`**``//`。 总而言之: | `Coffee-AHK` | `AHK` | | :------------------: | :------: | | `is` | `==` | | `isnt` | `!=` | | `not` | `!` | | `and` | `&&` | | `or` | `\|\|` | | `true`, `yes`, `on` | `true` | | `false`, `no`, `off` | `false` | | `@`, `this` | `this` | | `a ** b` | `a ** b` | | `a // b` | `a // b` | ```coffeescript if ignition is on then launch() if band isnt SpinalTap then volume = 10 unless answer is no then letTheWildRumpusBegin() if car.speed < limit then accelerate() print inspect "My name is #{@name}" ``` ```ahk if (ignition == true) { launch.Call() } if (band != SpinalTap) { volume := 10 } if !(answer == false) { letTheWildRumpusBegin.Call() } if (car.speed < limit) { accelerate.Call() } print.Call(inspect.Call("My name is " . (this.name) . "")) ``` ## 链式调用 使用行首`.`来更简单地使用链式调用。 ```coffeescript $ 'body' .click (e) -> $ '.box' .fadeIn 'fast' .addClass 'show' .css 'background', 'white' ``` ```ahk $.Call("body").click.Call(Func("ahk_1").Bind($)).css.Call("background", "white") ahk_1($, e) { $.Call(".box").fadeIn.Call("fast").addClass.Call("show") } ``` ## 赋值解构`JavaScript`一样,`Coffee-AHK`支持赋值解构。当你将一个数组或对象文字赋值时,`Coffee-AHK`会将两边的值打散并相互匹配,将右边的值赋给左边的变量。这可以用于最简单的交换变量: ```coffeescript theBait = 1e3 theSwitch = 0 [theBait, theSwitch] = [theSwitch, theBait] ``` ```ahk global theBait := 1000 global theSwitch := 0 global __array__ := [theSwitch, theBait] theBait := __array__[1] theSwitch := __array__[2] ``` 或是实现非常实用的多返回函数: ```coffeescript weatherReport = (location) -> # Make an Ajax request to fetch the weather... return [location, 72, 'Mostly Sunny'] [city, temp, forecast] = weatherReport 'Berkeley, CA' ``` ```ahk global weatherReport := Func("ahk_1") global __array__ := weatherReport.Call("Berkeley, CA") global city := __array__[1] global temp := __array__[2] global forecast := __array__[3] ahk_1(location) { return [location, 72, "Mostly Sunny"] } ``` ## 类 由于`AHK`不区分大小写,请不要使用`item = new Item()`这种写法。而应该这么写:`item2 = new Item()````coffeescript class Animal constructor: (name) -> @name = name move: (meters) -> alert @name + " moved #{meters}m." class Snake extends Animal move: -> alert 'Slithering...' super.move 5 class Horse extends Animal move: -> alert 'Galloping...' super.move 45 sam = new Snake 'Sammy the Python' tom = new Horse 'Tommy the Palomino' sam.move() tom.move() ``` ```ahk class Animal { __New(name) { this.name := name } move := Func("ahk_3").Bind(alert).Bind(this) } class Snake extends Animal { move := Func("ahk_2").Bind(alert).Bind(this) } class Horse extends Animal { move := Func("ahk_1").Bind(alert).Bind(this) } global sam := new Snake("Sammy the Python") global tom := new Horse("Tommy the Palomino") sam.move.Call() tom.move.Call() ahk_1(alert, this) { alert.Call("Galloping...") base.move.Call(45) } ahk_2(alert, this) { alert.Call("Slithering...") base.move.Call(5) } ahk_3(alert, this, meters) { alert.Call(this.name + " moved " . (meters) . "m.") } ``` ## Switch/When/Else ```coffeescript switch day when 'Mon' then go work when 'Tue' then go relax when 'Thu' then go iceFishing when 'Fri', 'Sat' if day is bingoDay go bingo go dancing when 'Sun' then go church else go work ``` ```ahk switch day { case "Mon": { go.Call(work) } case "Tue": { go.Call(relax) } case "Thu": { go.Call(iceFishing) } case "Fri", "Sat": { if (day == bingoDay) { go.Call(bingo) go.Call(dancing) } } case "Sun": { go.Call(church) } default: { go.Call(work) } } ``` ## Try/Catch/Finally ```coffeescript try allHellBreaksLoose() catsAndDogsLivingTogether() catch error print error finally cleanUp() ``` ```ahk try { allHellBreaksLoose.Call() catsAndDogsLivingTogether.Call() } catch error { print.Call(error) } finally { cleanUp.Call() } ``` ## 模块 ```coffeescript import './local-file.coffee' import 'js-shim.ahk' # via npm import fn from './source/fn' import data from './data.json' import data2 from './data.yaml ``` ## 原生代码 如果你需要在代码中穿插一些原生`AHK`片段,你可以这么做: ```coffeescript hi = -> msg = 'Hello AHK' `MsgBox, % msg` ``` ```ahk global hi := Func("ahk_1") ahk_1() { msg := "Hello AHK" MsgBox, % msg } ```