prompt.tin 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分。
  4. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  5. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  6. */
  7. #var lib_ui_prompt[META] {
  8. {NAME} {提示栏插件}
  9. {DESC} {支持丰富的自定义选项,用户可用此模块定制自己的 UI。}
  10. {AUTHOR} {担子炮}
  11. };
  12. ///=== {
  13. ///// prompt 是 PaoTin++ 中非常重要的 UI 插件,现行 UI 的主要元素都是由 prompt 来支撑的。
  14. /////
  15. ///// prompt 插件把整个 TinTin++ 屏幕划分为七个区域,从上到下依次为:
  16. /////
  17. ///// Top line1
  18. ///// Top line2
  19. ///// ...
  20. ///// Top lineN
  21. ///// ----------- TopSepBar --------------
  22. ///// (游戏区)
  23. ///// ----------- MidSepBar --------------
  24. ///// Bot line1
  25. ///// Bot line2
  26. ///// ...
  27. ///// Bot lineN
  28. ///// ----------- BotSepBar --------------
  29. ///// <提示符>:(输入区)
  30. /////
  31. ///// 输入区前面的提示符部分可以用 API prompt.Change 来修改。
  32. /////
  33. ///// 除输入区和游戏区之外,剩下五个区域都可以定制,用来显示信息内容(以下称为字段)。
  34. ///// 每一行都可以有多个字段。字段在视觉上由两部分组成,字段标签和字段内容。
  35. ///// 其显示样式分别可以控制,并受到几个 prompt 特性的影响,下面会分别予以介绍。
  36. /////
  37. ///// 字段的编排是高度可定制的,每个字段的标签、内容、颜色、显示风格、行为属性,
  38. ///// 都可以通过自己修改 #list prompt-fields 来修改。下面是对 #list prompt-fields
  39. ///// 的格式说明,但不建议直接在此处修改变量,请通过 var/etc/ui-settings.tin 来修改。
  40. ///// prompt 模块在启动时会自动加载该文件。
  41. /////
  42. ///// #list prompt-fields 是一个列表,其中中每个元素是一个 tt++ table,代表一个字段。
  43. ///// tt++ table 由一组选项和与之对应的选项值来组成,用来说明想要定制的字段的选项。
  44. /////
  45. ///// 下面是所有可供设置的字段选项:
  46. /////
  47. ///// 1. place 枚举值 可选项: {Top|TopSepBar|MidSepBar|Bot|BotSepBar}
  48. ///// 希望将字段显示在屏幕上的什么位置。
  49. ///// 其中 {Top} 和 {Bot} 支持多行,其它三个只有一行。
  50. ///// 默认为 BotSepBar。
  51. /////
  52. ///// 2. line 自然数
  53. ///// 只有 place={Top|Bot} 才支持 line,代表第几行,最上面是第一行。
  54. ///// 默认为 1。
  55. /////
  56. ///// 3. order 自然数
  57. ///// 在同一行中的次序,默认按照在 list 中出现的顺序来排序。
  58. /////
  59. ///// 4. label 中英文字符串
  60. ///// 字段标签,每个字段都可以有一个标签,显示在内容前面。
  61. ///// 默认为空白。
  62. /////
  63. ///// 5. color tintin 格式的颜色代码,例如 <ddd>
  64. ///// 字段值的颜色,通过该选项可以为字段值指定一个与配色主题不一样的颜色。
  65. ///// 一般来说只有极个别选项才需要特别的颜色,没必要为每个选项都指定颜色,
  66. ///// 因为那样的话你还不如去设置配色主题,参见下面配色主题的设置。
  67. ///// 默认为空白,代表采用配色主题。
  68. /////
  69. ///// 6. name 英文字符串 不能为空
  70. ///// 字段名称,必须唯一,不能重复。
  71. /////
  72. ///// 7. width 整数
  73. ///// 字段内容的宽度,如果字段内容长度变化较大,可以设置一个固定宽度,以免晃动。
  74. ///// 默认为 0,表示按照内容长度自动适配。
  75. /////
  76. ///// 8. visibility 枚举值 {HideEmpty|HideCool|HideZero|HideLabel|HideAll|Always}
  77. ///// 含义如下:
  78. ///// * HideEmpty 如果字段内容为空则不予显示。
  79. ///// * HideCool 如果内容已陈旧则不予显示。请参考 cooldown 选项。
  80. ///// * HideZero 如果倒计时归零则不予显示。请参考 countdown 选项。
  81. ///// * HideLabel 仅显示字段内容,不显示字段标签。
  82. ///// * HideAll 什么也不显示,从面板上擦除该字段。
  83. ///// * Always 总是显示该字段的标签和内容。
  84. ///// 所有的 Hide* 选项自动拥有 HideEmpty 语义。
  85. ///// 默认为 HideEmpty。
  86. /////
  87. ///// 9. cooldown 非负整数
  88. ///// 该字段的有效时间。超过有效时间没有更新的字段将在视觉上予以弱化显示,以提醒
  89. ///// 用户。也就是说,如果 cooldown 不为 0,则该字段被更新时其标签将会以颜色主题
  90. ///// 中 HotLabel 所指定的风格显示(意指新鲜的内容),之后持续若干秒后,转为由
  91. ///// CoolLabel 所指定的风格显示(意指陈旧的内容)。
  92. ///// 持续时间由 cooldown 字段的值来决定,单位为秒。
  93. ///// 陈旧的内容遇到 visibility=HideCool 时则不予显示。
  94. ///// 如果 cooldown 为 0,则不会以 CoolLabel 风格显示。
  95. ///// 默认值为 0。
  96. /////
  97. ///// 10. countdown 枚举值 {Auto|Clock|Seconds}
  98. ///// 倒计时类型的字段。其内容为一个非负整数,代表需要倒计时的秒数,或者也可以夹杂
  99. ///// 于文字内容当中,此时文字内容中所有形如 (%d) 的内容将会被替换成倒计时显示。
  100. ///// 本插件会自动为该字段更新其内容,使得用户能够看到倒计时的效果。
  101. ///// 倒计时有两种显示样式,本选项设置为 Clock 时,显示为时钟样式(N天HH:MM:SS),
  102. ///// 设置为 Seconds 时,显示为读秒样式(N秒)。设置为 Auto 时则根据剩余时间长短,
  103. ///// 自动切换两种显示效果。
  104. ///// 倒计时类型的字段,如果同时设置了 visibility=HideZero,那么倒计时归零后会自动
  105. ///// 隐藏该字段。
  106. ///// 在倒计时存续期间,该字段的 cooldown 属性将会被抑制,直到倒计时归零后才起作用。
  107. ///// 这条规则确保倒计时字段即使设置了 visibility=HideCool,也至少会完成倒计时,而
  108. ///// 倒计时结束后,如果 cooldown 时间比倒计时时间还要长,则还会继续显示一段时间之
  109. ///// 后才会被隐藏。
  110. // };
  111. VAR {信息栏的字段列表} prompt-fields {};
  112. VAR {信息栏的默认配色主题} prompt-theme {
  113. {Disable}{<bbc>}
  114. {BusyColor}{<239>}
  115. {BattleColor}{<119>}
  116. {BattleBusyColor}{<599><119>}
  117. {TopSepBar}{<229>}
  118. {MidSepBar}{<229>}
  119. {BotSepBar}{<229>}
  120. {HotLabel}{<199><F399>}
  121. {CoolLabel}{<109>}
  122. {Value}{<299>}
  123. };
  124. VAR {信息栏的填充字符} prompt-padding {─};
  125. VAR {常用图标} prompt-icon {
  126. {DisableRefresh}{🚫}
  127. };
  128. VAR {热键绑定} global-key-bindings {
  129. {1} {{key}{\cos} {action}{prompt.ToggleSwitch}}
  130. };
  131. VAR {信息栏的顶部高度(自动计算)} prompt-top-max-line {0};
  132. VAR {信息栏的底部高度(自动计算)} prompt-bot-max-line {0};
  133. VAR {屏幕的宽度(自动更新)} prompt-screen-width {0};
  134. VAR {所有的字段值的字典} prompt-dict {};
  135. VAR {上次实际绘制屏幕的时间} prompt-refresh {
  136. {global}{false}
  137. {lines} {false}
  138. {prompt}{false}
  139. };
  140. VAR {命令输入提示符} prompt-prompt {Input};
  141. #func {lib_ui_prompt.Init} {
  142. load-file {etc/ui-settings.tin};
  143. #if { "@getenv{TERM_PROGRAM}" == "vscode" && "@getenv{TERM_PROGRAM_VERSION}" <= "1.81.1" } {
  144. #if { "$prompt-padding" == "─" } {
  145. #var prompt-padding {-};
  146. };
  147. };
  148. prompt.layout;
  149. #local _ @prompt.ScreenWidth{};
  150. prompt.Set {};
  151. prompt.bindKey;
  152. prompt.Enable;
  153. ttevent.Handle {SCREEN RESIZE} {prompt} {lib/ui} {prompt.resize};
  154. #return true;
  155. };
  156. #nop 构造布局,主要是设置 order 字段。;
  157. #alias {prompt.layout} {
  158. #local all-order {};
  159. #foreach {*prompt-fields[]} {idx} {
  160. #local field {$prompt-fields[$idx]};
  161. #local place {$field[place]};
  162. #local line {$field[line]};
  163. #local order {$field[order]};
  164. #local last @defaultNum{$all-order[$place/$line];0};
  165. #if { "$order" != "" } {
  166. #local order @defaultNum{$order;1};
  167. #if { $last < $order } {
  168. #local all-order[$place/$line] {$order};
  169. };
  170. };
  171. #else {
  172. math.Inc last;
  173. #var prompt-fields[$idx][order] {$last};
  174. #local all-order[$place/$line] {$last};
  175. };
  176. };
  177. };
  178. ///=== {
  179. ///// 下面是本模块的一些常用方法:
  180. /////
  181. // ## prompt.SetField <字段名称> <字段属性表格>
  182. // 重新设置指定的信息栏字段的属性,如果字段不存在,则添加一个新的字段。
  183. // 可供修改的属性请参考 HELP prompt。
  184. // };
  185. #alias {prompt.SetField} {
  186. #local name {%1};
  187. #local attrib {%2};
  188. #if { "$name" == "" } {
  189. xtt.Usage prompt.SetField;
  190. #return;
  191. };
  192. #local attr {};
  193. #foreach {*attrib[]} {attr} {
  194. #if { "$attr" != "{place|line|order|label|name|color|width|visibility|cooldown|countdown}" } {
  195. errLog 用法有误,不可识别的字段属性 $attr。;
  196. #return;
  197. };
  198. #local value {$attrib[$attr]};
  199. #if { "$attr" == "place" && "$value" != "{Top|TopSepBar|MidSepBar|Bot|BotSepBar}" } {
  200. errLog 用法有误,字段属性 place 的值只能是 {Top|TopSepBar|MidSepBar|Bot|BotSepBar} 其中之一。;
  201. #return;
  202. };
  203. #if { "$attr" == "visibility" && "$value" != "{HideEmpty|HideCool|HideZero|HideLabel|HideAll|Always}" } {
  204. errLog 用法有误,字段属性 visibility 的值只能是 {HideEmpty|HideCool|HideZero|HideLabel|HideAll|Always} 其中之一。;
  205. #return;
  206. };
  207. #if { "$attr" == "countdown" && "$value" != "{Auto|Clock|Seconds}" } {
  208. errLog 用法有误,字段属性 countdown 的值只能是 {Auto|Clock|Seconds} 其中之一。;
  209. #return;
  210. };
  211. };
  212. #local idx {};
  213. #foreach {*prompt-fields[]} {idx} {
  214. #local field {$prompt-fields[$idx]};
  215. #if { "$field[name]" == "$name" } {
  216. #var prompt-fields[$idx] {$field $attrib};
  217. #return;
  218. };
  219. };
  220. #if { "$attrib[place]" == "" } {
  221. errLog 用法有误,添加字段时,不能省略字段属性 place。;
  222. #return;
  223. };
  224. #if { "$attrib[place]" == "{Top|Bot}" && "$attrib[line]" == "" } {
  225. #local attrib[line] {1};
  226. };
  227. #list prompt-fields add {{{name}{$name} $attrib}};
  228. };
  229. ///=== {
  230. // ## prompt.Set <表格>
  231. // 将表格中指定的字段和值,设置到 prompt 字典中。如果配置文件中存在该字段的配置,
  232. // 则会显示到屏幕上。
  233. //
  234. // 参数是一个由字段名和字段值组成的表格,例如:
  235. //
  236. // #nop 为 note 字段设置值。;
  237. // prompt.Set {{note}{我是一条随手笔记}};
  238. //
  239. // #nop 对大多数字段而言,将值设置为空会隐藏该字段。;
  240. // prompt.Set {{note}{}};
  241. //
  242. // #nop 也可同时为多个字段设置值。;
  243. // prompt.Set {{foo}{一些值} {bar}{另一些值}};
  244. // };
  245. #alias {prompt.Set} {
  246. #local fields {%1};
  247. #local now {};
  248. #format now {%T};
  249. #local field {};
  250. #foreach {*fields[]} {field} {
  251. #var prompt-dict[$field] {
  252. {updateTime}{$now}
  253. {showTime}{$now}
  254. {value}{$fields[$field]}
  255. };
  256. };
  257. };
  258. ///=== {
  259. // ## prompt.SetAwhile <字段名> <字段值> [<持续时间>]
  260. // 设置字段值,被设置的字段值将立即显示在屏幕上,但会在一段时间后消失。
  261. // 如果省略持续时间,则默认为 5 秒。
  262. // };
  263. #alias {prompt.SetAwhile} {
  264. #local id {%1};
  265. #local value {%2};
  266. #local secs {%3};
  267. #if { "$secs" == "" } {
  268. #local secs {5};
  269. };
  270. prompt.Set {{$id}{$value}};
  271. #line sub {VARIABLES} {
  272. #delay prompt-set-awhile-$id {
  273. prompt.Set {{$id}{}};
  274. } {$secs};
  275. };
  276. };
  277. #nop 备份的之前的内容,只有新内容与当前正在显示的内容不同时,才会刷新。;
  278. #var prompt.current-content {};
  279. #nop 显示字段值;
  280. #alias {prompt.refresh} {
  281. #local topMaxLine {0};
  282. #local botMaxLine {0};
  283. #local topLines {};
  284. #local botLines {};
  285. #local topSepBar {};
  286. #local midSepBar {};
  287. #local botSepBar {};
  288. #foreach {*prompt-fields[]} {idx} {
  289. #local field {$prompt-fields[$idx]};
  290. #nop 如果全局开关已经禁用,则跳过所有字段,除了 BotSepBar;
  291. #if { "$prompt-dict[disable][value]" != "" } {
  292. #if { "$field[place]" != "BotSepBar" } {
  293. #continue;
  294. };
  295. };
  296. #if { "$field[visibility]" == "" } {
  297. #local field[visibility] {HideEmpty};
  298. };
  299. #switch {"$field[place]"} {
  300. #case {"Top"} {
  301. #while {1} {
  302. #if { $field[line] <= $topMaxLine } {
  303. #break;
  304. };
  305. #math topMaxLine {$topMaxLine + 1};
  306. #local topLines[$topMaxLine] {};
  307. };
  308. #if { "$field[order]" == "" } {
  309. #local field[order] {@math.Eval{ @math.Max{0;*topLines[$field[line]][]} + 1 }};
  310. };
  311. #local topLines[$field[line]][$field[order]] {$field};
  312. };
  313. #case {"Bot"} {
  314. #while {1} {
  315. #if { $field[line] <= $botMaxLine } {
  316. #break;
  317. };
  318. #math botMaxLine {$botMaxLine + 1};
  319. #local botLines[$botMaxLine] {};
  320. };
  321. #if { "$field[order]" == "" } {
  322. #local field[order] {@math.Eval{ @math.Max{0;*botLines[$field[line]][]} + 1 }};
  323. };
  324. #local botLines[$field[line]][$field[order]] {$field};
  325. };
  326. #case {"TopSepBar"} {
  327. #if { "$field[order]" == "" } {
  328. #local field[order] {@math.Eval{ @math.Max{0;*topSepBar[]} + 1 }};
  329. };
  330. #local topSepBar[$field[order]] {$field};
  331. };
  332. #case {"MidSepBar"} {
  333. #if { "$field[order]" == "" } {
  334. #local field[order] {@math.Eval{ @math.Max{0;*midSepBar[]} + 1 }};
  335. };
  336. #local midSepBar[$field[order]] {$field};
  337. };
  338. #case {"BotSepBar"} {
  339. #if { "$field[order]" == "" } {
  340. #local field[order] {@math.Eval{ @math.Max{0;*botSepBar[]} + 1 }};
  341. };
  342. #local botSepBar[$field[order]] {$field};
  343. };
  344. #default {
  345. #echo {字段 $field[name] 的配置有误,请检查。place=[%s]} {$field[place]};
  346. };
  347. };
  348. };
  349. #if { $topMaxLine > 0 || &topSepBar[] > 0 } {
  350. #math topMaxLine {$topMaxLine + 1};
  351. };
  352. #if { $botMaxLine > 0 && &midSepBar[] > 0 } {
  353. #math botMaxLine {$botMaxLine + 2};
  354. };
  355. #else {
  356. #local botMaxLine {1};
  357. };
  358. #local allBarColor {};
  359. #if { "$prompt-dict[busy][value]" == "true" } {
  360. #local allBarColor {$prompt-theme[BusyColor]};
  361. };
  362. #if { "$prompt-dict[battle][value]" == "true" } {
  363. #local allBarColor {$prompt-theme[BattleColor]};
  364. };
  365. #if { "$prompt-dict[battle][value]" == "true" && "$prompt-dict[busy][value]" == "true" } {
  366. #local allBarColor {$prompt-theme[BattleBusyColor]};
  367. };
  368. #if { "$prompt-dict[disable][value]" != "" } {
  369. #local allBarColor {$prompt-theme[Disable]};
  370. };
  371. #local content {};
  372. #list content create {};
  373. #local line {};
  374. #local delta {0};
  375. #foreach {*topLines[]} {line} {
  376. #local fields {$topLines[$line]};
  377. #local text {@__prompt_build_line__{{$fields}}};
  378. #if { $text[width] > 0 } {
  379. #local realLine {};
  380. #math realLine {$line - $delta};
  381. #list content {add} {{{line}{$realLine}{text}{$text[text]}}};
  382. };
  383. #else {
  384. #math delta {$delta + 1};
  385. #math topMaxLine {$topMaxLine - 1};
  386. };
  387. };
  388. #if { $topMaxLine > 0 } {
  389. #local text {@__prompt_build_line__{{$topSepBar}}};
  390. #if { $text[width] == 0 && $topMaxLine == 1 } {
  391. #math topMaxLine {0};
  392. };
  393. #else {
  394. #local barColor {$prompt-theme[TopSepBar]};
  395. #if { "$allBarColor" != "" } {#local barColor {$allBarColor}};
  396. #local text {@__prompt_fill_line__{{$text[text]};{$text[width]};$barColor}};
  397. #list content {add} {{{line}{$topMaxLine}{text}{$text}}};
  398. };
  399. };
  400. #if { $botMaxLine > 0 } {
  401. #local text {@__prompt_build_line__{{$botSepBar}}};
  402. #local barColor {$prompt-theme[BotSepBar]};
  403. #if { "$allBarColor" != "" } {#local barColor {$allBarColor}};
  404. #local text {@__prompt_fill_line__{{$text[text]};{$text[width]};$barColor}};
  405. #list content {add} {{{line}{-2}{text}{$text}}};
  406. };
  407. #local line {0};
  408. #if { &botLines[] > 0 } {
  409. #loop {&botLines[]} {1} {line} {
  410. #local fields {$botLines[$line]};
  411. #local text {@__prompt_build_line__{{$fields}}};
  412. #if { $text[width] > 0 } {
  413. #local realLine {};
  414. #math realLine {$line - $botMaxLine - 1};
  415. #list content {add} {{{line}{$realLine}{text}{$text[text]}}};
  416. };
  417. #else {
  418. #math botMaxLine {$botMaxLine - 1};
  419. };
  420. };
  421. };
  422. #if { &midSepBar[] > 0 || &botLines[] > 0 } {
  423. #local text {@__prompt_build_line__{{$midSepBar}}};
  424. #local barColor {$prompt-theme[MidSepBar]};
  425. #if { "$allBarColor" != "" } {#local barColor {$allBarColor}};
  426. #local text {@__prompt_fill_line__{{$text[text]};{$text[width]};$barColor}};
  427. #math line {$botMaxLine + 1};
  428. #list content {add} {{{line}{-$line}{text}{$text}}};
  429. };
  430. #if { "$prompt-top-max-line" != "$topMaxLine" || "$prompt-bot-max-line" != "$botMaxLine" } {
  431. #local lineWidth {@prompt.ScreenWidth{}};
  432. #local spaceLine {};
  433. #format spaceLine {%-${lineWidth}s} {};
  434. #local newMax {$topMaxLine};
  435. #while { $newMax < $prompt-top-max-line } {
  436. #math newMax {$newMax + 1};
  437. #echo {{$spaceLine}{$newMax}};
  438. };
  439. #local newMax {$botMaxLine + 1};
  440. #while { $newMax < $prompt-bot-max-line } {
  441. #math newMax {$newMax + 1};
  442. #echo {{$spaceLine}{-$newMax}};
  443. };
  444. #var prompt-top-max-line {$topMaxLine};
  445. #var prompt-bot-max-line {$botMaxLine};
  446. #split {$topMaxLine} {$botMaxLine};
  447. #var prompt.current-content {};
  448. #buffer end;
  449. };
  450. #local idx {};
  451. #foreach {*content[]} {idx} {
  452. #local line {$content[$idx]};
  453. #if { {$prompt.current-content[=$line[line]]} === {$line[text]} } {
  454. #continue;
  455. };
  456. #var prompt.current-content[=$line[line]] {$line[text]};
  457. #echo {{%s}{$line[line]}} {$line[text]};
  458. };
  459. #local prompt {$prompt-prompt};
  460. #if { "$prompt" != "" } {
  461. #echo {{$prompt}{-1}};
  462. };
  463. #cursor {redraw input};
  464. };
  465. #func {__prompt_build_line__} {
  466. #local fields {%1};
  467. #local text {};
  468. #local order {};
  469. #local lineWidth {0};
  470. #foreach {*fields[]} {order} {
  471. #local field {$fields[$order]};
  472. #local name {$field[name]};
  473. #local label {$field[label]};
  474. #local color {$field[color]};
  475. #local width {$field[width]};
  476. #local value {$prompt-dict[$name]};
  477. #local now {};
  478. #format now {%T};
  479. #nop 隐藏字段简单忽略就好。;
  480. #if { "$field[visibility]" == "HideAll" } {
  481. #continue;
  482. };
  483. #nop 所有的 Hide* 选项自动拥有 HideEmpty 语义。;
  484. #if { "$field[visibility]" == "Hide%*" && "$value[value]" == "" } {
  485. #continue;
  486. };
  487. #nop 检查是否是倒计时,以及倒计时是否已经归零;
  488. #local zero {undef};
  489. #if { "$field[countdown]" != "" } {
  490. #local seconds {};
  491. #math seconds {$now - $prompt-dict[$name][showTime]};
  492. #replace value[value] {^%+1..d$} {@__prompt_countdown__{&1;$seconds}};
  493. #replace value[value] {(%+1..d)} {(@__prompt_countdown__{&1;$seconds})};
  494. #if { "$value[value]" != "{[1-9][0-9]*|.*\([1-9][0-9]*\).*}" } {
  495. #local zero {true};
  496. };
  497. #else {
  498. #local zero {false};
  499. };
  500. #var {prompt-dict[$name][showTime]} {$now};
  501. #var {prompt-dict[$name][value]} {$value[value]};
  502. #replace value[value] {^%+1..d$} {@__prompt_show_countdown__{$field[countdown];&1}};
  503. #replace value[value] {(%+1..d)} {(@__prompt_show_countdown__{$field[countdown];&1})};
  504. };
  505. #nop 如果设置了 HideZero,那么倒计时归零时,不予显示该字段。;
  506. #if { "$field[visibility]" == "HideZero" && "$zero" == "true" } {
  507. #continue;
  508. };
  509. #nop 检查是否已经是冷却了的字段,倒计时字段当倒计时持续时不会变为冷却;
  510. #local cool {false};
  511. #if { $field[cooldown] > 0 && $now - $value[updateTime] > $field[cooldown] && "$zero" != "false" } {
  512. #local cool {true};
  513. };
  514. #nop 如果设置了 HideCool,那么内容冷却之后则不予显示;
  515. #if { "$field[visibility]" == "HideCool" && "$cool" == "true" } {
  516. #continue;
  517. };
  518. #nop 如果设置了 HideLabel,那么不显示标签;
  519. #if { "$field[visibility]" == "HideLabel" } {
  520. #local label {};
  521. };
  522. #if { "$label" != "" } {
  523. #nop 如果全局开关已经禁用,则忽略所有配色,全部显示为禁用色;
  524. #if { "$prompt-dict[disable][value]" != "" } {
  525. #replace label {^<{[a-zA-Z0-9]+}>} {};
  526. #local label {$prompt-theme[Disable]$label};
  527. };
  528. #else {
  529. #nop 否则根据内容的新鲜程度自动改变颜色;
  530. #if { "$cool" == "true" } {
  531. #replace label {^<{[a-zA-Z0-9]+}>} {};
  532. #local label {$prompt-theme[CoolLabel]$label};
  533. };
  534. #else {
  535. #local label {$prompt-theme[HotLabel]$label};
  536. };
  537. };
  538. #local label {$label<299> };
  539. };
  540. #if { "$field[visibility]" == "HideLabel" } {
  541. #local label {};
  542. };
  543. #if { "$color" == "" } {
  544. #local color {$prompt-theme[Value]};
  545. };
  546. #format value {$color%-${width}s<299>} {$value[value]};
  547. #math lineWidth {$lineWidth + @str.Width{$label} + @str.Width{$value}};
  548. #if { "$text" == "" } {
  549. #local text {$label$value};
  550. };
  551. #elseif { "$label$value" != "" } {
  552. #local text {$text $label$value};
  553. #math lineWidth {$lineWidth + 1};
  554. };
  555. };
  556. #return {{width}{$lineWidth}{text}{$text}};
  557. };
  558. #func {__prompt_countdown__} {
  559. #local value {%1};
  560. #local count {%2};
  561. #math value {$value - $count};
  562. #if { $value < 0 } {
  563. #local value {0};
  564. };
  565. #return {$value};
  566. };
  567. #func {__prompt_show_countdown__} {
  568. #local type {%1};
  569. #local secs {%2};
  570. #local ret {};
  571. #if { "$type" == "Seconds" } {
  572. #local ret {${secs}s};
  573. };
  574. #elseif { "$type" == "Auto" } {
  575. #if { $secs > 86400 } {
  576. #local day {};
  577. #math day {$secs / 86400};
  578. #local hour {};
  579. #math hour {($secs % 86400) / 3600};
  580. #format ret {%d天%d小时} {$day} {$hour};
  581. };
  582. #elseif { $secs > 3600 } {
  583. #local hour {};
  584. #math hour {$secs / 3600};
  585. #local mins {($secs % 3600) / 60};
  586. #format ret {%d小时%d分} {$hour} {$mins};
  587. };
  588. #elseif { $secs > 180 } {
  589. #local mins {};
  590. #math mins {$secs / 60};
  591. #math secs {$secs % 60};
  592. #format ret {00:%%02d:%%02d} {$mins} {$secs};
  593. };
  594. #else {
  595. #local ret {${secs}s};
  596. };
  597. };
  598. #elseif { "$type" == "Clock" } {
  599. #if { $secs > 86400 } {
  600. #local day {};
  601. #math day {$secs / 86400};
  602. #math secs {$secs % 86400};
  603. #format ret {%d天} {$day};
  604. };
  605. #local hour {};
  606. #local mins {};
  607. #math hour {$secs / 3600};
  608. #math secs {$secs % 3600};
  609. #math mins {$secs / 60};
  610. #math secs {$secs % 60};
  611. #format ret {%s%%02d:%%02d:%%02d} {$ret} {$hour} {$mins} {$secs};
  612. };
  613. #return {$ret};
  614. };
  615. #func {__prompt_fill_line__} {
  616. #local text {%1};
  617. #local width {%2};
  618. #local color {%3};
  619. #local newText {@str.Trim{$text}};
  620. #math width {$width + @str.Width{$newText} - @str.Width{$text}};
  621. #local screenWidth {$prompt-screen-width};
  622. #local leftLen {0};
  623. #local rightLen {0};
  624. #math leftLen {($screenWidth - $width) / 2 - 1};
  625. #math rightLen {$screenWidth - $leftLen - $width - 2};
  626. #local left {};
  627. #format {left} {%${leftLen}s} {};
  628. #replace {left} { } {$prompt-padding};
  629. #local right {};
  630. #format {right} {%${rightLen}s} {};
  631. #replace {right} { } {$prompt-padding};
  632. #if { $leftLen < 0 } {
  633. #format {newText} {%$screenWidth.${screenWidth}s} {$newText};
  634. #return {$newText};
  635. };
  636. #elseif { "$newText" == "" } {
  637. #return {$color$left$prompt-padding$prompt-padding$right<099>};
  638. };
  639. #else {
  640. #return {$color$left<299> $newText $color$right<099>};
  641. };
  642. };
  643. #alias {prompt.resize} {
  644. #var prompt-top-max-line {0};
  645. #var prompt-bot-max-line {0};
  646. #var prompt-screen-width {0};
  647. #local _ @prompt.ScreenWidth{};
  648. prompt.refresh;
  649. #buffer end;
  650. };
  651. #event {CATCH IAC SB NAWS} {#0};
  652. ///=== {
  653. // ## prompt.Disable
  654. // 禁止 prompt 更新。一般用作调试,可以防止 prompt 自身的运行产生的大量日志干扰调试。
  655. // 参见 prompt.Enable。
  656. // };
  657. #alias {prompt.Disable} {
  658. prompt.Set {{disable}{$prompt-icon[DisableRefresh]}};
  659. prompt.refresh;
  660. #untick prompt.refresh;
  661. };
  662. ///=== {
  663. // ## prompt.Enable
  664. // 允许 prompt 更新。
  665. // 参见 prompt.Disable。
  666. // };
  667. #alias {prompt.Enable} {
  668. prompt.Set {{disable}{}};
  669. Tick prompt.refresh {prompt.refresh} 1;
  670. };
  671. ///=== {
  672. // ## prompt.ToggleSwitch
  673. // 在 prompt.Disable 和 prompt.Enable 之间切换。
  674. // };
  675. #alias {prompt.ToggleSwitch} {
  676. #if { "$prompt-dict[disable][value]" == "" } {
  677. prompt.Disable;
  678. };
  679. #else {
  680. prompt.Enable;
  681. };
  682. };
  683. #alias {prompt.bindKey} {
  684. #local idx {};
  685. #foreach {*global-key-bindings[]} {idx} {
  686. #local key {$global-key-bindings[$idx][key]};
  687. #local code {$global-key-bindings[$idx][action]};
  688. #line sub var #macro {$key} {$code};
  689. };
  690. };
  691. ///=== {
  692. // ## prompt.Change <提示符>
  693. // 设置提示符,提示符位于屏幕最下方输入区的首部,用作指示整个游戏所处的状态。
  694. // };
  695. #alias {prompt.Change} {
  696. #local text {%1};
  697. #var prompt-prompt {$text};
  698. #echo {{\r\e[K$prompt-prompt}{-1}};
  699. };
  700. ///=== {
  701. // ## prompt.HotKeys
  702. // 显示系统已配置的热键清单。
  703. // 本命令也可写作 HOTKEYS,作用相同。
  704. // };
  705. #alias {HOTKEYS} {prompt.HotKeys};
  706. #alias {prompt.HotKeys} {
  707. #echo;
  708. #echo { <128>%-20s %-30s %-40s} {快捷键} {含义} {对应代码};
  709. #draw Yellow scroll line 1 1 1 90;
  710. #local idx {};
  711. #foreach {*global-key-bindings[]} {idx} {
  712. #local key {$global-key-bindings[$idx][key]};
  713. #local meaning {$global-key-bindings[$idx][meaning]};
  714. #local code {$global-key-bindings[$idx][action]};
  715. #replace key {\\c} {Ctrl+};
  716. #replace key {Ctrl+%.%+1..*} {Ctrl+&1 &2};
  717. #echo { %-20s %-30s %-40s}
  718. {$key} {$meaning} {$code};
  719. };
  720. #echo;
  721. okLog 快捷键中如果存在多个按键序列的,带加号的为一组,需要同时按下,其余依次按下即可。请注意区分大小写。;
  722. okLog 例如 Ctrl+o k 的正确按法是,先按下 Ctrl+o,然后松开双手,再按下 k。;
  723. okLog 如果快捷键以 ^ 开头,则意味着只有输入框为空时,它才会生效。;
  724. #echo;
  725. };
  726. ///=== {
  727. // ## prompt.Note <文本>
  728. // 发表一条随手笔记。随手笔记是个很实用的功能,可以把短期内需要用户注意的事情醒目地显示在屏幕上。
  729. // 本命令也可写作 NOTE,作用相同。
  730. // };
  731. #alias {NOTE} {prompt.Note};
  732. #alias {prompt.Note} {
  733. prompt.Set {{note}{%0}};
  734. #if { @isEmpty{%0} } {
  735. okLog 你轻轻地从笔记本上撕下一页,捏成一个纸团丢到了垃圾桶里。;
  736. };
  737. #else {
  738. okLog 你抬头看着远方,若有所思,接着又奋笔疾书,在笔记本上记下一些东西。;
  739. };
  740. };
  741. ///=== {
  742. // #@ prompt.ScreenWidth
  743. // 返回屏幕宽度。
  744. // };
  745. #func {prompt.ScreenWidth} {
  746. #if { $prompt-screen-width == 0 } {
  747. #screen get COLS prompt-screen-width;
  748. };
  749. #return {$prompt-screen-width};
  750. };
  751. #alias {prompt.test} {
  752. #local fullme {<219>很久没有进行机器人检查(fullme)了,任务奖励将受到影响。<299>};
  753. #local fullme {http://pkuxkx.com/antirobot/robot.php?filename=1576762922984895};
  754. prompt.Set { {URL}{$fullme} };
  755. prompt.Set {
  756. {pot}{357.75万}
  757. {exp}{7510.56万}
  758. {expSpd}{11.88万/小时}
  759. {profit}{308金币/小时}
  760. };
  761. prompt.Set {
  762. {job}{<171>乔峰}
  763. {stage}{寻找NPC}
  764. {area}{建康}
  765. {room}{中城}
  766. {npc}{庞九公}
  767. {type}{杀死}
  768. };
  769. };