event.tin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分
  4. ===========
  5. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  6. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  7. ===========
  8. */
  9. ///=== {
  10. ///// event 模块实现了一个事件驱动编程框架,
  11. ///// 提供基本的事件驱动编程 API,允许用户定义、发射、订阅事件。
  12. ///// };
  13. #var lib_event[META] {
  14. {NAME} {事件驱动编程框架}
  15. {DESC} {提供基本的事件驱动编程 API,允许用户定义、发射、订阅事件}
  16. {AUTHOR} {担子炮}
  17. {NOTE} {本文件属于 PaoTin++ 的一部分}
  18. };
  19. VAR {已注册的 PaoTin++ 事件句柄} gEventHandlers {};
  20. VAR {已定义的 PaoTin++ 事件列表} gValidEvent {};
  21. #func {lib_event.Init} {
  22. #return true;
  23. };
  24. #func {__xtt_event_name_is_valid__} {
  25. #local event {%1};
  26. #if { "$event" == "{[_a-zA-Z]([./_a-z A-Z0-9-]*[a-zA-Z0-9])?}" } {
  27. #return {true};
  28. };
  29. #return {false};
  30. };
  31. ///=== {
  32. // ## event.Define <名称> <类型> <模块> <说明>
  33. // 定义事件。事件在使用前必须先定义。事件经过定义后,可以用 event.List 查看。
  34. // 参数列表:
  35. // - 名称:标识事件的唯一名称,只能以拉丁字母或下划线开头,后面跟若干个
  36. // 字母、数字、下划线(_)、斜线(/)、小数点(.) 组成。其中三个
  37. // 标点符号不能出现在末尾,只能出现在中间。
  38. // - 类型:枚举值,{有参} 或者 {无参} 二选一。
  39. // 如果事件被定义为有参,则允许发射事件时携带参数,事件驱动会将
  40. // 参数传递给事件处理句柄。
  41. // - 模块:标识事件所属模块,一般来说事件发射方为事件所属模块。
  42. // 这里要用标准的 PaoTin++ 模块描述符。
  43. // - 说明:事件的简短说明。会出现在类似于 event.List 的用户交互界面。
  44. // };
  45. #alias {event.Define} {
  46. #local event {%1};
  47. #local type {%2};
  48. #local module {%3};
  49. #local desc {%4};
  50. #if { "@__xtt_event_name_is_valid__{{$event}}" != "true" } {
  51. xtt.Usage event.Define 事件名称不是合法的标识符名称;
  52. #return;
  53. };
  54. #if { "$type" == "" } {
  55. #local type {无参};
  56. };
  57. #if { "$type" != "{有参|无参}" } {
  58. xtt.Usage event.Define 事件类型参数值不正确;
  59. #return;
  60. };
  61. #var {gValidEvent[$event]} {
  62. {type}{$type}
  63. {module}{$module}
  64. {desc}{$desc}
  65. };
  66. };
  67. ///=== {
  68. // ## event.List
  69. // 列出所有已定义的事件,以及目前已注册在这些事件上面的钩子。
  70. // };
  71. #alias {event.List} {
  72. #local pattern {@default{{%1};%*}};
  73. #if { &gValidEvent[] <= 0 } {
  74. infoLog 尚未定义任何事件。;
  75. #return;
  76. };
  77. #echo {%h} { 已经定义的事件列表 };
  78. #echo {%-40s %-5s %-40s %s} {事件/已注册的钩子} {类型} {模块} {说明/代码};
  79. #echo {%-40s %-5s %-40s %s} {@str.Repeat{40;-}} {----} {@str.Repeat{40;-}} {------------};
  80. #local event {};
  81. #foreach {*gValidEvent[]} {event} {
  82. #local type {有参};
  83. #if { "$gValidEvent[$event][type]" == "{无参|}" } {
  84. #local type {无参};
  85. };
  86. #local module {$gValidEvent[$event][module]};
  87. #local desc {$gValidEvent[$event][desc]};
  88. #local event-line {};
  89. #format {event-line} {%-40s %-5s %-40s %s} {$event} {$type}
  90. {@genModuleLink{$module;MOD}} {$desc};
  91. #local eventShown {0};
  92. #local hookPattern {$pattern};
  93. #if { "$event/$module/$desc" == "%*$pattern%*" } {
  94. #local eventShown {1};
  95. #echo {%s} {$event-line};
  96. #local hookPattern {%*};
  97. };
  98. #local hookHiden {0};
  99. #local classCount {0};
  100. #local class {};
  101. #foreach {*gEventHandlers[$event][]} {class} {
  102. #local hook {};
  103. #math classCount {$classCount + 1};
  104. #local hookCount {0};
  105. #foreach {*gEventHandlers[$event][$class][]} {hook} {
  106. #local module {$gEventHandlers[$event][$class][$hook][module]};
  107. #if { "$class/$module/$hook" != "%*$hookPattern%*" } {
  108. #math hookHiden {$hookHiden + 1};
  109. #continue;
  110. };
  111. #if { ! $eventShown } {
  112. #local eventShown {1};
  113. #echo {%s} {$event-line};
  114. };
  115. #math hookCount {$hookCount + 1};
  116. #local lead {├};
  117. #if { $classCount == &gEventHandlers[$event][]
  118. && $hookCount == &gEventHandlers[$event][$class][] } {
  119. #local lead {╰};
  120. };
  121. #local hookStr {@str.FormatIfElse{"$class" != "ANY_CLASS";$hook(%s);$hook;$class}};
  122. #local len {1};
  123. #format len {%L} {$hookStr};
  124. #math len {36 - $len};
  125. #echo { $lead@str.Repeat{$len;─} %s %-40s %s}{$hookStr}
  126. {@genModuleLink{$module;MOD}}
  127. {$gEventHandlers[$event][$class][$hook][code]};
  128. };
  129. };
  130. #if { $eventShown && $hookHiden > 0 } {
  131. #echo { ╰@str.Repeat{5;─} %s %-40s %s}{以及其它 $hookHiden 项};
  132. };
  133. };
  134. #echo {%h} { <868>你可以用 event.List <838><正则表达式><868> 来进行模糊查询<898> };
  135. };
  136. ///=== {
  137. // ## event.Emit <事件名称> [<回调钩子通配符>] [<事件参数>]
  138. // 发射事件。这将导致与回调钩子通配符相匹配的回调钩子被立即执行。
  139. // 默认会触发所有注册在本事件下的事件回调钩子。
  140. // 你可以参考 event.Handle 理解什么是事件回调钩子。
  141. // };
  142. #alias {event.Emit} {
  143. #local event {%1};
  144. #local pHook {%2};
  145. #local args {%3};
  146. #if { "@__xtt_event_name_is_valid__{{$event}}" != "true" } {
  147. xtt.Usage event.Emit 事件名称不是合法的标识符名称;
  148. #return;
  149. };
  150. #if { "$gValidEvent[$event]" == "" } {
  151. xtt.Usage event.Emit {未定义的事件名称: $event};
  152. #return;
  153. };
  154. #local count {0};
  155. #local delivered {false};
  156. #local class {};
  157. #foreach {*gEventHandlers[$event][]} {class} {
  158. #local hook {};
  159. #foreach {*gEventHandlers[$event][$class][]} {hook} {
  160. #local options {$gEventHandlers[$event][$class][$hook][options]};
  161. #local code {$gEventHandlers[$event][$class][$hook][code]};
  162. #math count {$count + 1};
  163. #nop 如果发射事件时指定了 pHook,则只唤醒指定的 hook,注意这里的 pHook 支持通配符;
  164. #if { "$pHook" != "" && "$hook" != "$pHook" } {
  165. #continue;
  166. };
  167. #local delivered {true};
  168. dbgLog event => 事件「$event」即将投递给「$gEventHandlers[$event][$class][$hook][module]」模块的「$hook」。;
  169. #if { "$options[justOnce]" == "true" } {
  170. #unvar {gEventHandlers[$event][$class][$hook]};
  171. };
  172. #if { "$args" == "" || "$gValidEvent[$event][type]" == "无参" } {
  173. #line sub {escapes;var;func} $code;
  174. };
  175. #else {
  176. #line sub {escapes;var;func} $code {$args};
  177. };
  178. };
  179. };
  180. #if { $count == 0 } {
  181. dbgLog event => 事件「$event」已产生,但因为没有注册接受者所以无法投递。;
  182. };
  183. #elseif { @isFalse{$delivered} } {
  184. dbgLog event => 事件「$event」已产生,但因为没有与 {$pHook} 相匹配的接受者所以无法投递。;
  185. };
  186. };
  187. ///=== {
  188. // ## event.DelayEmit <事件名称> [<回调钩子通配符>] [<事件参数>]
  189. // 延迟发射事件。类似于 event.Emit,但是会在当前触发执行完毕之后再发射事件。
  190. // };
  191. #alias {event.DelayEmit} {
  192. #if { "@__xtt_event_name_is_valid__{%1}" != "true" } {
  193. xtt.Usage event.DelayEmit;
  194. #return;
  195. };
  196. #delay 0 {event.Emit %0};
  197. };
  198. #alias {event.handle} {
  199. #local event {%1};
  200. #local hook {%2};
  201. #local module {%3};
  202. #local code {%4};
  203. #local method {%5};
  204. #local options {%6};
  205. #if { "$event" == "" || "$hook" == "" || "$module" == "" || {$code} == {} } {
  206. xtt.Usage $method;
  207. #return;
  208. };
  209. #if { "@__xtt_event_name_is_valid__{{$event}}" != "true" } {
  210. xtt.Usage $method 事件名称不是合法的标识符名称;
  211. #return;
  212. };
  213. #local class {@default{$options[class];ANY_CLASS}};
  214. #if { "$class" != "ANY_CLASS" } {
  215. ttevent.HandleOnce {CLASS DESTROYED $class} {event} {event} {event.on-class-kill};
  216. };
  217. #var {gEventHandlers[$event][$class][$hook]} {
  218. {options}{$options}
  219. {module}{$module}
  220. {code}{$code}
  221. };
  222. };
  223. ///=== {
  224. // ## event.Handle <事件名称> <回调钩子> <所属模块> <回调代码>
  225. // 注册事件回调钩子。参数说明如下:
  226. // - 事件名称: 本钩子要关联的事件的名称,需要事先用 event.Define 声明。
  227. // - 回调钩子: 本次注册的钩子,可以在随后用来取消本钩子,或者当事件发射时,
  228. // 发射方可以用正则表达式指定要触发哪些钩子。
  229. // - 所属模块: 注册钩子所在的代码模块。必须是一个严格的 PaoTin++ 模块描述符。
  230. // - 回调代码: 用来指明钩子被回调时要执行的代码。
  231. // };
  232. #alias {event.Handle} {
  233. event.handle {%1} {%2} {%3} {%24} {event.Handle} {};
  234. };
  235. ///=== {
  236. // ## event.HandleOnce <事件名称> <回调钩子> <所属模块> <回调代码>
  237. // 同 event.Handle,但是本钩子只会被执行一次,然后会自动注销。
  238. // };
  239. #alias {event.HandleOnce} {
  240. event.handle {%1} {%2} {%3} {%24} {event.HandleOnce} {{justOnce}{true}};
  241. };
  242. ///=== {
  243. // ## event.ClassHandle <事件名称> <回调钩子> <所属模块> <回调代码>
  244. // 同 event.Handle,但会在当前 #class 消亡时自动注销。
  245. // };
  246. #alias {event.ClassHandle} {
  247. #info session save;
  248. #local class {$info[SESSION][CLASS]};
  249. #unvar info[SESSION];
  250. event.handle {%1} {%2} {%3} {%24} {event.ClassHandle} {{class}{$class}};
  251. #class $class open;
  252. };
  253. ///=== {
  254. // ## event.ClassHandleOnce <事件名称> <回调钩子> <所属模块> <回调代码>
  255. // 同 event.HandleOnce,但会在当前 #class 消亡时自动注销。
  256. // };
  257. #alias {event.ClassHandleOnce} {
  258. #info session save;
  259. #local class {$info[SESSION][CLASS]};
  260. #unvar info[SESSION];
  261. event.handle {%1} {%2} {%3} {%24} {event.ClassHandleOnce} {{justOnce}{true}{class}{$class}};
  262. #class $class open;
  263. };
  264. ///=== {
  265. // ## event.UnHandle <事件名称> <事件回调钩子名称>
  266. // 注销已注册的事件回调钩子。
  267. // };
  268. #alias {event.UnHandle} {
  269. #local event {%1};
  270. #local hook {%2};
  271. #if { "$event" == "" || "$hook" == "" } {
  272. xtt.Usage event.UnHandle;
  273. #return;
  274. };
  275. #if { "@__xtt_event_name_is_valid__{{$event}}" != "true" } {
  276. xtt.Usage event.UnHandle 事件名称不是合法的标识符名称;
  277. #return;
  278. };
  279. #local class {};
  280. #foreach {*gEventHandlers[$event][]} {class} {
  281. #unvar {gEventHandlers[$event][$class][$hook]};
  282. };
  283. };
  284. VAR {已注册的 TinTin++ 事件句柄} gTTEventHandlers {};
  285. VAR {当前正在处理的 TinTin++ 事件名称} gTTEventName {};
  286. VAR {当前正在处理的 TinTin++ 事件 %0} gTTEventArgZero {};
  287. #alias {ttevent.handle} {
  288. #local event {%1};
  289. #local hook {%2};
  290. #local module {%3};
  291. #local code {%4};
  292. #local method {%5};
  293. #local options {%6};
  294. #if { "$event" == "" || "$hook" == "" || "$module" == "" || {$code} == {} } {
  295. xtt.Usage $method;
  296. #return;
  297. };
  298. #if { "$event" != "{[A-Za-z0-9./ -]+}" } {
  299. xtt.Usage $method 事件名称不是合法的标识符名称;
  300. #return;
  301. };
  302. #local class {@default{$options[class];ANY_CLASS}};
  303. #if { "$class" != "ANY_CLASS" } {
  304. ttevent.HandleOnce {CLASS DESTROYED $class} {event} {event} {event.on-class-kill};
  305. };
  306. #if { &gTTEventHandlers[$event][$class][] == 0 } {
  307. #class data/lib/event open;
  308. #line quiet #line sub var #event {$event} {
  309. #var gTTEventName {$event};
  310. #var gTTEventArgZero {%%0};
  311. #var gTTEventArgv {
  312. {1} {%%1} {2} {%%2} {3} {%%3} {4} {%%4} {5} {%%5}
  313. {6} {%%6} {7} {%%7} {8} {%%8} {9} {%%9}
  314. };
  315. ttevent.emit;
  316. };
  317. #class data/lib/event close;
  318. };
  319. #var {gTTEventHandlers[$event][$class][$hook]} {
  320. {options}{$options}
  321. {module}{$module}
  322. {code}{$code}
  323. };
  324. };
  325. #alias {ttevent.emit} {
  326. #local event {$gTTEventName};
  327. #local count {0};
  328. #local delivered {false};
  329. #local class {};
  330. #foreach {*gTTEventHandlers[$event][]} {class} {
  331. #local hook {};
  332. #foreach {*gTTEventHandlers[$event][$class][]} {hook} {
  333. #local options {$gTTEventHandlers[$event][$class][$hook][options]};
  334. #local code {$gTTEventHandlers[$event][$class][$hook][code]};
  335. #local delivered {true};
  336. dbgLog ttevent => 事件「$event」即将投递给「$gTTEventHandlers[$event][$class][$hook][module]」模块的「$hook」。;
  337. #if { "$options[justOnce]" != "true" } {
  338. #math count {$count + 1};
  339. };
  340. #else {
  341. #unvar {gTTEventHandlers[$event][$class][$hook]};
  342. #if { &gTTEventHandlers[$event][$class][] == 0 } {
  343. #unvar {gTTEventHandlers[$event][$class]};
  344. #if { &gTTEventHandlers[$event][] == 0 } {
  345. #unvar {gTTEventHandlers[$event]};
  346. };
  347. };
  348. };
  349. #line sub {escapes;var;func} $code;
  350. };
  351. };
  352. #if { $count == 0 } {
  353. #unevent {$event};
  354. };
  355. #if { @isFalse{$delivered} } {
  356. dbgLog ttevent => 事件「$event」已产生,但因为没有注册接受者所以无法投递。;
  357. };
  358. };
  359. ///=== {
  360. // ## ttevent.Handle <事件名称> <回调钩子> <所属模块> <回调代码>
  361. // 注册 #event 事件回调钩子。参数说明如下:
  362. // - 事件名称: 本钩子要关联的事件的名称,参考 #help event。
  363. // - 回调钩子: 本次注册的钩子,可以在随后用来取消本钩子。
  364. // - 所属模块: 注册钩子所在的代码模块。必须是一个严格的 PaoTin++ 模块描述符。
  365. // - 回调代码: 用来指明钩子被回调时要执行的代码。
  366. // };
  367. #alias {ttevent.Handle} {
  368. ttevent.handle {%1} {%2} {%3} {%24} {ttevent.Handle} {};
  369. };
  370. ///=== {
  371. // ## ttevent.HandleOnce <事件名称> <回调钩子> <所属模块> <回调代码>
  372. // 同 ttevent.Handle,但是本钩子只会被执行一次,然后会自动注销。
  373. // };
  374. #alias {ttevent.HandleOnce} {
  375. ttevent.handle {%1} {%2} {%3} {%24} {ttevent.HandleOnce} {{justOnce}{true}};
  376. };
  377. ///=== {
  378. // ## ttevent.ClassHandle <事件名称> <回调钩子> <所属模块> <回调代码>
  379. // 同 ttevent.Handle,但会在当前 #class 消亡时自动注销。
  380. // };
  381. #alias {ttevent.ClassHandle} {
  382. #info session save;
  383. #local class {$info[SESSION][CLASS]};
  384. #unvar info[SESSION];
  385. ttevent.handle {%1} {%2} {%3} {%24} {ttevent.ClassHandle} {{class}{$class}};
  386. #class $class open;
  387. };
  388. ///=== {
  389. // ## ttevent.ClassHandleOnce <事件名称> <回调钩子> <所属模块> <回调代码>
  390. // 同 ttevent.HandleOnce,但会在当前 #class 消亡时自动注销。
  391. // };
  392. #alias {ttevent.ClassHandleOnce} {
  393. #info session save;
  394. #local class {$info[SESSION][CLASS]};
  395. #unvar info[SESSION];
  396. ttevent.handle {%1} {%2} {%3} {%24} {ttevent.ClassHandleOnce} {{justOnce}{true}{class}{$class}};
  397. #class $class open;
  398. };
  399. ///=== {
  400. // ## ttevent.UnHandle <事件名称> <事件回调钩子名称>
  401. // 注销已注册的事件回调钩子。
  402. // };
  403. #alias {ttevent.UnHandle} {
  404. #local event {%1};
  405. #local hook {%2};
  406. #if { "$event" == "" || "$hook" == "" } {
  407. xtt.Usage ttevent.UnHandle;
  408. #return;
  409. };
  410. #if { "$event" != "{[A-Za-z0-9. -]+}" } {
  411. xtt.Usage ttevent.UnHandle 事件名称不是合法的标识符名称;
  412. #return;
  413. };
  414. #local count {0};
  415. #local class {};
  416. #foreach {*gTTEventHandlers[$event][]} {class} {
  417. #unvar {gTTEventHandlers[$event][$class][$hook]};
  418. #math count {$count + &gTTEventHandlers[$event][$class][]};
  419. #if { &gTTEventHandlers[$event][$class][] == 0 } {
  420. #unvar {gTTEventHandlers[$event][$class]};
  421. #if { &gTTEventHandlers[$event][] == 0 } {
  422. #unvar {gTTEventHandlers[$event]};
  423. };
  424. };
  425. };
  426. #if { $count == 0 } {
  427. #unevent {$event};
  428. };
  429. };
  430. /*
  431. 对于 TinTin++ 而言,考虑到性能,这里只删钩子,不注销 #event 本身。
  432. 注销动作延迟到下一次 event 被触发时进行。
  433. */
  434. #alias {event.on-class-kill} {
  435. #local class {$gTTEventArgZero};
  436. #local event {};
  437. #foreach {*gEventHandlers[]} {event} {
  438. #unvar {gEventHandlers[$event][$class]};
  439. #if { &gEventHandlers[$event][] == 0 } {
  440. #unvar {gEventHandlers[$event]};
  441. };
  442. };
  443. #foreach {*gTTEventHandlers[]} {event} {
  444. #unvar {gTTEventHandlers[$event][$class]};
  445. #if { &gTTEventHandlers[$event][] == 0 } {
  446. #unvar {gTTEventHandlers[$event]};
  447. #unevent {$event};
  448. };
  449. };
  450. };