-
Notifications
You must be signed in to change notification settings - Fork 0
/
stdlib.lzui
1250 lines (1102 loc) · 44.1 KB
/
stdlib.lzui
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#
# Library file (*.lzui)
#
# Standard functions
#
ZUI[stdlib_sourced]="1"
# Available colors to embed in generated text
#
# Excluded codes, recognized by curses, are: 010,
# 011, 012, 015, 033. Tabulation is handled by
# this library (conversion to spaces).
#
# Foreground range: $'\03'-$'\07' $'\013'-$'\014' $'\016'-$'\017'
# Background range: $'\020'-$'\030'. With BOLD it is ...-$'\031'
# Formatting codes range: $'\03'-$'\07' $'\013'-$'\014' $'\016'-$'\031'
#
# \01 and \02 are used by buttons, \032, \02 by text fields
# If one would want to use the lib without plugin...
typeset -gA ZUI
typeset -ga ZUI_MESSAGES
# Ends colors and bold
ZUI[FMT_END]=$'\037' # octal value, decimal 31 - Unit separator
# Foreground, excluded are 010, 011, 012, 015
ZUI[BLACK]=$'\03' # End of text
ZUI[RED]=$'\04' # End of transmission
ZUI[GREEN]=$'\05' # Enquiry
ZUI[YELLOW]=$'\06' # Acknowledge
ZUI[BLUE]=$'\07' # Bell
ZUI[MAGENTA]=$'\013' # Vertical tab
ZUI[CYAN]=$'\014' # Form feed
ZUI[WHITE]=$'\016' # Shift out
ZUI[DEFAULT]=$'\017' # Shift in
# Background, no exclusions
ZUI[BG_BLACK]=$'\020' # Data line escape
ZUI[BG_RED]=$'\021' # Device control 1
ZUI[BG_GREEN]=$'\022' # Device control 2
ZUI[BG_YELLOW]=$'\023' # Device control 3
ZUI[BG_BLUE]=$'\024' # Device control 4
ZUI[BG_MAGENTA]=$'\025' # Negative acknowledge
ZUI[BG_CYAN]=$'\026' # Synchronous idle
ZUI[BG_WHITE]=$'\027' # End transmission block
ZUI[BG_DEFAULT]=$'\030' # Cancel
# Bold
ZUI[BOLD]=$'\031' # End of medium
# Buttons' separator
ZUI[HYP_SEP]=$'\01'
# Text fields's separator
ZUI[FLD_SEP]=$'\032'
# List boxes' separator
ZUI[LST_SEP]=$'\034'
# Hyperlink end
ZUI[HYP_END]=$'\02'
# Special code used to mark active button
ZUI[MARK]=$'\035' # octal value, decimal 29 - Group separator
ZUI[MARK2]=$'\036' # octal value, decimal 30 - Record separator
ZUI[MARK_E]=$ZUI[FMT_END]
# FUNCTION: -zui_std_init {{{
# Initializes ZUI application. To be called before any emulate -L
# Can take two arguments, prefixed with app: or app_name:, to set
# ZUI[app] or ZUI[app_name]
function -zui_std_init() {
[[ -o interactivecomments ]] && ZUI[INTERACTIVE_COMMENTS]="1" || ZUI[INTERACTIVE_COMMENTS]="0"
[[ -o promptsubst ]] && ZUI[PROMPT_SUBST]="1" || ZUI[PROMPT_SUBST]="0"
ZUI[FIRST]=1
[[ "$1" = app:* ]] && ZUI[app]=${1#app:}
[[ "$2" = app:* ]] && ZUI[app]=${2#app:}
[[ "$1" = app_name:* ]] && ZUI[app_name]=${1#app_name:}
[[ "$2" = app_name:* ]] && ZUI[app_name]=${2#app_name:}
} # }}}
# FUNCTION: -zui_std_init2 {{{
# Initializes ZUI application. To
# be called after any emulate -L
function -zui_std_init2() {
unsetopt localoptions
[[ "${ZUI[PROMPT_SUBST]}" = "1" ]] && setopt promptsubst
[[ "${ZUI[INTERACTIVE_COMMENTS]}" = "1" ]] && setopt interactivecomments
[[ "${ZUI[app]}" != "${ZUI[messages_app]}" ]] && {
ZUI_MESSAGES=()
ZUI[message_count]=0
ZUI[messages_app]="${ZUI[app]}"
}
} # }}}
# FUNCTION: -zui_std_special_text {{{
# Appends special-text into output array. The text can contain special
# characters like ', `, (, [, space.
#
# $1 - text
# $2 - optional output array name
#
function -zui_std_special_text() {
local __text="$1"
local __var_name="${2:-reply}"
# Quote only text, not codes
__text="${__text//(#b)([^$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']##)/${(q)match[1]}}"
__var_name="${__var_name}[${(P)#__var_name}+1]"
local __output=$'\01'$'\01'$'\01'$'\01'$'\01'$'\02'"${__text}"$'\02'
unset __text
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_button_ext {{{
# Appends hyperlink into output array. It's an action button
# shown without surrounding "[" and "]".
#
# $1 - action ID
# $2 - data1, e.g. timestamp
# $3 - data2, e.g. command
# $4 - data3, e.g. active path
# $5 - data4, e.g. file path, file name, URL, other data
# $6 - text
# $7 - optional handler function name, can be empty text
# $8 - optional output variable name (defualt: 'reply')
#
# Output array is extended by hyperlink's text (one new element)
#
function -zui_std_button_ext() {
local __id="${(q)1}" __data1="${(q)2}" __data2="${(q)3}" __data3="${(q)4}" __data4="${(q)5}" __text="$6" __handler="$7"
local __var_name="${8:-reply}"
local pfx=""
[[ -n "$__handler" ]] && {
[[ $__handler = *internal* ]] && pfx="zuiiaction" || pfx="zuiaction"
ZUI[$pfx$__id]="$__handler"
}
# Quote only text, not codes
__text="${__text//(#b)([^$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']##)/${(q)match[1]}}"
__var_name="${__var_name}[${(P)#__var_name}+1]"
local __output=$'\01'"$pfx$__id"$'\01'"$__data1"$'\01'"$__data2"$'\01'"$__data3"$'\01'"$__data4"$'\02'"${__text}"$'\02'
unset pfx __id __data1 __data2 __data3 __data4 __text __handler
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_rc_button_ext {{{
# Appends hyperlink into output array. It's an action button
# shown with surrounding [ and ].
#
# Arguments are the same as in -zui_std_button_ext
#
function -zui_std_rc_button_ext() {
local __id="${(q)1}" __data1="${(q)2}" __data2="${(q)3}" __data3="${(q)4}" __data4="${(q)5}" __text="$6" __handler="$7"
local __var_name="${8:-reply}"
local pfx=""
[[ -n "$__handler" ]] && {
[[ $__handler = *internal* ]] && pfx="zuiiaction" || pfx="zuiaction"
ZUI[$pfx$__id]="$__handler"
}
# Quote only text, not codes
__text="${__text//(#b)([^$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']##)/${(q)match[1]}}"
__var_name="${__var_name}[${(P)#__var_name}+1]"
local __output=$'\01'"$pfx$__id"$'\01'"$__data1"$'\01'"$__data2"$'\01'"$__data3"$'\01'"$__data4"$'\02'"[${__text}]"$'\02'
unset pfx __id __data1 __data2 __data3 __data4 __text __handler
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_rc_button {{{
# Short rectangle button function - no user data
#
# $1 - action ID
# $2 - text
# $3 - optional handler function name, can be empty text
# $4 - optional output variable name (defualt: 'reply')
function -zui_std_rc_button() {
local __id="$1" __text="$2" __handler="$3" __var_name="${4:-reply}"
-zui_std_rc_button_ext "$__id" "" "" "" "" "$__text" "$__handler" "$__var_name"
}
# }}}
# FUNCTION: -zui_std_button {{{
# Short button function - no user data
#
# $1 - action ID
# $2 - text
# $3 - optional handler function name, can be empty text
# $4 - optional output variable name (defualt: 'reply')
function -zui_std_button() {
local __id="$1" __text="$2" __handler="$3" __var_name="${4:-reply}"
-zui_std_button_ext "$__id" "" "" "" "" "$__text" "$__handler" "$__var_name"
}
# }}}
# FUNCTION: -zui_std_anchor {{{
# Appends anchor hyperlink into "reply" output array
# (or to array given by name via $8).
#
# Arguments are initially the same as in -zui_std_\
# button, except:
#
# - the first data argument (data1, $2) needs to be
# index of line to jump to,
#
# - you normally also want to pass instance ID as data2
# (module, $3) and data3 (instance, $4) if you assign
# a handler that is shared between modules,
#
# - instead of handler you might use data3 and data4
# ($4 & $5) as a module regeneration instruction,
# i.e. pass e.g.: ",mod2_ice1," "arg", to regenerate
# some module numbered 2, instance 1, with passed
# user-data "arg".
#
# If the handler is external (i.e. doesn't have "internal"
# in its name), then it might too deploy list regeneration,
# by doing reply=( ",mod2_ice1," "arg"), for example.
#
# Anchor of which data3 matches ",*," is set to be external.
# If handler doesn't have word "internal" in its name, then
# anchor is also set to be external.
#
# Example call:
# -zui_std_anchor "regen1" "4" "" ",mod1_ice2," "$RANDOM" "[${ZUI[MAGENTA]}Regen${ZUI[FMT_END]}]"
#
# Generator has instance ID (mod and ice) in $1 and $2
# by the design of restart-regeneration loop. So, this
# instructs to regenerate module 1 instance 2, with no
# handler call, with $RANDOM as generator's third input
# - regeneration user-data. "4" is the line number on
# which the cursor will be placed.
#
function -zui_std_anchor() {
setopt localoptions extendedglob
local __id="${(q)1}" __data1="${(q)2}" __data2="${(q)3}" __data3="${(q)4}" __data4="${(q)5}" __text="$6" __handler="$7"
local __var_name="${8:-reply}"
# Set to some weird line that probably exists,
# to signal that anchor works, but input line
# number is incorrect
# [[ "$__data1" != <-> && "$__data1" != <->[-+]<-> ]] && __data1="1+0+0+0"
# With no handler do only no-restart jumps
local hpfx="zuiiaction" __pfx="zuianchor"
[[ -n "$__handler" ]] && {
[[ $__handler = *internal* ]] || { hpfx="zuiaction"; __pfx="zuieanchor"; }
ZUI[$hpfx$__id]="$__handler"
unset hpfx
} || {
# Passed a regeneration instruction?
# This will make link external, i.e.
# leading to list restart (so, it's
# "external" to the list; "internal"
# is ran within single list run).
[[ "$__data3" = ,*, ]] && __pfx="zuieanchor"
}
# Quote only text, not codes
__text="${__text//(#b)([^$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']##)/${(q)match[1]}}"
__var_name="${__var_name}[${(P)#__var_name}+1]"
local __output=$'\01'"$__pfx$__id"$'\01'"$__data1"$'\01'"$__data2"$'\01'"$__data3"$'\01'"$__data4"$'\02'"${__text}"$'\02'
: ${(PA)__var_name::=$__output}
# Store anchor's target line index
ZUI[$__pfx$__id]="$__data1"
} # }}}
# FUNCTION: -zui_std_text_field {{{
# Appends text-field hyperlink into output array (default: reply)
#
# $1 - action ID
# $2 - width parameter (min and max text width - padding with "_")
# $3 - start-index parameter - what part of string to show
# $4 - text parameter - name of parameter holding text
# $5 - data1
# $6 - data2
# $7 - data3
# $8 - handler (function name)
# $9 - optional output array name (default: reply)
#
function -zui_std_text_field() {
local __id="${(q)1}" __width_var="${(q)2}" __sidx_var="${(q)3}" __text_var="${(q)4}" __data1="${(q)5}" __data2="${(q)6}" __data3="${(q)7}" __handler="$8"
local __var_name="${9:-reply}"
[[ -n "$__handler" ]] && ZUI[zuitfield$__id]="$__handler"
__var_name="${__var_name}[${(P)#__var_name}+1]"
if (( ${(P)+${(Q)__width_var}} + ${(P)+${(Q)__sidx_var}} + ${(P)+${(Q)__text_var}} != 3 )); then
local __key_part=$RANDOM
ZUI[my_err_tfield_width_${__key_part}]=100
ZUI[my_err_tfield_sidx_${__key_part}]=1
ZUI[my_err_tfield_data_${__key_part}]="ERROR: Not all variables exist: ${(Q)__width_var}, ${(Q)__sidx_var}, ${(Q)__text_var}"
__width_var="ZUI\[my_err_tfield_width_${__key_part}\]"
__sidx_var="ZUI\[my_err_tfield_sidx_${__key_part}\]"
__text_var="ZUI\[my_err_tfield_data_${__key_part}\]"
fi
local __output=$'\032'"zuitfield$__id"$'\032'"$__data1"$'\032'"$__data2"$'\032'"$__data3"$'\032'"$__width_var"$'\032'"$__sidx_var"$'\032'"$__text_var"$'\02'
unset __id __module_idx __width_var __sidx_var __text_var __data1 __data2 __handler
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_list_box {{{
# Appends list-box hyperlink into output array (default: reply)
#
# $1 - action ID
# $2 - width parameter (min and max text width - padding with spaces)
# $3 - index parameter - what option is active
# $4 - options parameter - name of parameter holding ";" separated options
# $5 - data1
# $6 - data2
# $7 - data3
# $8 - handler (function name)
# $9 - optional output array name (default: reply)
#
function -zui_std_list_box() {
local __id="${(q)1}" __width_var="${(q)2}" __idx_var="${(q)3}" __opts_var="${(q)4}" __data1="${(q)5}" __data2="${(q)6}" __data3="${(q)7}" __handler="$8"
local __var_name="${9:-reply}"
[[ -n "$__handler" ]] && ZUI[zuilbox$__id]="$__handler"
__var_name="${__var_name}[${(P)#__var_name}+1]"
if (( ${(P)+${(Q)__width_var}} + ${(P)+${(Q)__idx_var}} + ${(P)+${(Q)__opts_var}} != 3 )); then
local __key_part=$RANDOM
ZUI[my_err_tfield_width_${__key_part}]=100
ZUI[my_err_tfield_idx_${__key_part}]=1
ZUI[my_err_tfield_data_${__key_part}]="ERROR: Not all variables exist: ${(Q)__width_var}, ${(Q)__idx_var}, ${(Q)__opts_var}"
__width_var="ZUI\[my_err_tfield_width_${__key_part}\]"
__idx_var="ZUI\[my_err_tfield_idx_${__key_part}\]"
__opts_var="ZUI\[my_err_tfield_data_${__key_part}\]"
fi
local __output=$'\034'"zuilbox$__id"$'\034'"$__data1"$'\034'"$__data2"$'\034'"$__data3"$'\034'"$__width_var"$'\034'"$__idx_var"$'\034'"$__opts_var"$'\02'
unset __id __width_var __idx_var __opts_var __data1 __data2 __data3 __handler
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_get_ganchor {{{
# Doesn't have data1 (normally index to jump to) nor other data, and
# also doesn't have handler. Returns anchor button that jumps to given
# GLOBAL anchor and calls its handler (which invokes -zui-standard-gl\
# obal-anchors-callback).
#
# $1 - module index
# $2 - instance index
# $3 - visible text of the anchor
# $4 - optional output array name
function -zui_std_get_ganchor() {
local __mod="$1" __ice="$2" __text="$3" __var_name="${4:-reply}"
# Quote only text, not codes
__text="${__text//(#b)([^$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']##)/${(q)match[1]}}"
__var_name="${__var_name}[${(P)#__var_name}+1]"
local __output=$'\01'"zuianchoraglobal_m${__mod}_i${__ice}"$'\01'""$'\01'""$'\01'""$'\01'""$'\02'"${__text}"$'\02'
: ${(PA)__var_name::=$__output}
} # }}}
# FUNCTION: -zui_std_decode_hyperlink {{{
# Decodes given button/anchor/raw hyperlink returning
# data contained. Testable - test to check if string
# was correctly decoded.
#
# $1 - hyperlink string
# $2 - optional output array name (default: "reply")
#
# $reply[1] - ID (of button, anchor or raw link)
# $reply[2] - data1
# $reply[3] - data2
# $reply[4] - data3
# $reply[5] - data4
#
function -zui_std_decode_hyperlink() {
local __var_name="${2:-reply}"
: ${(PA)__var_name::=}
if [[ "$1" = (#b)*$'\01'([^$'\01']#)$'\01'([^$'\01']#)$'\01'([^$'\01']#)$'\01'([^$'\01']#)$'\01'([^$'\02']#)$'\02'* ]]; then
local __id="${match[1]}" __data1="${match[2]}" __data2="${match[3]}" __data3="${match[4]}" __data4="${match[5]}"
local assgn_str="${__var_name}[1]"
: ${(P)assgn_str::=${(Q)__id}}
assgn_str="${__var_name}[2]"
: ${(P)assgn_str::=${(Q)__data1}}
assgn_str="${__var_name}[3]"
: ${(P)assgn_str::=${(Q)__data2}}
assgn_str="${__var_name}[4]"
: ${(P)assgn_str::=${(Q)__data3}}
assgn_str="${__var_name}[5]"
: ${(P)assgn_str::=${(Q)__data4}}
return 0
fi
return 1
} # }}}
# FUNCTION: -zui_std_decode_text_field {{{
# Decodes given text-field and returns data contained.
# Testable - test to check if hyperlink was correctly
# decoded.
#
# $1 - hyperlink string
# $2 - optional output array name (default: "reply")
#
# $reply[1] - ID (of action)
# $reply[2] - width parameter name
# $reply[3] - start-index parameter name
# $reply[4] - text parameter name
# $reply[5] - data1
# $reply[6] - data2
# $reply[7] - data3
#
function -zui_std_decode_text_field() {
local __var_name="${2:-reply}"
: ${(PA)__var_name::=}
# id [1] data1 [2] data2 [3] data3 [4] width_var [5] sidx_var [6] text_var [7]
if [[ "$1" = (#b)*$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\02']#)$'\02'* ]]; then
local __id="${match[1]}" __data1="${match[2]}" __data2="${match[3]}" __data3="${match[4]}" __width_var="${match[5]}" __sidx_var="${match[6]}" __param="${match[7]}"
local assgn_str="${__var_name}[1]"
: ${(P)assgn_str::=${(Q)__id}}
assgn_str="${__var_name}[2]"
: ${(P)assgn_str::=${(Q)__width_var}}
assgn_str="${__var_name}[3]"
: ${(P)assgn_str::=${(Q)__sidx_var}}
assgn_str="${__var_name}[4]"
: ${(P)assgn_str::=${(Q)__param}}
assgn_str="${__var_name}[5]"
: ${(P)assgn_str::=${(Q)__data1}}
assgn_str="${__var_name}[6]"
: ${(P)assgn_str::=${(Q)__data2}}
assgn_str="${__var_name}[7]"
: ${(P)assgn_str::=${(Q)__data3}}
return 0
fi
return 1
} # }}}
# FUNCTION: -zui_std_decode_list_box {{{
# Decodes given list-box and returns data contained.
# Testable - test to check if hyperlink was correctly
# decoded.
#
# $1 - hyperlink string
# $2 - optional output array name (default: "reply")
#
# $reply[1] - ID (of action)
# $reply[2] - width parameter name
# $reply[3] - start-index parameter name
# $reply[4] - text parameter name
# $reply[5] - data1
# $reply[6] - data2
# $reply[7] - data3
#
function -zui_std_decode_list_box() {
local __var_name="${2:-reply}"
: ${(PA)__var_name::=}
# id [1] data1 [2] data2 [3] data3 [4] width_var [5] idx_var [6] text_var [7]
if [[ "$1" = (#b)*$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\02']#)$'\02'* ]]; then
local __id="${match[1]}" __data1="${match[2]}" __data2="${match[3]}" __data3="${match[4]}" __width_var="${match[5]}" __idx_var="${match[6]}" __param="${match[7]}"
local assgn_str="${__var_name}[1]"
: ${(P)assgn_str::=${(Q)__id}}
assgn_str="${__var_name}[2]"
: ${(P)assgn_str::=${(Q)__width_var}}
assgn_str="${__var_name}[3]"
: ${(P)assgn_str::=${(Q)__idx_var}}
assgn_str="${__var_name}[4]"
: ${(P)assgn_str::=${(Q)__param}}
assgn_str="${__var_name}[5]"
: ${(P)assgn_str::=${(Q)__data1}}
assgn_str="${__var_name}[6]"
: ${(P)assgn_str::=${(Q)__data2}}
assgn_str="${__var_name}[7]"
: ${(P)assgn_str::=${(Q)__data3}}
return 0
fi
return 1
} # }}}
# FUNCTION: -zui_std_decode {{{
# Tries various decoding functions, testable. Returns (in REPLY)
# "1" if hyperlink (anchor, button, raw link), "2" if text field,
# "3" if list-box
#
# $1 - hyperlink
# $2 - output parameter name, for type (default: REPLY)
# $3 - output array name, for hyperlink data (default: reply)
function -zui_std_decode() {
local __out="${2:-REPLY}" __var_name="${3:-reply}"
: ${(PA)__var_name::=}
[[ "$1" = *$'\01'* ]] && { -zui_std_decode_hyperlink "$1" "$__var_name" && { : ${(P)__out::=1}; return 0; }; }
[[ "$1" = *$'\032'* ]] && { -zui_std_decode_text_field "$1" "$__var_name" && { : ${(P)__out::=2}; return 0; }; }
[[ "$1" = *$'\034'* ]] && { -zui_std_decode_list_box "$1" "$__var_name" && { : ${(P)__out::=3}; return 0; }; }
: ${(P)__out::=0}
return 1
} # }}}
# FUNCTION: -zui_std_get_stext {{{
#
# $1 - special-text string
# $2 - optional output parameter name (default: "REPLY")
#
# REPLY: decoded text contained in the special string
#
function -zui_std_get_stext() {
local __var_name="${2:-REPLY}"
if [[ "$1" = (#b)(*)$'\01'$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\02']#$'\02'([^$'\02']#)$'\02'(*) ]]; then
# Repeat the wrapping text, too
: ${(P)__var_name::=${match[1]}${(Q)match[2]}${match[3]}}
return 0
fi
return 1
} # }}}
# FUNCTION: -zui_std_strip_meta_data {{{
function -zui_std_strip_meta_data() {
local buf="$1"
# Remove hyperlinks
buf="${buf//(#b)$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\02']#$'\02'([^$'\02']#)$'\02'/${(Q)match[1]}}"
# id data1 data2 data3 width sidx text
buf="${buf//(#b)$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'([^$'\032']#)$'\032'([^$'\032']#)$'\032'([^$'\02']#)$'\02'/${(mr:${(P)${(Q)match[1]}}::_:)${(P)${(Q)match[3]}}[${(P)${(Q)match[2]}},-1]}}"
# id data1 data2 data3 width idx options text
buf="${buf//(#b)$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'([^$'\034']#)$'\034'([^$'\034']#)$'\034'([^$'\02']#)$'\02'/${(mr:${(P)${(Q)match[1]}}:: :)${(As:;:)${(P)${(Q)match[3]}}}[${(P)${(Q)match[2]}}]}}"
# Remove color marks
# [all] [fg] [bg] TEXT
buf="${buf//(#b)([$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'])([$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\017']|)([$'\020'-$'\030']|)([^${ZUI[FMT_END]}]#)${ZUI[FMT_END]}/$match[4]}"
# Mark 1
buf="${buf//(#b)${ZUI[MARK]}([^${ZUI[MARK_E]}]#)${ZUI[MARK_E]}/$match[1]}"
# Mark 2 (alternative for segments with background color)
buf="${buf//(#b)${ZUI[MARK2]}([^${ZUI[MARK_E]}]#)${ZUI[MARK_E]}/$match[1]}"
REPLY="$buf"
} # }}}
# FUNCTION: -zui_std_strip_color_codes {{{
function -zui_std_strip_color_codes() {
# [all] [fg] [bg] TEXT
REPLY="${1//[$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'$'\037']/}"
} # }}}
# FUNCTION: -zui_std_is_hyperlink {{{
# Checks if given text is a button/anchor/raw hyperlink
function -zui_std_is_hyperlink() {
[[ "$1" = *$'\01'[^$'\01']##$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\02']#$'\02'[^$'\02']#$'\02'* ]]
} # }}}
# FUNCTION: -zui_std_is_special_text {{{
# Checks if given text is a button/anchor/raw hyperlink
function -zui_std_is_special_text() {
[[ "$1" = *$'\01'$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\02']#$'\02'[^$'\02']#$'\02'* ]]
} # }}}
# FUNCTION: -zui_std_is_text_field {{{
# Checks if given text is a text field hyperlink
function -zui_std_is_text_field() {
# id data1 data2 data3 width_var sidx_var text_var
[[ "$1" = *$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\02']#$'\02'* ]]
} # }}}
# FUNCTION: -zui_std_is_list_box {{{
# Checks if given text is a list box hyperlink
function -zui_std_is_list_box() {
# id data1 data2 data3 width_var sidx_var text_var
[[ "$1" = *$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\02']#$'\02'* ]]
} # }}}
# FUNCTION: -zui_std_is_any_hyperlink {{{
# Tests if given text is a hyperlink. Returns (in REPLY)
# "1" if plain hyperlink (anchor, button, raw link), "2"
# if text field, "3" if list-box
#
# $1 - hyperlink
# $2 - output parameter name, for type (default: REPLY)
function -zui_std_is_any_hyperlink() {
local __out="${2:-REPLY}"
[[ "$1" = *$'\01'* ]] && { -zui_std_is_hyperlink "$1" && { : ${(P)__out::=1}; return 0; }; }
[[ "$1" = *$'\032'* ]] && { -zui_std_is_text_field "$1" && { : ${(P)__out::=2}; return 0; }; }
[[ "$1" = *$'\034'* ]] && { -zui_std_is_list_box "$1" && { : ${(P)__out::=3}; return 0; }; }
: ${(P)__out::=0}
return 1
} # }}}
# FUNCTION: -zui_std_has_any_hyperlinks {{{
# Checks if given text has any hyperlinks (buttons/anchors/raws,
# text fields, list boxes)
function -zui_std_has_any_hyperlinks() {
[[ "$1" = *$'\01'[^$'\01']##$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\01']#$'\01'[^$'\02']#$'\02'[^$'\02']#$'\02'* ]] ||
# id data1 data2 module index width_var sidx_var text_var
[[ "$1" = *$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\032']#$'\032'[^$'\02']#$'\02'* ]] ||
# id data1 data2 data3 width_var sidx_var text_var
[[ "$1" = *$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\034']#$'\034'[^$'\02']#$'\02'* ]]
} # }}}
# FUNCTION: -zui_std_pack_hyperlinks_into_box {{{
# Puts given links in a box, i.e. into sequence of lines
# that are limited in length. The sequence is returned
# in reply array. The length of a link is the length of
# its text, i.e. it doesn't include meta-data.
#
# $1 - box width (line length)
# $2 - max box height (i.e. max # of lines)
# $3 - hyperlink 1
# $4 - hyperlink 2
# $5 - ...
#
function -zui_std_pack_hyperlinks_into_box() {
local width="$1" max_height="$2"
shift 2
reply=()
local hyp_link __text new_line="" tmp pad
integer idx max_idx="${#}" text_len diff_len now_width=0 now_height=0
for (( idx=1; idx <= max_idx; idx ++ )); do
# The box is limited in height
(( now_height >= max_height )) && break
hyp_link="${@[idx]}"
__text="${hyp_link/(#b)$'\01'*$'\02'([^$'\02']#)$'\02'/${match[1]}}"
text_len="${#__text}"
# Will hyp_link fit into this line?
if [ "$now_width" != "0" ]; then
if (( now_width + text_len + 1 <= width )); then
now_width+=text_len+1
new_line+=" $hyp_link"
else
# The line will be too long, pad it and store
# it into the box array without current link
# – leave the link for next loop run
pad=""
(( width-now_width > 0 )) && pad="${(r:width-now_width:: :)pad}"
# Store the line into the box array
reply+=( "${new_line}${pad}" )
now_height+=1
# Next line – empty
new_line=""
now_width=0
# Repeat processing of current hyp_link
idx=idx-1
fi
else
if (( text_len <= width )); then
now_width+=text_len
new_line+="$hyp_link"
else
# Special case: a hyper-link that does
# not fit even when it's alone in line
diff_len=$(( ${#__text} - (width-2) ))
hyp_link="${hyp_link[1,-diff_len-1]}"
# Store the truncated button into box array
reply+=( "${hyp_link}.." )
now_height+=1
# Next line – empty
new_line=""
now_width=0
fi
fi
done
# Line that wasn't filled and store wasn't triggered
if [[ -n "$new_line" && "$now_height" -lt "$max_height" ]]; then
pad=""
(( width-now_width > 0 )) && pad="${(r:width-now_width:: :)pad}"
# Store the line into the box array
reply+=( "${new_line}${pad}" )
fi
#local tmp
#for tmp in "${reply[@]}"; do
# echo "| $tmp |" >> /tmp/reply
#done
} # }}}
# FUNCTION: -zui_std_load_config {{{
# Loads variable from configuration if it's older than
# e.g. 2 seconds. The point is: I expect users to not
# always manage ZUI hash well: forgot to call *cleanup,
# not reset ZUI[app], etc. This will be covered here:
# if config field in ZUI is fresh, less than say 2
# seconds old, it means it's probably correctly aimed
# at the ZUI application starting. If it's older, it's
# a stray value from previous app.
#
# This applies only to configuration variables stored in
# ZUI hash ($4 = ZUI\[*\]). Other target variables are
# just being read, without age examination.
#
# $1 - Zstyle variable to load, with "s:" or "b:" prefix
# for string or boolean
# $2 - default value, 0 or 1 for bools
# $3 - time limit
# $4 - output parameter to fill (name)
function -zui_std_load_config() {
local __ts=${EPOCHSECONDS:-0}
local __bool="${${${1##b:*}:+0}:-1}" __default="$2" __cvar="${${1#b:}#s:}" __time_limit="${3:-2}" __var_name="${4:-REPLY}"
local __key __value
local -a match mbegin mend
# Check if current ZUI[...] is fresh
if [[ "$__var_name" = (#b)ZUI\[(*)\] ]]; then
__key="${match[1]}_ts_"
# *_ts_ key in ZUI is older than __time_limit?
if [[ $(( __ts - __time_limit )) -gt "${ZUI[$__key]:-0}" || "$__ts" -eq 0 ]]; then
ZUI[$__key]=$__ts
else
return 0
fi
fi
# Global ZUI settings
if (( __bool )); then
if (( __default )); then
zstyle -T ":plugin:zui" "$__cvar" && : ${(P)__var_name::=1} || : ${(P)__var_name::=0}
else
zstyle -t ":plugin:zui" "$__cvar" && : ${(P)__var_name::=1} || : ${(P)__var_name::=0}
fi
else
zstyle -s ":plugin:zui" "$__cvar" __value || __value="$__default"
: ${(P)__var_name::=$__value}
fi
# Application - specific settings
[[ -n "${ZUI[app]}" ]] && {
local __zstyle_path=":plugin:zui:app:${ZUI[app]}"
if (( __bool )); then
zstyle -t $__zstyle_path "$__cvar" && : ${(P)__var_name::=1} || zstyle -T $__zstyle_path "$__cvar" || : ${(P)__var_name::=0}
else
zstyle -s $__zstyle_path "$__cvar" __value && : ${(P)__var_name::=$__value}
fi
}
return 0
} # }}}
# FUNCTION: -zui_std_refresh_configs {{{
# Causes -zui_std_load_config to think
# the configuration variable is freshly
# loaded. Use this when restarting list
# and updating ZUI[config] manually, with
# no Zstyle update
#
# $1, $2 ... – keys in ZUI to update, config
# variables' names
function -zui_std_refresh_configs() {
local ts=${EPOCHSECONDS:-0} config
(( ts == 0 )) && ts=$( date +%s )
for config in "$@"; do
(( ${+ZUI[$config]} )) && ZUI[${config}_ts_]=$ts
done
} # }}}
# FUNCTION: -zui_std_store_default_app_config {{{
# Stores given ZUI[app] configuration if it is not
# already set by user, i.e. if given Zstyle is empty,
# it is then set to given value, so that ZUI will
# read it as the application default, overriding ZUI
# global default.
#
# $1 - Zstyle variable to write, with "s:" or "b:" prefix
# for string or boolean
# $2 - value to write, 0 or 1 for bools
#
# Returns 0 if written, 1 if Zstyle was already set
function -zui_std_store_default_app_config() {
local cvar="${${1#b:}#s:}" value="$2" bool="${${${1##b:*}:+0}:-1}"
local zstyle_path=":plugin:zui:app:${ZUI[app]}" tmp
integer isset
# Establish if already set
if (( bool )); then
# Lets keep this as a fine piece of logic
if zstyle -t "$zstyle_path" "$cvar"; then
isset=1
else
zstyle -T "$zstyle_path" "$cvar" && isset=0 || isset=1
fi
else
zstyle -s "$zstyle_path" "$cvar" tmp && isset=1 || isset=0
fi
# Store if not set
if (( isset == 0 )); then
zstyle "$zstyle_path" "$cvar" "$value"
return 0
else
return 1
fi
} # }}}
# FUNCTION: -zui_std_cleanup {{{
# This function clears application data
# from $ZUI global hash. To be called at
# exit and at start of zui application
function -zui_std_cleanup() {
# Optimization to not recreate windows on list
# restart - but yes here, on app restart
(( ${+builtins[zcurses]} )) && {
if [[ -n "${zcurses_windows[(r)main]}" || -n "${zcurses_windows[(r)status]}" ]]; then
zcurses delwin main 2>/dev/null
zcurses delwin status 2>/dev/null
zcurses end
fi
}
local -a keys
# Anchors, checkboxes, actions, internal actions
keys=( ${ZUI[(I)zuianchor*]} ${ZUI[(I)zuieanchor*]} ${ZUI[(I)zuitfield*]} ${ZUI[(I)zuilbox*]}
${ZUI[(I)zuiaction*]} ${ZUI[(I)zuiiaction*]} ${ZUI[(I)fly_*]}
app app_name PROMPT_SUBST INTERACTIVE_COMMENTS GENERATION_TIME
# zui-list state fields
CURRENT_IDX FROM_WHAT_IDX_LIST_IS_SHOWN CURRENT_SEGMENT SEARCH_MODE SEARCH_BUFFER UNIQ_MODE TEXT_OFFSET PREV_SBUFFER PREV_SIDX
# zui-list working & configuration fields
REGENERATE_LIST IGNORE_MSG COLORING_PATTERN COLORING_COLOR COLORING_MATCH_MULTIPLE
# Configuration keys
text_mode text_mode_ts_
colorpair colorpair_ts_
border border_ts_
border_cp border_cp_ts_
bold bold_ts_
status_colorpair status_colorpair_ts_
status_border status_border_ts_
status_border_cp status_border_cp_ts_
status_bold status_bold_ts_
status_size status_size_ts_
mark mark_ts_
altmark altmark_ts_
mark2 mark2_ts_
altmark2 altmark2_ts_
select_mode select_mode_ts_
text_mode text_mode_ts_
text_select text_select_ts_
status_pointer status_pointer_ts_
log_append log_append_ts_
log_index log_index_ts_
log_size log_size_ts_
log_time_format log_time_format_ts_
log_colors log_colors_ts_
)
[[ -n "${ZUI[app]}" ]] && ZUI[previous_app]="${ZUI[app]}"
# Serialize?
if [[ "$1" = serialize* ]]; then
local dst="${${1#serialize}#:}"
-zui_std_serialize "${dst:-${ZUI[app]}}"
fi
local k
for k in "${keys[@]}" ${ZUI[(I)my_*]}; do
unset "ZUI[$k]"
done
(( ${+functions[-zui-standard-global-anchors-callback]} )) && unfunction -- -zui-standard-global-anchors-callback
(( ${+functions[-zui-standard-status-callback]} )) && unfunction -- -zui-standard-status-callback
(( ${+functions[-zui-standard-text-select-callback]} )) && unfunction -- -zui-standard-text-select-callback
(( ${+functions[-zui-standard-timeout-callback]} )) && unfunction -- -zui-standard-timeout-callback
# Deserialize?
if [[ "$1" = deserialize* ]]; then
local src="${${1#deserialize}#:}"
-zui_std_deserialize "${src:-${ZUI[app]}}"
fi
} # }}}
# FUNCTION: -zui_std_serialize {{{
# Stores my_* keys of ZUI hash into
# "serialized_${ZUI[app]}" key, which
# can be read with *deserialize() call
function -zui_std_serialize() {
local dst="${1:-${ZUI[app]}}"
local -a skeys
skeys=( ${ZUI[(I)my_*]} CURRENT_IDX FROM_WHAT_IDX_LIST_IS_SHOWN CURRENT_SEGMENT SEARCH_MODE SEARCH_BUFFER UNIQ_MODE TEXT_OFFSET PREV_SBUFFER PREV_SIDX )
local k out
for k in "${skeys[@]}"; do
(( ${+ZUI[$k]} )) && out+="${(q)k} ${(q)ZUI[$k]} "
done
ZUI[serialized_$dst]="${out% }"
} # }}}
# FUNCTION: -zui_std_deserialize {{{
# Reads ZUI[serialized_${ZUI[app]}] and maps
# the content onto ZUI keys, normally my_*
# keys. Use this to restore application state
# after exit and consecutive start.
function -zui_std_deserialize() {
local src="${1:-${ZUI[app]}}"
local -a data
data=( "${(Q@)${(z@)ZUI[serialized_$src]}}" )
if (( ${#data} % 2 == 0 && ${#data} > 0 )); then
ZUI+=( "${data[@]}" )
unset "ZUI[serialized_$src]"
fi
} # }}}
# FUNCTION: -zui_std_set_mod_factor {{{
# Modifies how many instances of a module should be generated.
# A regeneration (no on-the-fly support) should be called on
# the new instances.
#
# $1 - module index
# $2 - new factor
function -zui_std_set_mod_factor() {
local key="${zuiel_module_hash[(i)${1}_*]}"
zuiel_module_hash[$key]="$2"
} # }}}
# FUNCTION: -zui_std_get_mod_factor {{{
# Returns factor of given module (it's the number
# of instances of the module that are generated)
#
# $1 - module index
# $2 - output parameter name (default: REPLY)
function -zui_std_get_mod_factor() {
local __var_name="${2:-REPLY}" __key="${zuiel_module_hash[(i)${1}_*]}"
: ${(P)__var_name::=${zuiel_module_hash[$__key]}}
} # }}}
# FUNCTION: -zui_std_set_mod_spacing {{{
# It sets corresponding ZUI[SPACING_$mod_$ice] variable,
# which then can be read in generator, and returned via
# reply5, and from that point actually used in drawing,
# either on-the-fly, or via restart to zui-event-loop.
# So this is only a transport of data into generator, the
# thing that directly sets spacing is reply5. Spacing is
# the number of blank lines before the module's instance.
#
# TODO: on-the-fly regeneration ignores reply5
#
# $1 - module index
# $2 - instance index
# $3 - the spacing to set (i.e. number of blank lines)
function -zui_std_set_mod_spacing() {
ZUI[SPACING_${1}_${2}]="$3"
}
# }}}
# FUNCTION: -zui_std_get_mod_spacing {{{
# Gets module's spacing, either from the transport place
# - ZUI[SPACING_${mod}_${ice}] hash field, or from the
# destination place - mod${1}_ice${2}_spacing parameter
# directly used during on-the-fly generation or event-loop
# generation.
#
# Testable, but errors will not happen.
#
# $1 - module index
# $2 - instance index
# $3 - "tra" or "dst" - transport or destination
function -zui_std_get_mod_spacing() {
REPLY=1
if [[ "$3" = "tra" ]]; then
[[ "${+ZUI[SPACING_${1}_${2}]}" = "0" ]] && return 1
REPLY="${ZUI[SPACING_${1}_${2}]}"
return 0
fi
local __var_name="mod${1}_ice${2}_spacing"
[[ "${(P)+__var_name}" = "0" ]] && return 1
REPLY="${(P)var_name}"
return 0
}
# }}}
# FUNCTION: -zui_std_load_global_index_and_size {{{
# Use this to quickly load variables:
#
# - mod${midx}_ice${iidx}_global_index