Compare commits

...

1155 Commits

Author SHA1 Message Date
Christopher Jeffrey (JJ)
eab243fc7a Merge pull request #214 from dbkaplun/strict-mode-fixes
strict mode fixes
2016-01-04 00:13:40 -08:00
Dan Kaplun
ba1982d4a9 Replace octal parseInt with hex literal 2016-01-04 02:50:49 -05:00
Dan Kaplun
62b439ef8e strict mode fixes 2016-01-03 18:32:58 -05:00
Christopher Jeffrey
1c20b8b2ee improve listtable. 2015-12-22 02:03:40 -08:00
Christopher Jeffrey
04ffa283ac unicode env vars. 2015-09-07 05:14:10 -07:00
Christopher Jeffrey
10edaa088b use telnet2 for example. 2015-09-02 18:48:05 -07:00
Christopher Jeffrey
a45575fee6 v0.1.81 2015-09-02 18:31:21 -07:00
Christopher Jeffrey
e4900bb037 add "event" for any event. fixes #171. 2015-08-31 20:50:10 -07:00
Christopher Jeffrey
793646955f stop image animation on destroy. improve test. 2015-08-25 20:49:59 -07:00
Christopher Jeffrey
7a1a979632 add test for blessed+term.js. see #168. 2015-08-18 03:30:31 -07:00
Christopher Jeffrey
05dcd84216 minor: reset error on tput. 2015-08-18 02:24:10 -07:00
Christopher Jeffrey
5ccc80d8b8 browserify: use xterm-256color. fix transform on windows. fixes #167. 2015-08-18 02:23:42 -07:00
Christopher Jeffrey
1ae8604964 always reset global instances. 2015-08-14 00:40:25 -07:00
Christopher Jeffrey
1b0d912814 ansi viewer image. 2015-08-11 17:05:47 -07:00
Christopher Jeffrey
5d5fa05d8e fix multiple screen finding. throw errors on edge cases. 2015-08-11 07:16:36 -07:00
Christopher Jeffrey
19f61aba7f clear screen text buffer on term switch. 2015-08-11 03:25:50 -07:00
Christopher Jeffrey
607dc29dbb check for parm_*_cursor terminfo on program.cu[udbf]. 2015-08-11 03:01:01 -07:00
Christopher Jeffrey
a1ddc1443c renderer: check for parm_right_cursor before using it. 2015-08-11 02:57:02 -07:00
Christopher Jeffrey
f1d16950c5 unicode: cleanup combining table. 2015-08-11 00:02:03 -07:00
Christopher Jeffrey
142b5e070d add .jshintrc and .jscsrc. 2015-08-10 22:58:33 -07:00
Christopher Jeffrey
a79e8106ea cleanup and fixes. 2015-08-10 22:57:01 -07:00
Christopher Jeffrey
5e143e7fe5 v0.1.80. see #165. 2015-08-10 10:48:26 -07:00
Christopher Jeffrey
b7c5f0f2f2 add screen.realloc() method. 2015-08-09 17:35:34 -07:00
Christopher Jeffrey
364a56f4dc v0.1.21 2015-08-09 03:25:03 -07:00
Christopher Jeffrey
e317355a5e update readme. 2015-08-09 03:20:53 -07:00
Christopher Jeffrey
2934ac6408 improve forceUnicode. 2015-08-09 03:20:41 -07:00
Christopher Jeffrey
c1670137ae enable full unicode for blessed-telnet example. 2015-08-09 03:14:03 -07:00
Christopher Jeffrey
20636913e5 blessed-telnet improvement. 2015-08-08 17:20:32 -07:00
Christopher Jeffrey
f6a19a57e9 always lowercase terminal name. debug messages for blessed-telnet. 2015-08-08 15:02:53 -07:00
Christopher Jeffrey
524a922880 fix default blessed-telnet test. 2015-08-08 05:04:06 -07:00
Christopher Jeffrey
802e4ddc48 refactor and improve blessed-telnet. 2015-08-07 21:07:55 -07:00
Christopher Jeffrey
29c9d1529a fix terminal element destroy. do not render if screen is destroyed. 2015-08-07 21:02:16 -07:00
Christopher Jeffrey
b54e86d361 call screen.destroy instead of process.exit in tests. 2015-08-07 21:00:31 -07:00
Christopher Jeffrey
7e0104ef42 blessed-telnet: termtype. 2015-08-06 03:33:00 -07:00
Christopher Jeffrey
d7933adfb0 blessed-telnet: handle env variables. 2015-08-06 03:27:18 -07:00
Christopher Jeffrey
a8b1764ec6 padding warning. 2015-08-06 01:50:17 -07:00
Christopher Jeffrey
216aaf1f48 fix NO_PADDING detection. 2015-08-06 00:35:22 -07:00
Christopher Jeffrey
0547509481 add a small Tput.print helper function. 2015-08-06 00:13:03 -07:00
Christopher Jeffrey
45b180174f disable * padding for now. 2015-08-06 00:03:59 -07:00
Christopher Jeffrey
64072411bb fix setTerminal. add termswitch test. 2015-08-05 23:54:48 -07:00
Christopher Jeffrey
9b5673edf7 automatically call setTerminal on terminal setter. 2015-08-05 23:30:07 -07:00
Christopher Jeffrey
3df75398a0 improve screen.setTerminal. 2015-08-05 21:27:08 -07:00
Christopher Jeffrey
210c33d076 add setTerminal(). use terminal option always for consistency. 2015-08-05 20:58:20 -07:00
Christopher Jeffrey
72586faef9 fix bigtext. whitespace. 2015-08-05 18:52:31 -07:00
Christopher Jeffrey (JJ)
41a354c571 Merge pull request #164 from anko/parse-tags-fix
Add failing test for helpers.parseTags
2015-08-05 18:35:09 -07:00
Christopher Jeffrey
e6a5b0cac9 lazily load Screen in helpers.js. fixes #164. 2015-08-05 17:59:18 -07:00
An Ko
ecf08f4ba7 Add failing test for helpers.parseTags
a4d56fb moved the function from here 99f9d622e6/lib/widget.js (L9607-L9610) to its own file, but didn't fill in any reference for the Screen variable.
2015-08-05 18:41:40 +02:00
Christopher Jeffrey
54430504d1 refactor screen finding. 2015-08-05 07:49:17 -07:00
Christopher Jeffrey
730dd59b39 set screen when appending a node. 2015-08-05 07:28:02 -07:00
Christopher Jeffrey
90c441a329 add multiple screen docs and telnet server example. 2015-08-05 07:22:06 -07:00
Christopher Jeffrey
b068a8d036 cleanup. 2015-08-05 05:06:07 -07:00
Christopher Jeffrey
0d86165122 ensure screen and program globals are reset. 2015-08-05 05:02:37 -07:00
Christopher Jeffrey
8007aa8ee7 automatically find screen if we are using multiple. 2015-08-05 05:00:14 -07:00
Christopher Jeffrey
a9fb228f23 add program.index. 2015-08-05 04:39:48 -07:00
Christopher Jeffrey
7351c8a716 set screen.index. 2015-08-05 04:34:18 -07:00
Christopher Jeffrey
86fb0582cc do not default to program.global. 2015-08-05 03:49:41 -07:00
Christopher Jeffrey
ee31799e7f use _owrite instead of output.write. 2015-08-05 03:27:24 -07:00
Christopher Jeffrey
2b26fe9952 minor: readme. 2015-08-02 01:57:00 -07:00
Christopher Jeffrey
aa23f346d9 readme. package. 2015-08-02 01:56:26 -07:00
Christopher Jeffrey
89afe613ad readme: remove blessed changes finally. 2015-07-31 20:49:41 -07:00
Christopher Jeffrey
5cb517e3f8 readme 2015-07-31 20:48:56 -07:00
Christopher Jeffrey
17f7d7bf31 readme: minor. 2015-07-31 02:17:34 -07:00
Christopher Jeffrey
fb2cc6a205 readme: screen options. 2015-07-31 02:14:38 -07:00
Christopher Jeffrey
8b81eb7299 v0.1.20 2015-07-31 00:15:24 -07:00
Christopher Jeffrey
af2a42423b remove backward compat tty helpers. 2015-07-31 00:09:46 -07:00
Christopher Jeffrey
b4fb673943 Revert "support node v0.6.x."
This reverts commit ce59050ded.
2015-07-31 00:09:01 -07:00
Christopher Jeffrey
ce59050ded support node v0.6.x. 2015-07-30 23:54:24 -07:00
Christopher Jeffrey
53f3d002b0 require node >=v0.8.0. 2015-07-30 23:53:37 -07:00
Christopher Jeffrey
be8ad38e6c check for setRawMode on spawn(). 2015-07-30 23:43:47 -07:00
Christopher Jeffrey
bdb3f098ca improve backward compat with node <=0.6.0. 2015-07-30 23:41:20 -07:00
Christopher Jeffrey
29f70f11f9 v0.1.19 2015-07-30 23:08:47 -07:00
Christopher Jeffrey
103ce24787 helpers to potentially support node <=0.6.0. 2015-07-30 23:07:23 -07:00
Christopher Jeffrey
b0d0063b1c support node <=0.8.0. 2015-07-30 22:55:05 -07:00
Christopher Jeffrey
33db6f4a31 v0.1.18 2015-07-30 20:38:00 -07:00
Christopher Jeffrey
3ff6c4e5fb fix property name collision if input/output is a socket. 2015-07-30 18:17:58 -07:00
Christopher Jeffrey
fe1f470995 allow focusing of detached children still. 2015-07-30 17:58:30 -07:00
Christopher Jeffrey
22469380e2 fix focus error. fix table setData error. fixes #160. 2015-07-30 17:55:40 -07:00
Christopher Jeffrey
ad3a5ae7f9 v0.1.17 2015-07-30 05:08:26 -07:00
Christopher Jeffrey
dc95fc6e3c fix terminal element clearing. 2015-07-30 05:08:04 -07:00
Christopher Jeffrey
eeb9038d1e v0.1.16 2015-07-30 03:49:28 -07:00
Christopher Jeffrey
f8fd4253f2 remove listeners property on screen.destroy and program.destroy. fix ignoreLocked. 2015-07-29 21:28:36 -07:00
Christopher Jeffrey
debbc864e4 handle destroy methods better: stop all polling on the event loop. 2015-07-29 19:20:53 -07:00
Christopher Jeffrey
1628e7d629 force unicode when browserified for now. see #158. 2015-07-28 03:55:30 -07:00
Christopher Jeffrey
6e409f2789 add forceUnicode option. see #158. 2015-07-28 03:53:13 -07:00
Christopher Jeffrey
0f655de980 terminal: minor fix for clear screen. 2015-07-28 03:05:14 -07:00
Christopher Jeffrey
852d780990 fix: set table cell border lines to dirty before rendering. 2015-07-28 02:43:29 -07:00
Christopher Jeffrey
141c5a6eab minor fix for bin/tput.js. 2015-07-27 21:46:54 -07:00
Christopher Jeffrey
78b858742b fix tput.js for browserifying. fixes #158 again. 2015-07-27 21:42:33 -07:00
Christopher Jeffrey
18f3dfcc99 more browserify refactoring. #158. 2015-07-26 17:48:22 -07:00
Christopher Jeffrey
956836a9ed refactor browserify fix. see #158. 2015-07-26 17:46:18 -07:00
Christopher Jeffrey
a42f512c44 refactor browserify fix. see #158. 2015-07-26 16:29:34 -07:00
Christopher Jeffrey
901595077f cleanup browserify transform. fixes #158. 2015-07-26 13:52:46 -07:00
Christopher Jeffrey
b46003799d less insane browserify workaround. see #158. 2015-07-26 13:50:40 -07:00
Christopher Jeffrey
fa080e6546 browserify workaround to avoid changing code. see #158. 2015-07-26 13:35:39 -07:00
Christopher Jeffrey
58a6b6c242 v0.1.15 2015-07-23 02:00:38 -07:00
Christopher Jeffrey
ffb611e383 minor fix for dockable borders. 2015-07-23 02:00:17 -07:00
Christopher Jeffrey
82d4355517 reduce color in program._attr. 2015-07-22 08:32:22 -07:00
Christopher Jeffrey
e506412f93 rename program.list. 2015-07-22 08:07:52 -07:00
Christopher Jeffrey
797dcc2369 do not use nextTick to wait for flush. 2015-07-22 06:03:40 -07:00
Christopher Jeffrey
da59a32ac5 fix iteration through programs on events. see #157. 2015-07-22 05:52:32 -07:00
Christopher Jeffrey
e35811ae97 allow multiple programs to use the same streams correctly. see #157. 2015-07-22 05:45:26 -07:00
Christopher Jeffrey
5e31eb1370 add padding to warning window. 2015-07-22 05:35:17 -07:00
Christopher Jeffrey
989157dcce fix alignment when width is shrunken. 2015-07-22 05:08:05 -07:00
Christopher Jeffrey
f026de2e52 make _twrite() wait for the first bytes to be output. 2015-07-22 05:04:24 -07:00
Christopher Jeffrey
bb83be4b47 fix padding for labels. 2015-07-22 04:38:27 -07:00
Christopher Jeffrey
600cb85909 fix regression from fix for #152. 2015-07-22 02:46:30 -07:00
Christopher Jeffrey
672efc5a3f Revert "fix: ListTable without borders. fixes #152."
This reverts commit 89f54e3be4.
2015-07-22 02:31:45 -07:00
Christopher Jeffrey
d64e5f04ff improve window title grabbing. 2015-07-21 21:27:16 -07:00
Christopher Jeffrey
797feb6ab1 refactor listen. 2015-07-21 20:11:20 -07:00
Christopher Jeffrey
2072968e03 refactor title reset. 2015-07-21 20:06:50 -07:00
Christopher Jeffrey
0cf4934ac1 refactor listen input and listen output into separate methods. 2015-07-21 20:03:26 -07:00
Christopher Jeffrey
ef0a6af11a more readme additions. 2015-07-21 19:57:11 -07:00
Christopher Jeffrey
5c51bfe412 update and fix readme. 2015-07-21 19:35:19 -07:00
Christopher Jeffrey
96b917efe1 enable warnings for all tests. 2015-07-21 19:23:57 -07:00
Christopher Jeffrey
f0556b500b fix transparency when used with valign. 2015-07-21 19:12:54 -07:00
Christopher Jeffrey
1e57352eee add warnings for no isatty(), and bad terminfo. 2015-07-21 19:10:46 -07:00
Christopher Jeffrey
c488c08501 prevent memory leaks when using multiple screens. see #157. 2015-07-21 19:02:08 -07:00
Christopher Jeffrey
44017d988b more tmux 2.0 workarounds. 2015-07-20 04:02:43 -07:00
Christopher Jeffrey
a04c944069 v0.1.14 2015-07-19 05:26:37 -07:00
Christopher Jeffrey
f7c1ba52a3 fix implicit global. 2015-07-19 05:26:25 -07:00
Christopher Jeffrey
881fb50681 v0.1.13 2015-07-19 05:24:10 -07:00
Christopher Jeffrey
6d163377ff improve version check. 2015-07-19 05:20:11 -07:00
Christopher Jeffrey
211fcd3b4c revert readme. 2015-07-19 05:15:04 -07:00
Christopher Jeffrey
415b35e7ee fix tmux passthrough. 2015-07-19 05:02:26 -07:00
Christopher Jeffrey
940bf564a4 refactor: rename "isTMUX". 2015-07-19 03:59:40 -07:00
Christopher Jeffrey
9cdba8979a no tmux checking code seems necessary. see #145. 2015-07-19 03:41:22 -07:00
Christopher Jeffrey
c766a2dc5c panes do not seem to matter. tmux still handles this. see #145. 2015-07-19 03:23:35 -07:00
Christopher Jeffrey
abf7ab2409 tmux "all motion" workaround. see #145. 2015-07-19 03:20:38 -07:00
Christopher Jeffrey
be6d556e94 update faq: mention tmux all-motion removal. 2015-07-18 17:58:06 -07:00
Christopher Jeffrey
fcafb31a83 v0.1.12 2015-07-18 15:21:42 -07:00
Christopher Jeffrey
1d05e3d265 optimize tng for disposeOp=2. 2015-07-18 15:18:57 -07:00
Christopher Jeffrey
d2a2847506 update tng. 2015-07-18 15:10:25 -07:00
Christopher Jeffrey
cd1599e833 update readme. 2015-07-18 14:55:33 -07:00
Christopher Jeffrey
2b21fcd164 rename itype to type. 2015-07-18 14:40:51 -07:00
Christopher Jeffrey
72ddc05fd1 allow appending of listbar items while detached. fixes #148. 2015-07-17 18:52:07 -07:00
Christopher Jeffrey
67b6674558 v0.1.11 2015-07-17 03:18:22 -07:00
Christopher Jeffrey
b9005e6bfe minor fixes for ANSIImage. 2015-07-17 03:17:59 -07:00
Christopher Jeffrey
97d72926a5 minor: whitespace. 2015-07-17 03:14:45 -07:00
Christopher Jeffrey
6f2c2105a2 v0.1.10-1 2015-07-17 03:12:03 -07:00
Christopher Jeffrey
4fa34aa538 add widget name aliases. 2015-07-17 03:11:21 -07:00
Christopher Jeffrey
89debe2577 add more ansii image methods for animation. fix test. 2015-07-17 03:06:33 -07:00
Christopher Jeffrey
2a8f232d18 fix readme faq. 2015-07-17 02:57:38 -07:00
Christopher Jeffrey
281a8a2e8b v0.1.10 2015-07-16 20:13:06 -07:00
Christopher Jeffrey
ea8c671251 update tng. 2015-07-16 20:09:02 -07:00
Christopher Jeffrey
78fad856b6 fix w3m image test. 2015-07-16 20:04:03 -07:00
Christopher Jeffrey
81082488f9 add ansiimage and overlay image. fixes #153. 2015-07-16 03:19:45 -07:00
Christopher Jeffrey
b53835c147 allow additions to ListBar while it is detached. see #148. 2015-07-16 01:03:11 -07:00
Christopher Jeffrey
89f54e3be4 fix: ListTable without borders. fixes #152. 2015-07-16 00:50:05 -07:00
Christopher Jeffrey
ffb657ba1b minor fix. refactor. 2015-07-14 16:24:06 -07:00
Christopher Jeffrey
abdd0a8c89 rename - work. 2015-07-13 12:56:42 -07:00
Christopher Jeffrey
aa9a85be9d whitespace 2015-07-12 03:15:13 -07:00
Christopher Jeffrey
2b1203bb3a add BigText element. fix video args. 2015-07-12 03:12:40 -07:00
Christopher Jeffrey
de02802bf0 refactor/rename w3mimage.js 2015-07-11 15:19:15 -07:00
Christopher Jeffrey
ff39185773 reorganize readme. 2015-07-11 15:08:01 -07:00
Christopher Jeffrey
e638d21dc3 separating image into w3mimage and png elements. 2015-07-11 15:01:46 -07:00
Christopher Jeffrey
baf6d2858a add experimental video widget. fix 16 colors in _attr. 2015-07-11 14:28:04 -07:00
Christopher Jeffrey
cc7c9cbe03 v0.1.7 2015-07-06 18:35:14 -07:00
Christopher Jeffrey
3f7d24ebba readme 2015-07-06 18:35:02 -07:00
Christopher Jeffrey
f8ac8a540c term name 2015-07-06 04:10:56 -07:00
Christopher Jeffrey
1aebe9e395 minor tng update 2015-07-06 02:31:24 -07:00
Christopher Jeffrey
7197a4e16d update tng. 2015-07-06 02:26:26 -07:00
Christopher Jeffrey
ab8e309268 fix listtable resize clearing. fixes #150. 2015-07-04 03:33:42 -07:00
Christopher Jeffrey
77bd73b4c8 add sendFocus option. see #149. 2015-07-04 03:30:49 -07:00
Christopher Jeffrey
90367cd891 readme 2015-07-01 01:18:43 -07:00
Christopher Jeffrey
2f3f10d3b1 readme 2015-07-01 01:15:52 -07:00
Christopher Jeffrey
9a249914dd readme: use capital letters for once. 2015-07-01 01:09:47 -07:00
Christopher Jeffrey
0966af8b35 fix readme 2015-07-01 00:51:28 -07:00
Christopher Jeffrey
f4a2c53bb5 readme. tng. 2015-06-30 23:50:57 -07:00
Christopher Jeffrey
de213ceec0 minor 2015-06-30 00:23:15 -07:00
Christopher Jeffrey
c473cc527f update tng 2015-06-29 22:17:43 -07:00
Christopher Jeffrey
dfedd81d46 minor tng update 2015-06-29 03:46:52 -07:00
Christopher Jeffrey
60c54590a1 update tng 2015-06-29 02:58:06 -07:00
Christopher Jeffrey
64e1a730dc update tng. 2015-06-29 02:16:02 -07:00
Christopher Jeffrey
9b613d58f7 remove old tng. 2015-06-29 02:15:47 -07:00
Christopher Jeffrey
b61cda656f do not disable disposeOps for pngs. 2015-06-28 23:07:25 -07:00
Christopher Jeffrey
2842f3f6ce add PNG/ANSIImage element. 2015-06-28 22:55:42 -07:00
Christopher Jeffrey
305aa063d4 move blending to colors.js. 2015-06-27 17:39:04 -07:00
Christopher Jeffrey
9f1552c687 fix {|} separator in the presence of alignments. fixes #146. 2015-06-27 03:06:08 -07:00
Christopher Jeffrey
36d94d41a6 fix cellMotion for tmux. fix mousemove check for VTE. fixes #125. 2015-06-23 18:02:05 -07:00
Christopher Jeffrey
3dd3f22820 new readme. see #143. 2015-06-23 18:00:32 -07:00
Christopher Jeffrey
ebdd1940fe v0.1.61 2015-06-19 18:16:28 -07:00
Christopher Jeffrey
4759fcfa31 readme. 2015-06-19 18:14:43 -07:00
Christopher Jeffrey
f3f4233a7a fix unnecessary onScreenEvent change. fixes #142. 2015-06-19 17:59:06 -07:00
Christopher Jeffrey
8228142060 allow any kind of stream as input and output. fixes #138. 2015-06-09 05:13:11 -07:00
Christopher Jeffrey
983b5a745a fix some helper functions. 2015-06-03 01:08:49 -07:00
Christopher Jeffrey
b962994201 v0.1.60 2015-05-21 19:20:36 -07:00
Christopher Jeffrey
c7252ea86f account for ena_acs. fix for tmux 2.0. see #137. 2015-05-21 15:58:00 -07:00
Christopher Jeffrey
f0b7204af0 fix for tmux 2.0. closes #137. 2015-05-20 18:59:39 -07:00
Christopher Jeffrey
3690aae695 test playing and recording. 2015-05-13 21:02:37 -07:00
Christopher Jeffrey
9e0df1a6ae layout test. 2015-05-07 22:18:05 -07:00
Christopher Jeffrey
d36b90ce40 removeLabel: remove listeners before detaching. 2015-05-07 18:54:07 -07:00
Christopher Jeffrey
da1ff18493 fix label reposition. fixes #134. 2015-05-07 18:53:06 -07:00
Christopher Jeffrey
173f62c519 test. 2015-05-07 17:41:59 -07:00
Christopher Jeffrey
e214141ccb add a distinct grid and inline layout. see #23. 2015-05-07 17:25:23 -07:00
Christopher Jeffrey
f89e6661f3 fix list.removeItem. add list.insertItem, list.setItem. fixes #18. 2015-05-06 17:39:49 -07:00
Christopher Jeffrey
b21e535391 add a customizable Layout element. see #23. 2015-05-06 13:00:57 -07:00
Christopher Jeffrey
583fa4f6f7 more refactoring of lib/blessed. 2015-05-05 23:59:50 -07:00
Christopher Jeffrey
8d11075b89 improve lib/blessed.js 2015-05-05 23:22:40 -07:00
Christopher Jeffrey
5eddd2aed2 whitespace. comments. 2015-05-05 23:10:18 -07:00
Christopher Jeffrey
a4d56fb819 refactor: split widgets up. fixes #133. 2015-05-05 21:44:38 -07:00
Christopher Jeffrey
99f9d622e6 minor fix for sync image rendering. 2015-05-05 19:17:16 -07:00
Christopher Jeffrey
ce7cab13ba v0.1.56 2015-05-02 03:09:23 -07:00
Christopher Jeffrey
a7d6f6e591 multiplexer. 2015-05-02 03:08:28 -07:00
Christopher Jeffrey
9260848868 add synchronous setImage for Image elements. 2015-05-02 03:01:42 -07:00
Christopher Jeffrey
e6c763a73c use onScreenEvent for element keys to prevent memory leaks. 2015-05-01 22:43:31 -07:00
Christopher Jeffrey
d68aa5cf41 v0.1.55 2015-05-01 22:26:24 -07:00
Christopher Jeffrey
1044a88e58 allow custom draggable checks. 2015-05-01 22:14:49 -07:00
Christopher Jeffrey
3205dd289d fix onScreenEvent listeners. 2015-05-01 22:04:26 -07:00
Christopher Jeffrey
245b3f44b1 experimental angle improvement. 2015-05-01 21:59:09 -07:00
Christopher Jeffrey
c435b03bdc use onScreenEvent to prevent memory leaks. 2015-05-01 21:58:26 -07:00
Christopher Jeffrey
de4aa27d70 make terminals focusable. set elements being dragged to front of z-index. terminal multiplexer. 2015-05-01 21:24:45 -07:00
Christopher Jeffrey
b5341b8b81 add ignoreDockContrast option. 2015-05-01 21:09:40 -07:00
Christopher Jeffrey
0ea19cacad fix off-screen coords. fix draggable. 2015-05-01 20:55:13 -07:00
Christopher Jeffrey
f26ae44d84 fix fillRegion/clearRegion. 2015-05-01 18:20:16 -07:00
Christopher Jeffrey
69b3d144c4 widget-unicode test. 2015-05-01 18:07:15 -07:00
Christopher Jeffrey
b8a170592f rename widget-eaw->widget-unicode. 2015-05-01 17:46:21 -07:00
Christopher Jeffrey
ba4108445a avoid wrapping shortfall due to surrogate pairs. 2015-05-01 17:44:49 -07:00
Christopher Jeffrey
092b240ef6 surrogate pair emoticons for widget-eaw. 2015-05-01 16:47:05 -07:00
Christopher Jeffrey
b6c512925f fix shift+G. potentially use getScrollHeight for more things. 2015-05-01 16:44:10 -07:00
Christopher Jeffrey
0b5b04c739 bright grey == regular white. 2015-05-01 01:29:37 -07:00
Christopher Jeffrey
0506f5fea2 bright and grey color names. 2015-05-01 01:27:11 -07:00
Christopher Jeffrey
e2faf2300e windows commands. 2015-05-01 01:02:26 -07:00
Christopher Jeffrey
b0daa72a72 comment. 2015-05-01 00:57:40 -07:00
Christopher Jeffrey
d2586089c8 reorganize more code. 2015-05-01 00:47:39 -07:00
Christopher Jeffrey
0b6fceec23 refactor blend. 2015-05-01 00:40:12 -07:00
Christopher Jeffrey
f5f2b71562 refactor helpers. 2015-05-01 00:33:34 -07:00
Christopher Jeffrey
3e8083d5a1 more refactoring of helpers. 2015-05-01 00:32:44 -07:00
Christopher Jeffrey
8eb57e919e refactor: move helpers around. 2015-05-01 00:27:33 -07:00
Christopher Jeffrey
797d8de45f handle unicode and tags better in tables and textareas. 2015-04-30 23:51:45 -07:00
Christopher Jeffrey
23567a75ab improve charWidth and strWidth. 2015-04-30 23:09:09 -07:00
Christopher Jeffrey
4ce0df57da v0.1.54 2015-04-30 09:49:01 -07:00
Christopher Jeffrey
4ff2c992d5 fix overlapping draggable elements. 2015-04-30 09:48:50 -07:00
Christopher Jeffrey
d1bfdd5a31 only allow scrollbar usage with mouse if mouse option is set. 2015-04-30 09:41:07 -07:00
Christopher Jeffrey
bcf9b630bb mouse interactive scrollbar. 2015-04-29 12:43:58 -07:00
Christopher Jeffrey
b7cf7d08f6 ansi-viewer: hover text. 2015-04-29 12:11:11 -07:00
Christopher Jeffrey
023e6be4e5 another hover fix. 2015-04-27 23:57:08 -07:00
Christopher Jeffrey
a5bfa4397a clean and fix hover code. 2015-04-27 23:55:49 -07:00
Christopher Jeffrey
5468509778 optimize hover text. 2015-04-27 21:24:58 -07:00
Christopher Jeffrey
36c726006f add more events to lists. 2015-04-27 16:59:45 -07:00
Christopher Jeffrey
b05f3cc185 readme 2015-04-27 15:27:51 -07:00
Christopher Jeffrey
b241e1a4df do not render combining chars on iTerm2.
see: 2eb57cc725
2015-04-27 15:07:23 -07:00
Christopher Jeffrey
46e9c52030 cursor position in textarea. 2015-04-27 15:04:33 -07:00
Christopher Jeffrey
09fe097d3f clean up unicode code and comments some more. 2015-04-27 14:53:34 -07:00
Christopher Jeffrey
f8946a22f3 fix combining check during unicode wrap. 2015-04-27 14:08:18 -07:00
Christopher Jeffrey
53066c8f4c minor: comment. 2015-04-27 14:04:17 -07:00
Christopher Jeffrey
cb9ffee1e3 fix surrogate singles. stop using bad surrogate double for testing.
see 2eb57cc725
2015-04-27 12:51:11 -07:00
Christopher Jeffrey
582831e5bc clear screen on windows during Screen.enter. 2015-04-27 01:23:30 -07:00
Christopher Jeffrey
a42631cbc7 fix unicode on windows. see #130. 2015-04-27 00:19:55 -07:00
Christopher Jeffrey
f37a619cc6 allow 0-width 0-height elements. see slap-editor/slap#153. 2015-04-27 00:14:02 -07:00
Christopher Jeffrey
3f8ed04898 allow unicode on all windows consoles for now. see #130. 2015-04-26 19:22:23 -07:00
Christopher Jeffrey
56aae2e861 cjk ambiguous with if statement. 2015-04-26 07:56:51 -07:00
Christopher Jeffrey
33d2f52dcf amiguous CJK character check. 2015-04-26 07:53:39 -07:00
Christopher Jeffrey
56421ccc7b fix VTE again - two chars for surrogate wide replacement. 2015-04-26 07:17:39 -07:00
Christopher Jeffrey
0ea8c77dd8 fix VTE. only remove surrogate double chars. 2015-04-26 07:16:50 -07:00
Christopher Jeffrey
051e90070c workaround VTEs wide surrogate pair display bug. 2015-04-26 07:03:52 -07:00
Christopher Jeffrey
b753a8c492 cleanup eaw test. 2015-04-26 06:56:56 -07:00
Christopher Jeffrey
da368f58d9 v0.1.53 2015-04-26 06:54:57 -07:00
Christopher Jeffrey
86dd7e169a eaw test. attempt to use harmony unicode features. 2015-04-26 06:54:07 -07:00
Christopher Jeffrey
34fd68b620 Revert "isSurrogateLast"
This reverts commit e19730578c.
2015-04-26 06:38:06 -07:00
Christopher Jeffrey
e19730578c isSurrogateLast 2015-04-26 06:37:45 -07:00
Christopher Jeffrey
2eb57cc725 do not break on spaces, double-widths, surrogates, or combinings for text wrapping. 2015-04-26 06:32:41 -07:00
Christopher Jeffrey
9a2b6dfd81 v0.1.52 2015-04-26 06:09:17 -07:00
Christopher Jeffrey
94ba30cbfd fix: break on extra space for double-width again. 2015-04-26 05:55:20 -07:00
Christopher Jeffrey
fe4a807042 fix 鹃 when bold in eaw test. 2015-04-26 05:54:39 -07:00
Christopher Jeffrey
e21a470853 eaw test. 2015-04-26 05:36:30 -07:00
Christopher Jeffrey
c5257275ea v0.1.51 2015-04-26 05:10:12 -07:00
Christopher Jeffrey
620c17c7dc fix eaw test. comment. 2015-04-26 04:41:31 -07:00
Christopher Jeffrey
c73fee2f7d rename unicode regexes again. 2015-04-26 04:34:32 -07:00
Christopher Jeffrey
dafe95d900 rename unicode regexes. 2015-04-26 04:29:52 -07:00
Christopher Jeffrey
ccca1092e7 add regex for all wide chars. 2015-04-26 04:23:32 -07:00
Christopher Jeffrey
758eef133c stop double-width chars from breaking words when wrapped. 2015-04-26 04:16:47 -07:00
Christopher Jeffrey
edf22cd6cd screenshot. 2015-04-26 02:40:39 -07:00
Christopher Jeffrey
3d8dfd0db4 screen.screenshot 2015-04-26 02:34:17 -07:00
Christopher Jeffrey
963cfbb9f8 fix labels for non-scrollable elements. 2015-04-25 19:12:47 -07:00
Christopher Jeffrey
945e2a57fb time.js again. 2015-04-25 19:08:58 -07:00
Christopher Jeffrey
ab4ce7ee30 minor. time.js. 2015-04-25 19:06:39 -07:00
Christopher Jeffrey
cbed0b449a GetConsoleCP fixes. see #130. 2015-04-25 16:59:31 -07:00
Christopher Jeffrey
f2d809d57b fix chcp usage: exe->com. fix output parsing. see #130. 2015-04-25 15:19:29 -07:00
Christopher Jeffrey
0461a35219 fix error in tput.js. 2015-04-25 12:39:44 -07:00
Christopher Jeffrey
5f993a19d9 check for unicode on windows using GetConsoleCP. see #130. 2015-04-25 12:32:32 -07:00
Christopher Jeffrey
38cc1a3ea3 more ritems fixes. 2015-04-24 11:39:40 -07:00
Christopher Jeffrey
096869d82e fix ritems handling. debug. 2015-04-24 01:40:18 -07:00
Christopher Jeffrey
bcb248b768 minor. 2015-04-23 22:25:09 -07:00
Christopher Jeffrey
fdf181b8e0 return tagless values for list items. 2015-04-22 16:58:33 -07:00
Christopher Jeffrey
2e5da439b0 Revert "ritems with no tags."
This reverts commit 3ba251cc2f.
2015-04-22 16:54:15 -07:00
Christopher Jeffrey
3ba251cc2f ritems with no tags. 2015-04-22 16:53:46 -07:00
Christopher Jeffrey
01b2d0b265 fuzzyFind. 2015-04-22 13:32:23 -07:00
Christopher Jeffrey
861b5ef431 screenshot method cleanup. 2015-04-21 13:29:02 -07:00
Christopher Jeffrey
0847faa7e8 screenshot, shuffle, slideshow for ansi-viewer. 2015-04-21 07:13:22 -07:00
Christopher Jeffrey
43c39b525f handle animating screenshots. ansi-viewer. 2015-04-21 06:56:40 -07:00
Christopher Jeffrey
5f1d320112 add screenshot method to widget.js. 2015-04-21 05:46:21 -07:00
Christopher Jeffrey
429afdc541 comment. 2015-04-21 05:10:02 -07:00
Christopher Jeffrey
9a75c29281 screenshot coords. 2015-04-21 05:03:46 -07:00
Christopher Jeffrey
7c49f67247 screenshot. 2015-04-21 04:58:41 -07:00
Christopher Jeffrey
e70edff5ce better screenshot method. 2015-04-21 04:56:07 -07:00
Christopher Jeffrey
009b4bbee9 minor. 2015-04-21 04:46:44 -07:00
Christopher Jeffrey
e11e0044ef rename sgrRegion. 2015-04-21 04:45:33 -07:00
Christopher Jeffrey
cb977ca08f sgrRegion for ansi-viewer. 2015-04-21 04:43:02 -07:00
Christopher Jeffrey
c8bc743202 save art to regular utf8 sgr-only file. 2015-04-21 04:24:34 -07:00
Christopher Jeffrey
25a10675e9 ansi-viewer sizing. 2015-04-20 17:40:17 -07:00
Christopher Jeffrey
8194294ac7 ansi-viewer fixes. 2015-04-20 15:04:39 -07:00
Christopher Jeffrey
8b886e7539 convert ibm to utf8. see #127. 2015-04-20 14:09:16 -07:00
Christopher Jeffrey
e9be309ce4 make .gitignore more unixy. see #128. 2015-04-20 04:19:17 -07:00
Christopher Jeffrey (JJ)
057dd91085 Merge pull request #128 from yaronn/master
add .gitignore
2015-04-20 04:19:29 -07:00
Yaron Naveh
44a9c4f7ec add .gitignore 2015-04-20 14:13:18 +03:00
Christopher Jeffrey
a0daecc8bb fuzzyFind improvement. 2015-04-19 19:50:53 -07:00
Christopher Jeffrey
884b9bcb33 fix ansi-viewer require. see #127. 2015-04-19 12:09:05 -07:00
Christopher Jeffrey
1810f2f914 drop tty check for now. see yaronn/blessed-contrib#45. 2015-04-19 06:01:09 -07:00
Christopher Jeffrey
acd33d7bbe ansi-viewer minor. 2015-04-19 06:00:31 -07:00
Christopher Jeffrey
034728e900 narrow ansi-viewer list. 2015-04-18 23:58:41 -07:00
Christopher Jeffrey
a55e7620a0 v0.1.5 2015-04-18 22:29:33 -07:00
Christopher Jeffrey
868bcbff76 npmignore. 2015-04-18 22:28:19 -07:00
Christopher Jeffrey
564592891c fuzzyFind callback convention. 2015-04-18 22:25:13 -07:00
Christopher Jeffrey
2c00450029 allow regexes for fuzzyfind. 2015-04-18 22:22:32 -07:00
Christopher Jeffrey
2666a008bf fix fuzzyFind. 2015-04-18 22:18:42 -07:00
Christopher Jeffrey
6c195dd8a0 fix label scroll. improve search. add features to ansi-viewer. 2015-04-18 22:15:11 -07:00
Christopher Jeffrey
e3359a6877 update ansi-viewer deps. 2015-04-18 20:42:17 -07:00
Christopher Jeffrey
d479bc6153 v0.1.4 2015-04-18 20:37:08 -07:00
Christopher Jeffrey
72dcf7b18f ansi art viewer. 2015-04-18 20:36:46 -07:00
Christopher Jeffrey
02f5287b56 v0.1.3 2015-04-18 20:20:34 -07:00
Christopher Jeffrey
3ff31cf0c1 minor fixes. 2015-04-18 20:20:25 -07:00
Christopher Jeffrey
1ad3c0dcb2 v0.1.2 2015-04-17 21:20:47 -07:00
Christopher Jeffrey
82928702d3 surrogate. one flew over the 杜鹃's nest. 2015-04-17 21:17:11 -07:00
Christopher Jeffrey
d49881f96b readme again. 2015-04-16 23:21:45 -07:00
Christopher Jeffrey
72530932e3 Revert "readme"
This reverts commit cd81e96db6.
2015-04-16 23:21:02 -07:00
Christopher Jeffrey
cd81e96db6 readme 2015-04-16 23:18:49 -07:00
Christopher Jeffrey
32d734d568 v0.1.1 2015-04-16 17:58:50 -07:00
Christopher Jeffrey
347ef0c010 minor. 2015-04-16 17:45:46 -07:00
Christopher Jeffrey
7b31f45468 fix textarea for full unicode. 2015-04-16 16:16:55 -07:00
Christopher Jeffrey
5dacfbad97 stop using screen.cols. 2015-04-16 14:38:36 -07:00
Christopher Jeffrey
46a76abbdd add invertSelected option to List. fixes #124. 2015-04-16 13:20:49 -07:00
Christopher Jeffrey
489aa2dbe3 clean up Element.render surrogate handling. 2015-04-16 13:11:56 -07:00
Christopher Jeffrey
0acae98979 fix disappearing double-width chars on scroll up. 2015-04-16 12:31:07 -07:00
Christopher Jeffrey
d520c94c3b handle unicode combining characters properly. 2015-04-16 11:33:08 -07:00
Christopher Jeffrey
dfb87e2037 unicode. 2015-04-15 23:09:33 -07:00
Christopher Jeffrey
62cec50eb0 remove unicode-old. 2015-04-15 22:56:25 -07:00
Christopher Jeffrey
d12c51fc7b even more unicode. 2015-04-15 22:55:42 -07:00
Christopher Jeffrey
b043571fbe more unicode. 2015-04-15 22:51:47 -07:00
Christopher Jeffrey
1c76d4fb55 add back unicode-3/unicode-old for now. 2015-04-15 22:49:12 -07:00
Christopher Jeffrey
e714c4f930 cleanup unicode. 2015-04-15 22:44:47 -07:00
Christopher Jeffrey
73d158cf02 refactoring unicode. 2015-04-15 22:36:48 -07:00
Christopher Jeffrey
70c03a7f0b minor. 2015-04-15 21:49:28 -07:00
Christopher Jeffrey
5216720f26 readme code again. 2015-04-15 11:11:11 -07:00
Christopher Jeffrey
d42ce98154 readme. 2015-04-15 11:10:24 -07:00
Christopher Jeffrey
62b1003a05 handle 0-width surrogates. 2015-04-15 10:49:43 -07:00
Christopher Jeffrey
cb363c575b libvte cannot display surrogate pair double width characters properly. 2015-04-15 10:46:25 -07:00
Christopher Jeffrey
c5e5ed86f6 fix surrogate crash. 2015-04-15 10:38:26 -07:00
Christopher Jeffrey
29ca94e719 widget-shadow.js. 2015-04-15 10:35:47 -07:00
Christopher Jeffrey
4ca28d0860 use emitKeys() from node v0.12.2. see #91 #92 slap-editor/slap#74 slap-editor/slap#96. 2015-04-15 10:30:09 -07:00
Christopher Jeffrey
85be64273f clean up old surrogates code. 2015-04-15 10:10:19 -07:00
Christopher Jeffrey
ea4e142757 add support for surrogate pairs. fixes #123. see #4 and slap-editor/slap#107. 2015-04-15 10:05:34 -07:00
Christopher Jeffrey
1b1775a4c2 add doubleWidthPerfect option. 2015-04-15 00:38:18 -07:00
Christopher Jeffrey
3f73e08dd7 Revert "move wideChar handling to _wrapContent."
This reverts commit 307b757e1f.
2015-04-14 15:44:26 -07:00
Christopher Jeffrey
307b757e1f move wideChar handling to _wrapContent. 2015-04-14 15:43:37 -07:00
Christopher Jeffrey
ecf9e38f55 double width character handling. see slap-editor/slap#107. 2015-04-14 15:35:16 -07:00
Christopher Jeffrey
3d424076bd readme. 2015-04-11 04:09:13 -07:00
Christopher Jeffrey
e6e080f84c gif 2015-04-10 14:29:44 -07:00
Christopher Jeffrey
c8d3454fe0 changelog refactor. 2015-04-10 14:27:09 -07:00
Christopher Jeffrey
0704214dea changelog. 2015-04-10 14:21:10 -07:00
Christopher Jeffrey
530e9d77b1 v0.1.0 2015-04-10 14:07:21 -07:00
Christopher Jeffrey
01601036c3 gifs. 2015-04-10 14:06:27 -07:00
Christopher Jeffrey
d7982dcd47 changes. 2015-04-10 13:04:07 -07:00
Christopher Jeffrey
46b493d02e minor blend changes. 2015-04-10 13:01:00 -07:00
Christopher Jeffrey
eebbcdd702 dock test. 2015-04-08 01:38:56 -07:00
Christopher Jeffrey
95364dd229 better dragging. 2015-04-08 01:24:45 -07:00
Christopher Jeffrey
78e663a734 transparency again. 2015-04-07 23:19:01 -07:00
Christopher Jeffrey
6d487b3873 minor. test. 2015-04-06 21:13:43 -07:00
Christopher Jeffrey
b950e34459 Revert "add style.transparent option."
This reverts commit 8eaf7bab37.
2015-04-06 21:12:17 -07:00
Christopher Jeffrey
8eaf7bab37 add style.transparent option. 2015-04-06 21:05:15 -07:00
Christopher Jeffrey
49e4ec976b fix darken. 2015-04-06 20:49:07 -07:00
Christopher Jeffrey
5958b55bd0 remove unnecessary angles. 2015-04-06 19:40:16 -07:00
Christopher Jeffrey
a0d610e174 use unicode escapes for ACS. 2015-04-06 19:39:05 -07:00
Christopher Jeffrey
5f3d7f10b0 clean up border and table code. 2015-04-06 19:31:04 -07:00
Christopher Jeffrey
8a62f5e633 add "shadow" option to elements. see widget-shadow.js. 2015-04-06 19:26:14 -07:00
Christopher Jeffrey
67bdab7e4f improve border docking. selective border drawing. 2015-04-06 18:40:33 -07:00
Christopher Jeffrey
df21507d50 readme. 2015-04-04 17:36:09 -07:00
Christopher Jeffrey
1c048e6061 break on border loops when possible. 2015-04-04 07:12:01 -07:00
Christopher Jeffrey
9105c80eb7 improve w3m search. do not search for w3mimgdisplay in example. fixes #119. 2015-04-04 06:56:01 -07:00
Christopher Jeffrey
f6b5b8811a allow docking borders to obscured by screen edges. 2015-04-04 06:40:36 -07:00
Christopher Jeffrey
15d09e7ce1 Revert "allow explicit height for Table."
This reverts commit 85f8d4f4b7.
2015-04-04 03:04:11 -07:00
Christopher Jeffrey
85f8d4f4b7 allow explicit height for Table. 2015-04-04 03:03:24 -07:00
Christopher Jeffrey
d13774814d use application keys on init. 2015-04-04 02:24:19 -07:00
Christopher Jeffrey
bb4a8c82aa debug log. 2015-04-04 02:23:43 -07:00
Christopher Jeffrey
7afb791950 minor refactor of el.sattr. 2015-04-04 00:26:10 -07:00
Christopher Jeffrey
861ec57327 fix scroll on focus by taking into account border/itop. 2015-04-04 00:08:10 -07:00
Christopher Jeffrey
08bb19e17f update tests. 2015-04-04 00:07:39 -07:00
Christopher Jeffrey
2a4a38a4f1 represent all ACS characters in unicode escapes. 2015-04-03 23:04:27 -07:00
Christopher Jeffrey
2c6b34a86b add percentage offsets. see #118. 2015-04-03 22:55:56 -07:00
Christopher Jeffrey
5aeeed7683 add dockBorders option. see #118. 2015-04-03 20:50:22 -07:00
Christopher Jeffrey
bcd65ad420 minor table change. 2015-04-03 19:03:58 -07:00
Christopher Jeffrey
f34cf1bdfe table drawing and options. no tags for table style. readme. see #117. 2015-04-02 17:59:04 -07:00
Christopher Jeffrey
c8007331b0 helper. 2015-04-02 07:24:25 -07:00
Christopher Jeffrey
144dcce30a readme. 2015-04-02 07:16:21 -07:00
Christopher Jeffrey
9eb2005e36 expose some more helpers. 2015-04-02 06:40:41 -07:00
Christopher Jeffrey
6b3610450c fix error on table screen overlap. 2015-04-02 06:21:36 -07:00
Christopher Jeffrey
cf3eb09f9f improve table resize event listeners. 2015-04-02 06:12:52 -07:00
Christopher Jeffrey
b9a94f63ce fix valign option. 2015-04-02 05:10:23 -07:00
Christopher Jeffrey
2640838f33 allow custom width for tables. fixes #117. 2015-04-02 05:10:23 -07:00
Brian White
36fed3c12b add /lib/terminfo to terminfo dir list
At least on Ubuntu, `/lib/terminfo` contains a smaller subset of terminfo files and is worth using in case none of the other directories don't exist.
2015-04-01 23:43:43 -04:00
Christopher Jeffrey
897f8a2eca fix linux console clear. better debug window to test/widget.js. complete widget docs. 2015-04-01 19:46:08 -07:00
Christopher Jeffrey
b34c90ee2b minor. 2015-03-31 06:12:14 -07:00
Christopher Jeffrey
8901c29bd5 minor style change. 2015-03-31 05:50:28 -07:00
Christopher Jeffrey
afb5a0c7eb include important changes in readme. 2015-03-31 05:32:05 -07:00
Christopher Jeffrey
903886f083 clean up comments pertaining to position, autoPadding, shrinking. 2015-03-31 05:16:01 -07:00
Christopher Jeffrey
4419794991 enable autoPadding by default. see #114. 2015-03-31 05:11:50 -07:00
Christopher Jeffrey
51c3d88a69 textLength improvement. 2015-03-31 02:55:20 -07:00
Christopher Jeffrey
7a3525be77 remove duplicate functions. 2015-03-31 02:49:29 -07:00
Christopher Jeffrey
064a4e9086 add debug window and draggable option for all elements. 2015-03-31 02:45:01 -07:00
Christopher Jeffrey
a266a869b7 improve Log element. 2015-03-31 01:31:43 -07:00
Christopher Jeffrey
6154859110 cleanup Table code. fixes for Table. 2015-03-31 00:48:17 -07:00
Christopher Jeffrey
b067845242 readme. comments. temporary workaround for non-autoPadding list-table. 2015-03-31 00:37:32 -07:00
Christopher Jeffrey
8793be5562 optimize Table element. first pass at ListTable. 2015-03-31 00:25:38 -07:00
Christopher Jeffrey
cbc94254b4 add table cell text alignment. 2015-03-30 05:16:22 -07:00
Christopher Jeffrey
bc94be742e fixes for Log and Table elements. 2015-03-30 05:05:57 -07:00
Christopher Jeffrey
91bc189ba3 add Log and Table elements. update README. 2015-03-30 04:58:15 -07:00
Christopher Jeffrey
c7a6ce60f8 Revert "try to use getCoords everywhere."
This reverts commit 92f167eee8.
2015-03-29 15:48:07 -07:00
Christopher Jeffrey
92f167eee8 try to use getCoords everywhere. 2015-03-29 15:47:58 -07:00
Christopher Jeffrey
6dc7f688b6 readme markdown - use underscores. 2015-03-29 12:34:15 -07:00
Christopher Jeffrey
5e466c139e rename coord props for consistency. see #113. 2015-03-29 12:29:04 -07:00
Christopher Jeffrey
bed28181f3 use real linux terminfo. 2015-03-28 19:14:35 -07:00
Christopher Jeffrey
236ec0f6b7 minor 2015-03-21 10:30:34 -07:00
Christopher Jeffrey (JJ)
8d9024ca4e Merge pull request #110 from piranna/master
linux terminfo
2015-03-21 10:30:41 -07:00
Christopher Jeffrey
9070e7f78f refactor artificial cursors and other features. 2015-03-19 23:49:26 -07:00
Christopher Jeffrey
c3257e29dc readme 2015-03-19 05:23:56 -07:00
Christopher Jeffrey
2b425eec4f v0.0.51. 2015-03-19 04:46:41 -07:00
Christopher Jeffrey
67a77f4e83 readme. 2015-03-19 04:46:31 -07:00
Christopher Jeffrey
f4cbac1e1f readme. 2015-03-19 04:25:39 -07:00
Christopher Jeffrey
9f6888fc9e readme and package.json. 2015-03-19 04:17:13 -07:00
Christopher Jeffrey
685d7feb09 fix tmux bypassing for cursor status. 2015-03-19 04:16:59 -07:00
Christopher Jeffrey
cbcc7e6124 temporarily remove noAlt. 2015-03-19 04:13:44 -07:00
Christopher Jeffrey
63685f559a typo in readme. 2015-03-17 23:42:21 -07:00
Christopher Jeffrey
18e14e47b1 v0.0.50 2015-03-17 23:26:43 -07:00
Christopher Jeffrey
43903ca8b2 readme. title. 2015-03-17 23:26:27 -07:00
Jesús Leganés Combarro "piranna
d70b3f8dca linux terminfo 2015-03-17 23:10:44 +01:00
Christopher Jeffrey
13890ec409 fix artificial cursor color. 2015-03-16 23:53:31 -07:00
Christopher Jeffrey
5dc3af1937 readme. 2015-03-14 16:47:46 -07:00
Christopher Jeffrey
d3e566b9c1 lots of old code for proprietary codes and "artificial cursors". 2015-03-14 16:35:17 -07:00
Christopher Jeffrey
3dcc0b3d1b minor bug fixes. handle tmux escaping. 2015-03-14 16:14:39 -07:00
Christopher Jeffrey
0e2b626556 progressbar. automatic focus on elements. test/widget.js. reallyScrollable. 2015-02-26 15:37:01 -08:00
Christopher Jeffrey
236f5fba00 v0.0.49 2015-02-24 18:35:47 -08:00
Christopher Jeffrey
3778c37f40 expose enableMouse, enableKeys, and enableInput. 2015-02-24 18:33:00 -08:00
Christopher Jeffrey
02fd115fb0 remember last button for mouseup on x10 and urxvt protocols. 2015-02-24 18:22:04 -08:00
Christopher Jeffrey
ad546d9af9 remove comments. 2015-02-24 18:17:04 -08:00
Christopher Jeffrey
aaa9905fac drop terminfo checks in setMouse. 2015-02-24 18:11:03 -08:00
Christopher Jeffrey
21e5f436fd v0.0.48 2015-02-24 18:05:44 -08:00
Christopher Jeffrey
190e75884d cleanup setMouse. 2015-02-24 18:05:10 -08:00
Christopher Jeffrey
b42308c7cc fix key events for textareas. 2015-02-22 13:37:44 -08:00
Christopher Jeffrey
520dc08100 minor. 2015-02-22 12:59:53 -08:00
Christopher Jeffrey
02ca94a8d9 tput: debug info for {init,reset}_file. fix global var. 2015-02-21 13:52:39 -08:00
Christopher Jeffrey
77695f994a add noAlt option. fix list shrinking. 2015-02-21 13:31:25 -08:00
Christopher Jeffrey
586a586e60 remove mouse comments. fix removeHover. 2015-02-21 02:48:47 -08:00
Christopher Jeffrey
5d72fb1938 fix Terminal element. check for allocated gpmclient. 2015-02-17 22:12:49 -08:00
Christopher Jeffrey
a335257505 filter out all mouse events from keys. see slap-editor/slap-editor#74. 2015-02-13 19:28:18 -08:00
Christopher Jeffrey
03cdfbb39c add mouse protocols. window title restore. fix response. 2015-02-13 19:14:27 -08:00
Christopher Jeffrey
cb00aeb413 v0.0.47 2015-02-13 01:24:32 -08:00
Christopher Jeffrey
a29fdf1c74 fix hover text and demonstrate it better. 2015-02-13 01:18:20 -08:00
Christopher Jeffrey
66f6d958d7 v0.0.46 2015-02-13 01:01:59 -08:00
Christopher Jeffrey
c0e36f137d fix error caused when screen.render() is called during a delayed resize. 2015-02-13 00:59:47 -08:00
Christopher Jeffrey
41cb97d664 fix terminal cursor. 2015-02-12 22:37:53 -08:00
Christopher Jeffrey
33fec26984 v0.0.45 2015-02-11 17:26:23 -08:00
Christopher Jeffrey
29a78697bb fix style.border values. fixes #105. 2015-02-11 17:21:41 -08:00
Christopher Jeffrey
982e075a90 Image and Terminal element. 2015-02-11 17:20:22 -08:00
Christopher Jeffrey
267e77a089 improve Terminal element and terminal multiplexer example. 2015-02-11 02:27:11 -08:00
Christopher Jeffrey
00a0f800f9 add "interactive" option for lists. fixes #103. 2015-02-09 20:14:34 -08:00
Christopher Jeffrey
d69ed5c294 more work on Image element. 2015-02-09 19:49:33 -08:00
Christopher Jeffrey
1729244db3 image element: fix shrink. 2015-02-09 01:43:16 -08:00
Christopher Jeffrey
a4e6856901 fix image element test. 2015-02-09 00:21:58 -08:00
Christopher Jeffrey
9e234c3901 fix image rendering. 2015-02-09 00:19:35 -08:00
Christopher Jeffrey
cce38f9f21 improve w3m checking for Image element and screen.displayImage. 2015-02-09 00:09:30 -08:00
Christopher Jeffrey
4c1e020b42 add title. 2015-02-09 00:03:09 -08:00
Christopher Jeffrey
c8a9222749 image align=center. 2015-02-09 00:02:07 -08:00
Christopher Jeffrey
dd0f1cbb70 fix clearImage. 2015-02-08 23:43:32 -08:00
Christopher Jeffrey
49f1843955 improvements to the Image element. add screen.displayImage(). 2015-02-08 23:42:44 -08:00
Christopher Jeffrey
f88d74997a comment 2015-02-08 22:01:24 -08:00
Christopher Jeffrey
594b0bd340 fix NCURSES_NO_UTF8_ACS handling. 2015-02-08 21:34:46 -08:00
Christopher Jeffrey
c6287668ee comment 2015-02-08 14:35:08 -08:00
Christopher Jeffrey
1f2098707c require both terminfo and LANG to lack utf8 in order for ascii fallback. fixes #98. 2015-02-08 14:29:38 -08:00
Christopher Jeffrey
1cf69f74d9 minor. comment. 2015-02-07 16:04:14 -08:00
Christopher Jeffrey
e8fe076681 refactor mouse events. put buf on event object. 2015-02-07 15:37:01 -08:00
Christopher Jeffrey
64d65c444a fix tput.js. 2015-02-07 15:07:32 -08:00
Christopher Jeffrey
974350d652 v0.0.44 2015-02-07 00:15:43 -08:00
Christopher Jeffrey
0290d7f15f clear response listeners after 2 seconds. 2015-02-07 00:15:25 -08:00
Christopher Jeffrey
d70fa6d4a2 fix wheel, move, and button decoding for mouse events. 2015-02-04 20:39:34 -08:00
Christopher Jeffrey
89b2dfc373 major reimplementation of sgr and urxvt mouse. mousewheel not yet tested. 2015-02-03 21:22:04 -08:00
Christopher Jeffrey
1d67e23993 add image element to example. ubuntu warning. add faq. 2015-02-01 14:17:18 -08:00
Christopher Jeffrey
5a4ddda37d shrink Image element by image size. 2015-02-01 14:01:55 -08:00
Christopher Jeffrey
c365c937e2 add test image for the Image element. 2015-02-01 13:47:12 -08:00
Christopher Jeffrey
6ee469fdcb add Image element using w3mimgdisplay. 2015-02-01 13:43:52 -08:00
Christopher Jeffrey
690cf9d3f4 stop listening for mouse sequences before switching to normal buffer. 2015-02-01 09:51:05 -08:00
Christopher Jeffrey
562b9fe502 v0.0.43 2015-02-01 09:32:53 -08:00
Christopher Jeffrey
a2afbe54bc detect bugged vte mouse better. see #89. 2015-02-01 09:22:18 -08:00
Christopher Jeffrey
c243415049 attempt to use both alternate screen buffer sequences. 2015-02-01 08:51:56 -08:00
Christopher Jeffrey
e9b3bdac34 allow VTE mouse access to cells up to 287. see #89. 2015-02-01 08:47:24 -08:00
Christopher Jeffrey
1d900c928d add vt200hilite for forced mouse modes. see #101. 2015-02-01 07:47:00 -08:00
Christopher Jeffrey
8efba79453 cast vc to an int. 2015-02-01 07:41:26 -08:00
Christopher Jeffrey
b6853fbd88 minor style fixes. 2015-02-01 07:36:53 -08:00
Christopher Jeffrey
10b8cc2fe1 comment. 2015-02-01 07:23:43 -08:00
Christopher Jeffrey
ac6b54c181 comments. license. 2015-02-01 07:22:39 -08:00
Christopher Jeffrey
f13f1242b2 gpm: add a gpmMouse option for setMouse. 2015-02-01 07:10:17 -08:00
Christopher Jeffrey
87a3d2f288 gpm: refactor to fit style. 2015-02-01 07:07:55 -08:00
Christopher Jeffrey
fae4acceef Merge remote-tracking branch 'mgliewe/master'
Conflicts:
	lib/program.js
2015-02-01 06:46:22 -08:00
Mario GLiewe
fc227ed503 workaropund: allow forced mouse protocol via env 2015-02-01 13:16:29 +01:00
Mario GLiewe
db435b179d fix: would crash if no gpm installed 2015-02-01 13:15:41 +01:00
Christopher Jeffrey
23c35a54d4 v0.0.42 2015-01-31 22:32:54 -08:00
Christopher Jeffrey
8247501924 check for OSX terminal env variables. 2015-01-31 22:29:43 -08:00
Christopher Jeffrey
9589eb81d6 more env variable checks for vte. 2015-01-31 22:22:15 -08:00
Christopher Jeffrey
32a783b282 check for terminator - more VTE usage. 2015-01-31 21:57:23 -08:00
Christopher Jeffrey
8047c9da4a v0.0.41 2015-01-31 20:07:04 -08:00
Christopher Jeffrey
ffbadfc988 add vt200Mouse to rxvt because it supports it. 2015-01-31 18:54:23 -08:00
Christopher Jeffrey
37f2313979 more vte+rxvt cleanup. see #89. 2015-01-31 18:49:15 -08:00
Christopher Jeffrey
3cdcc7a64b more fixes for VTE. see #89. 2015-01-31 18:36:47 -08:00
Christopher Jeffrey
f055496161 fix program.getCursor. fixes #25. 2015-01-31 12:57:21 -08:00
Christopher Jeffrey
a980a295bf v0.0.40 2015-01-31 12:36:17 -08:00
Christopher Jeffrey
955f509581 drop wrapCursor and parseChar. should be used for other terminfo feature checks. 2015-01-31 12:35:22 -08:00
Christopher Jeffrey
610e00ee21 use emitter.setMaxListeners(). 2015-01-31 12:32:33 -08:00
Christopher Jeffrey
1795cd93d6 use setImmediate everywhere. 2015-01-31 12:26:19 -08:00
Christopher Jeffrey
a9153aeef5 clean up process events. 2015-01-31 12:24:55 -08:00
Mario GLiewe
96a19b8523 Merge https://github.com/chjj/blessed 2015-01-31 21:21:14 +01:00
Christopher Jeffrey
27060d59af automatically deal with custom process events. fixes #100. 2015-01-31 12:19:00 -08:00
Christopher Jeffrey
127ae12c1b use urxvt mouse protocol for vte-based terminals. fixes #89. 2015-01-31 01:51:40 -08:00
Christopher Jeffrey
df73eb5e3e Revert "add workarounds for libvte mouse events. see #89."
This reverts commit bb61e5c144.
2015-01-31 01:51:12 -08:00
Christopher Jeffrey
bb61e5c144 add workarounds for libvte mouse events. see #89. 2015-01-31 01:43:16 -08:00
Christopher Jeffrey
d136c46ecc v0.0.39 2015-01-29 22:08:13 -08:00
Christopher Jeffrey
0386f8b5d6 the ACS is finally correct. 2015-01-29 21:53:06 -08:00
Christopher Jeffrey
547812928e window title. potential enter/return fix for keys. 2015-01-29 20:08:23 -08:00
Christopher Jeffrey
0881128a4f fix ACS for TERM=linux again. fix listbar .style. 2015-01-29 20:06:37 -08:00
Christopher Jeffrey
02176938c9 add screen.title property. misc. 2015-01-27 20:39:00 -08:00
Mario GLiewe
d8eff3fa55 fix: make mousewheel work for gpm 2015-01-28 04:01:49 +01:00
Mario GLiewe
efe4e475a6 added gpm support for linux vc 2015-01-28 03:43:48 +01:00
Christopher Jeffrey
5bdfc18daf cleanup unnecesary code after terminal element addition. 2015-01-24 21:33:30 -08:00
Christopher Jeffrey
879a072353 add terminal widget and hover box. 2015-01-24 18:34:57 -08:00
Christopher Jeffrey
4050376761 v0.0.38 2015-01-16 15:08:59 -08:00
Christopher Jeffrey
1872f1406d work around bad choice of method name. 2015-01-16 15:08:27 -08:00
Christopher Jeffrey
436c81204f include our own emitKeypressEvents. fixes #92. 2015-01-16 11:56:19 -08:00
Christopher Jeffrey
0cafb89831 fix label "fixed" behavior. widget-file.js. 2015-01-16 11:13:12 -08:00
Christopher Jeffrey
6b91546e15 fix negative autoPadding checks. 2015-01-16 10:55:24 -08:00
Christopher Jeffrey
f445dd8765 fix scrolling on widget-form.js. 2015-01-16 10:29:15 -08:00
Christopher Jeffrey
5300702e34 remove commented code. 2015-01-15 13:32:50 -08:00
Christopher Jeffrey
20dce38741 fix widget-pos test. 2015-01-15 13:29:46 -08:00
Christopher Jeffrey
0b4d70a207 remove attr comments. fix two scroll bugs. 2015-01-15 13:22:55 -08:00
Christopher Jeffrey
6eb28b6b4f more scrolling fixes. 2015-01-14 16:24:55 -08:00
Christopher Jeffrey
dafad57d0d fix scrolling. 2015-01-14 10:46:07 -08:00
Christopher Jeffrey
101058517b misc fixes pertaining to element scrolling. 2015-01-13 15:04:24 -08:00
Christopher Jeffrey
8bff88848b comment code that does not properly abide by autopadding. 2015-01-07 14:53:29 -08:00
Christopher Jeffrey (JJ)
0abbfda862 Merge pull request #68 from beardtree/no-list-padding
No list padding
2014-10-20 20:43:20 -07:00
Dan Kaplun
e53ec4caa8 No list padding 2014-10-04 14:08:44 -05:00
Christopher Jeffrey
98b931be7f v0.0.37 2014-06-27 00:54:24 -05:00
Christopher Jeffrey
23bba3f41e fix: separator tag. 2014-06-26 12:48:27 -05:00
Christopher Jeffrey
e03eb16e6b v0.0.36 2014-06-16 22:41:55 -05:00
Christopher Jeffrey
73c50e41a8 add separator tag: {|}. 2014-06-16 22:41:28 -05:00
Christopher Jeffrey
b544eb796e v0.0.35 2014-06-11 03:14:19 -05:00
Christopher Jeffrey
4cf8be871d refactor fuzzyFind. 2014-06-11 03:03:32 -05:00
Christopher Jeffrey
5b249d3fec fix loader. element focused property. 2014-06-10 21:41:22 -05:00
Christopher Jeffrey
d065230e70 v0.0.34 2014-06-09 17:42:48 -05:00
Christopher Jeffrey
e8571684a7 Merge pull request #52 from slap-editor/last-character-crop-fix
Fixes last character cropping bug
2014-06-05 12:54:27 -05:00
Dan Kaplun
832f47d2c5 Fixes last character cropping bug 2014-06-05 12:53:41 -05:00
Christopher Jeffrey
47ead5ea93 Merge pull request #59 from beardtree/handle-uncaught-exceptions
Adds handleUncaughtExceptions option that allows disabling of Screen's uncaughtException handler
2014-06-05 12:45:43 -05:00
Dan Kaplun
b945d5c734 Adds handleUncaughtExceptions option that allows disabling of Screen's uncaughtException handler 2014-06-05 12:22:38 -05:00
Christopher Jeffrey
458e4dfdea Merge pull request #43 from EndangeredMassa/master
fix setIndex to include last item
2014-06-05 01:28:38 -05:00
Christopher Jeffrey
a1ea57eaf0 Merge pull request #63 from beardtree/click-fix
Fixes clicking when mousedown element != mouseup element
2014-06-05 01:24:04 -05:00
Christopher Jeffrey
a2651e22ba Merge pull request #49 from slap-editor/mousewheel-modifier-keys-fix
Fixes scroll wheel support with modifiers for GNOME Terminal
2014-06-05 01:23:52 -05:00
Christopher Jeffrey
e265779369 stop event propagation with button.press if desired. fixes #64. 2014-06-05 01:12:47 -05:00
Christopher Jeffrey
6f91361197 add ignoreLocked option to Screen. 2014-06-05 01:10:36 -05:00
Christopher Jeffrey
ba3f0e0815 Merge pull request #54 from bulkan/feature/list-search
Run a `search` function in vi mode for List's
2014-06-05 01:13:41 -05:00
Christopher Jeffrey
38ad885dd7 v0.0.33 2014-06-02 08:41:49 -05:00
Christopher Jeffrey
31e9e9c0c6 add setLabel and removeLabel. 2014-06-02 07:53:58 -05:00
Christopher Jeffrey
5dc840844c v0.0.32 2014-06-02 03:36:25 -05:00
Christopher Jeffrey
09ec03058e fix typo in shrink calculation. 2014-06-01 23:56:32 -05:00
Christopher Jeffrey
8f6381ddf5 fix shrink calculcation in edge cases. 2014-06-01 23:55:27 -05:00
Christopher Jeffrey
bd92e3bf4f add selectTab and enterSelected methods. 2014-06-01 23:43:02 -05:00
Christopher Jeffrey
12d6318d39 reset index of list.pick(). 2014-06-01 21:29:16 -05:00
Christopher Jeffrey
1568e1f341 v0.0.31 2014-06-01 20:38:42 -05:00
Christopher Jeffrey
083a4901bd add ignoreKyes option to Message. 2014-06-01 20:38:36 -05:00
Christopher Jeffrey
db10ca1bc4 [dist] v0.0.30 2014-05-31 19:45:20 -05:00
Dan Kaplun
2aabb8ddff Fixes clicking when mousedown element != mouseup element 2014-05-30 08:32:19 -05:00
Dan Kaplun
4fcfdbaff3 Fixes scroll wheel support with modifiers for GNOME Terminal 2014-05-18 02:59:02 -05:00
Christopher Jeffrey
41994632cf fix: check detached state in .visible. fixes #58. 2014-05-16 18:51:33 -05:00
Bulkan Evcimen
d498c0b7a1 Added a new function to do a regexp match on ritems 2014-05-07 21:55:53 +10:00
Bulkan Evcimen
11ba4dad59 Added docs on the new search option for List's 2014-05-07 09:29:34 +10:00
Bulkan Evcimen
7df11051e6 Search for a List item based on its string
If the List has vi mode enabled and a `search` function is set on the options
property then hitting `/` will call this function passing in a callback.
The search function will need to call the callback with the search string
2014-05-07 07:40:19 +10:00
Christopher Jeffrey
9a70b404af revert nowrap test back to old content. 2014-04-26 06:50:34 -05:00
Christopher Jeffrey
b19af4deb7 another method of adding an escape tag. 2014-04-26 06:47:41 -05:00
Christopher Jeffrey
eb4090e257 Revert "add cdata-like tag."
This reverts commit bef9c09598.
2014-04-26 06:40:30 -05:00
Christopher Jeffrey
bfd4e4e611 add test for escape tag. 2014-04-26 06:40:24 -05:00
Christopher Jeffrey
bef9c09598 add cdata-like tag. 2014-04-26 06:39:45 -05:00
Christopher Jeffrey
4bc910bd5b add escape function for tag text. 2014-04-26 06:06:03 -05:00
Christopher Jeffrey
737c88d7e5 add widget-nowrap test. 2014-04-26 05:17:45 -05:00
Christopher Jeffrey
c0f85b2567 fix cut-off tags when wrapping is disabled. fixes #50. 2014-04-26 05:12:39 -05:00
Christopher Jeffrey
6694b35ee4 add getItem and getItemIndex to docs. 2014-04-26 01:09:18 -05:00
Christopher Jeffrey
44256dcf70 add getItem and getItemIndex for List. 2014-04-26 01:05:25 -05:00
Christopher Jeffrey
867dc086a0 update List docs. 2014-04-26 01:00:57 -05:00
Christopher Jeffrey
fe08f9e819 add List.clearItems method. fixes #40. 2014-04-26 00:55:43 -05:00
Christopher Jeffrey
9a9611636a simple way of escaping curly braces in tags for now. fixes #51. 2014-04-26 00:38:17 -05:00
Christopher Jeffrey
8ccc3dbc49 Revert "another way of escape curly braces in tags. see #51."
This reverts commit 434bddcfc7.
2014-04-26 00:33:05 -05:00
Christopher Jeffrey
434bddcfc7 another way of escape curly braces in tags. see #51. 2014-04-26 00:31:04 -05:00
Christopher Jeffrey
1a4506195c Revert "escaping curly braces in tags. see #51."
This reverts commit 7bfd309e1a.
2014-04-26 00:23:42 -05:00
Christopher Jeffrey
7bfd309e1a escaping curly braces in tags. see #51. 2014-04-26 00:22:25 -05:00
Christopher Jeffrey
9814f832fb Revert "possibly a better fix for form focusing. see #38."
This reverts commit 7965ee581c.
2014-03-30 03:56:38 -05:00
Christopher Jeffrey
7965ee581c possibly a better fix for form focusing. see #38. 2014-03-30 03:55:56 -05:00
Christopher Jeffrey
d624fe0c45 fix call stack overflow on form focusing. fixes #38. 2014-03-30 03:51:54 -05:00
Christopher Jeffrey
1bdba0dad0 potentially fix acs handling again: utf8 fallback on brokenACS. 2014-03-18 01:26:16 -05:00
Christopher Jeffrey
dc6f6ade41 fix acs handling with screen when LANG != utf8. 2014-03-18 01:24:49 -05:00
Sean Massa
16ff30a788 fix setIndex to include last item 2014-03-13 22:07:50 -05:00
Christopher Jeffrey
075ca1049a fix setItems keeping references to original arrays. 2014-01-25 16:31:15 -06:00
Christopher Jeffrey
304bd8e63e v0.0.29 2014-01-19 01:50:46 -06:00
Christopher Jeffrey
6777957ff2 improve reselection list updates. 2014-01-19 01:22:28 -06:00
Christopher Jeffrey
e3324d2216 v0.0.28 2014-01-17 19:55:27 -06:00
Christopher Jeffrey
8384a185a6 fix generateTags. 2014-01-17 19:54:59 -06:00
Christopher Jeffrey
1236f23f9e form methods. 2014-01-16 23:54:19 -06:00
Christopher Jeffrey
9673eaf517 form: do not focus invisible elements. 2014-01-16 18:08:59 -06:00
Christopher Jeffrey
f2ec07fd1c v0.0.27 2014-01-16 15:09:19 -06:00
Christopher Jeffrey
03e4d0d52b add item to ritems on appendItem. 2014-01-16 15:02:04 -06:00
Christopher Jeffrey
eae9fb5fbd form work. 2014-01-13 12:38:50 -06:00
Christopher Jeffrey
c218df7350 getLines and getScreenLines, handle detaching/reattaching widgets. 2014-01-13 10:25:31 -06:00
Christopher Jeffrey
445d9f4065 question improvement. 2014-01-12 10:40:18 -06:00
Christopher Jeffrey
491731f1d7 catch error. get rid of picklist. 2014-01-12 08:58:35 -06:00
Christopher Jeffrey
c0b3115fb3 add tests. 2014-01-12 06:19:54 -06:00
Christopher Jeffrey
0228b28cc4 potentially fix shrunken + scrollable elements. 2014-01-12 06:12:13 -06:00
Christopher Jeffrey
6a959074a4 multiple fixes/improvements. 2014-01-12 05:08:16 -06:00
Christopher Jeffrey
4cebb15918 key->prefix for listbar. misc. 2014-01-11 21:07:14 -06:00
Christopher Jeffrey
3766ffaa38 add tests. 2014-01-11 20:59:28 -06:00
Christopher Jeffrey
6fd0527c07 listbar cleanup. 2014-01-11 20:59:11 -06:00
Christopher Jeffrey
5930dab630 listbar scrolling work. 2014-01-11 20:47:40 -06:00
Christopher Jeffrey
2c337bb572 minor listbar work. 2014-01-11 19:32:43 -06:00
Christopher Jeffrey
401b1a61cd listbar rendering. 2014-01-11 19:28:14 -06:00
Christopher Jeffrey
2b33e34d3a even more listbar work. 2014-01-11 18:54:26 -06:00
Christopher Jeffrey
66933f63b6 remove old listbar.setItems. 2014-01-11 18:24:11 -06:00
Christopher Jeffrey
6ed2451e36 listbar work. 2014-01-11 18:23:38 -06:00
Christopher Jeffrey
045f8d6dc1 lots of work for different widgets. 2014-01-11 17:26:36 -06:00
Christopher Jeffrey
5b38ebfefd fix problem with textarea borders and cursors. 2014-01-05 01:01:21 -06:00
Christopher Jeffrey
8610fa3d5f v0.0.26 2014-01-04 16:11:05 -06:00
Christopher Jeffrey
e4de476c7f fix double line feed problem in textboxes. 2014-01-04 16:02:10 -06:00
Christopher Jeffrey
e3baaa9236 Revert "lazy loading for modules."
This reverts commit 999b47a71c58f0d327462067d126b592adce10eb.
2014-01-01 22:47:29 -06:00
Christopher Jeffrey
636bb45965 lazy loading for modules. 2014-01-01 22:47:29 -06:00
Christopher Jeffrey
c73a6c47b9 expose screen.enter and screen.leave. fixes #29. 2014-01-01 22:47:29 -06:00
Christopher Jeffrey
d49ffa7aa4 readme changes. 2014-01-01 22:47:29 -06:00
Christopher Jeffrey
42291fad3b Merge pull request #22 from naggie/master
add var self = this to progress bar
2014-01-01 19:54:56 -08:00
Christopher Jeffrey
6b7e632c90 fix CLA. 2013-12-04 06:37:55 -06:00
Christopher Jeffrey
63d2a36ac8 add CLA to readme. 2013-12-04 06:34:22 -06:00
Christopher Jeffrey
6a393f5a32 fix spacing in tput.js. 2013-12-04 06:34:17 -06:00
Christopher Jeffrey
647b8e1fef fix 12:00am for time.js. 2013-10-18 04:33:14 -05:00
Christopher Jeffrey
25b70f8f8f thicker numbers for time.js. 2013-10-16 23:19:56 -05:00
Christopher Jeffrey
781794ef92 allow custom bch for time.js. 2013-10-16 14:01:53 -05:00
Christopher Jeffrey
1451077f12 use bch properly. 2013-10-16 06:51:14 -05:00
Christopher Jeffrey
c8116f6569 fix clock centering. 2013-10-16 06:46:02 -05:00
Christopher Jeffrey
3e12897b31 time.js spacing and letter color. 2013-10-16 06:06:45 -05:00
Christopher Jeffrey
70864552db fix clock once again. 2013-10-14 10:08:15 -05:00
Christopher Jeffrey
31e3a0329e cleanup clock. 2013-10-14 10:02:08 -05:00
Christopher Jeffrey
495f90db3d add a terminal clock example. 2013-10-14 09:40:17 -05:00
Christopher Jeffrey
c5d2c45f19 readEditor error handling. 2013-09-14 00:02:00 -05:00
Callan Bryant
4d0ed49bac add var self = this to progress bar
Fixes crash when using progress bar:
	ReferenceError: self is not defined
	at ProgressBar.<anonymous>
	(/home/cbryant/bl/node_modules/blessed/lib/widget.js:4862:11)
	...
						v
2013-09-11 12:22:08 +01:00
Christopher Jeffrey
ac54a9d944 v0.0.25 2013-09-03 21:40:38 -05:00
Christopher Jeffrey
353794224c stop using termcap aliases. 2013-08-29 21:55:36 -05:00
Christopher Jeffrey
b5026af628 always default to windows-ansi on windows. minor refactor. 2013-08-29 18:22:35 -05:00
Christopher Jeffrey
a14650860d fix terminfo operators. fixes #19. 2013-08-29 17:47:14 -05:00
Christopher Jeffrey
97b6d6faee cleanup _prefix and readTermcap. 2013-08-29 17:41:19 -05:00
Christopher Jeffrey
a1c91ccb99 cleanup. 2013-08-28 23:49:25 -05:00
Christopher Jeffrey
4b1365bccc always have list item selected. 2013-08-27 11:10:09 -05:00
Christopher Jeffrey
1625046d9c filemanager label. do not hook remove() from List. 2013-08-27 10:25:20 -05:00
Christopher Jeffrey
f8c2ebef1d assume screen.tput is present. 2013-08-27 09:04:00 -05:00
Christopher Jeffrey
e563155b0e update readme. 2013-08-25 00:30:45 -05:00
Christopher Jeffrey
9cb55b3711 v0.0.24 2013-08-24 23:28:20 -05:00
Christopher Jeffrey
00ee15a32f better terminfo/cap discovery. fixes #17. 2013-08-24 22:31:33 -05:00
Christopher Jeffrey
fdfdac63a8 minor test change. 2013-08-24 21:28:15 -05:00
Christopher Jeffrey
38f234aa91 add getScrollHeight. fixes #16. 2013-08-20 13:34:18 -05:00
Christopher Jeffrey
b280a3c320 v0.0.23 2013-08-18 15:05:23 -05:00
Christopher Jeffrey
0eaff0bb07 fix enter key workaround. minor. typo. 2013-08-18 15:02:35 -05:00
Christopher Jeffrey
18d97ce0d7 fix calls to clearPos in render hooks. 2013-08-15 07:14:56 -05:00
Christopher Jeffrey
65fd7d2529 fix shrink rendering bug. 2013-08-15 06:42:08 -05:00
Christopher Jeffrey
34e451bbfa minor fix. potential fixes. 2013-08-13 13:09:24 -05:00
Christopher Jeffrey
2953a469da do not scroll if detached. fixes #8. 2013-08-13 13:01:31 -05:00
Christopher Jeffrey
8460e1c8a0 possibly fix max autoPadding height+border problem
An element with a border has a child with no height or width properties, but a
left and top of 0: this causes the child elements background to cover the
bottom and right borders. It doesn't have a `position.right`, but `iright`
still needs to be subtracted.
2013-08-13 11:56:30 -05:00
Christopher Jeffrey
214ad84a66 add setIndex method. see #9. 2013-08-13 11:44:04 -05:00
Christopher Jeffrey
070cbd9001 decode mouse events and responses properly. 2013-08-13 11:30:44 -05:00
Christopher Jeffrey
d42adf7e32 make enter and return keypresses identical on all platforms. see #2. 2013-08-13 11:30:20 -05:00
Christopher Jeffrey
6f9ae457e4 add button.value. add simple form example. 2013-08-13 10:54:17 -05:00
Christopher Jeffrey
185a05d759 rename bgChar. 2013-08-12 09:07:19 -05:00
Christopher Jeffrey
4b6cf96030 Merge pull request #12 from johnspackman/element-bg-char
Added a background fill character to Element
2013-08-12 06:50:19 -07:00
John Spackman
ffd98d0f8e Added a background fill character to Element
This is used to fill the background of the element, EG for text area I
typically set this to '_' to show the extent of the field
2013-08-12 14:45:01 +01:00
Christopher Jeffrey
7b3557262f check TERMINFO_DIRS correctly. 2013-08-11 23:13:28 -05:00
Christopher Jeffrey
980e65bd2c try hex char representations for terminfo subdirectory. see #2. 2013-08-11 23:04:00 -05:00
Christopher Jeffrey
a30d3ecbe8 switch back to old acs. 2013-08-10 15:48:27 -05:00
Christopher Jeffrey
66dc2118e7 add fastCSR option. 2013-08-10 10:02:29 -05:00
Christopher Jeffrey
fc92dca39c remove old acs code. 2013-08-10 09:34:37 -05:00
Christopher Jeffrey
2ba6dcc2b8 acs work. potential wide char support. 2013-08-10 09:33:41 -05:00
Christopher Jeffrey
7f23ade08b v0.0.22 2013-08-08 13:49:59 -05:00
Christopher Jeffrey
8c558dbf3f fix clearPos and clickable/keyable check on removal. fixes #6. 2013-08-08 13:47:59 -05:00
Christopher Jeffrey
599b186614 v0.0.21 2013-08-08 12:20:37 -05:00
Christopher Jeffrey
94bdb41dd1 fix readme. improve tput._print. refactor test/tput.js. 2013-08-08 06:19:44 -05:00
Christopher Jeffrey
45f8f0e5bb add getScroll method. 2013-08-06 01:06:33 -05:00
Christopher Jeffrey
16bbb5ea24 allow zero-width elements. enforce minimums for shrink. 2013-08-04 09:20:50 -05:00
Christopher Jeffrey
6cb640c0e5 remove non-printable chars from comment. 2013-08-04 08:46:26 -05:00
Christopher Jeffrey
abd89d3aee minor: fix indexOf call. 2013-08-04 08:40:53 -05:00
Christopher Jeffrey
4ad7d90c9d mark acs as broken if the terminal uses the pc alt charset as acs. 2013-08-04 08:36:51 -05:00
Christopher Jeffrey
c05beb3059 setup method. use path.sep wherever possible. misc. 2013-08-04 08:13:01 -05:00
Christopher Jeffrey
8ebbbbac65 add setText and getText methods. expose element and node. 2013-08-04 04:59:28 -05:00
Christopher Jeffrey
dadf185a87 cleanup mouse handler. improve "visible" getter. 2013-08-04 04:38:29 -05:00
Christopher Jeffrey
c746cd7197 v0.0.20 2013-08-04 01:29:54 -05:00
Christopher Jeffrey
17c4cb1e2a minor changes and cleanup. 2013-08-04 01:21:48 -05:00
Christopher Jeffrey
b5c7aed3ad clean up old code. 2013-08-04 01:21:48 -05:00
Christopher Jeffrey
5317e14c98 fix Button in readme. 2013-08-04 01:21:48 -05:00
Christopher Jeffrey
981de641ae Merge pull request #5 from mscdex/master
better Windows support
2013-08-03 23:20:38 -07:00
mscdex
a1616aec0a Better Windows support 2013-08-02 21:59:49 -04:00
Christopher Jeffrey
b7fa80cc2e fix uncaught error throwing. 2013-08-02 12:47:22 -05:00
Christopher Jeffrey
7a8a0d2591 setMouse improvements. do not allow fg changes on selected items. do not bubble render events. 2013-08-02 05:59:54 -05:00
Christopher Jeffrey
8efe06e8f4 explain event bubbling in the readme. 2013-08-01 20:10:21 -05:00
Christopher Jeffrey
52a9f5d182 fix scroll rendering for children with padding. 2013-08-01 20:00:24 -05:00
Christopher Jeffrey
c4a7f05025 obscure overlapping sides in scrolling elements. 2013-08-01 04:19:58 -05:00
Christopher Jeffrey
598be3bb88 refactor constructors. 2013-08-01 03:28:10 -05:00
Christopher Jeffrey
d3c34f6f89 optimize clickable sort. better autofocus. flush on exception. 2013-08-01 02:52:03 -05:00
Christopher Jeffrey
b2666ffecb add event bubbling. 2013-08-01 01:02:16 -05:00
Christopher Jeffrey
0e047b8e51 minor fixes. 2013-07-31 19:21:10 -05:00
Christopher Jeffrey
f3df07a237 buffer everything. cancel acs at the end of draw() if necessary. 2013-07-31 17:43:03 -05:00
Christopher Jeffrey
51771dc19a add log method to program object. 2013-07-31 00:43:24 -05:00
Christopher Jeffrey
2e58aed1ea refactor position and new padding code. 2013-07-30 23:57:48 -05:00
Christopher Jeffrey
78a3726f2f add auto-positioning which respects padding and borders. 2013-07-30 23:46:07 -05:00
Christopher Jeffrey
ac88ceaebe remove radio-button handling from checkbox. 2013-07-29 19:27:15 -05:00
Christopher Jeffrey
33214ee924 cleanup new dump method. 2013-07-29 19:06:22 -05:00
Christopher Jeffrey
b7e7a8264b better dumps. 2013-07-29 19:00:31 -05:00
Christopher Jeffrey
81267dbd2a move el._focus to screen._focus. 2013-07-29 17:40:48 -05:00
Christopher Jeffrey
af27e80447 fix readme typo. 2013-07-29 17:35:48 -05:00
Christopher Jeffrey
82322ac017 allow border option to be a string. 2013-07-29 17:22:21 -05:00
Christopher Jeffrey
1f17a48af3 maintain the readme example in example/ 2013-07-29 17:18:30 -05:00
Christopher Jeffrey
31c0d2a550 add keywords to package.json. 2013-07-29 17:11:42 -05:00
Christopher Jeffrey
9328c0e401 fix scrollablebox/text mixup in readme. 2013-07-29 17:09:23 -05:00
Christopher Jeffrey
3b5196910c update readme code example. 2013-07-29 17:06:36 -05:00
Christopher Jeffrey
24ceab93f9 new textarea/textbox options. 2013-07-29 17:04:39 -05:00
Christopher Jeffrey
631f42bd74 v0.0.19 2013-07-29 16:59:05 -05:00
Christopher Jeffrey
1a4c0cd761 fix mwidth for elements with no content. 2013-07-29 16:49:44 -05:00
Christopher Jeffrey
36415f76b6 fix textbox/textarea. 2013-07-29 16:38:19 -05:00
Christopher Jeffrey
d2226c3295 improve focus. fix getCoords. readme. 2013-07-29 15:49:09 -05:00
Christopher Jeffrey
a3e2983b4b fix form errors. 2013-07-29 10:40:59 -05:00
Christopher Jeffrey
6a03ad42ff textbox. progressbar. misc. readme. 2013-07-29 09:14:03 -05:00
Christopher Jeffrey
2dfedf5e47 enable textbox input-on-focus. 2013-07-29 04:23:52 -05:00
Christopher Jeffrey
9b77e3df63 fix setEffects and failed fg/bg 256 color sequences. 2013-07-29 04:22:20 -05:00
Christopher Jeffrey
9a1411338c fix small error. 2013-07-28 14:49:01 -05:00
Christopher Jeffrey
0bc25d9989 make dumps for all tests. 2013-07-28 14:45:38 -05:00
Christopher Jeffrey
3bcbd9b39f enable new parseTags method. clean up old code. 2013-07-28 14:18:28 -05:00
Christopher Jeffrey
084f28fcff content attribute and tag handling.
- handle content attributes with better respect to element's style.
- add a more sophisticated tag parser.
2013-07-28 13:20:52 -05:00
Christopher Jeffrey
927c40d2f3 fix mwidth. minor. 2013-07-28 10:51:43 -05:00
Christopher Jeffrey
f8fbb2a0c8 remove dwidth characters for now. 2013-07-28 10:19:04 -05:00
Christopher Jeffrey
f236898f73 optimize shrink width. 2013-07-28 10:02:04 -05:00
Christopher Jeffrey
9cc1f53d9a refactor wrapContent. 2013-07-28 09:43:28 -05:00
Christopher Jeffrey
88da43bfaf fix empty lines in wrapContent. 2013-07-28 09:24:08 -05:00
Christopher Jeffrey
a82ad19110 fixed only affects one level of scrollable ancestors. 2013-07-28 03:01:09 -05:00
Christopher Jeffrey
38473b6bfa comments. enable csr for elements with scrollbars. 2013-07-27 08:13:29 -05:00
Christopher Jeffrey
d9ca7112bc scrollbar track. 2013-07-27 07:34:32 -05:00
Christopher Jeffrey
80ae319225 back_color_erase comments. 2013-07-27 06:53:09 -05:00
Christopher Jeffrey
8f989eeadd fix scrollbar arithmetic. 2013-07-27 06:52:45 -05:00
Christopher Jeffrey
69f5993735 make new scrollable code compatible with get=false. add fixed option. 2013-07-27 05:37:53 -05:00
Christopher Jeffrey
2dc3146d1f cleanup scroll. 2013-07-27 05:19:32 -05:00
Christopher Jeffrey
ee71a1ac61 more scroll work. 2013-07-27 05:14:02 -05:00
Christopher Jeffrey
d63762fbe8 tput.js fixes. 2013-07-27 05:13:04 -05:00
Christopher Jeffrey
efbae0c203 cleanup scroll code. 2013-07-26 01:45:39 -05:00
Christopher Jeffrey
8ea1fe4dab working nested scrolling. 2013-07-26 01:38:25 -05:00
Christopher Jeffrey
ea857ea550 fix nested scrollable elements. 2013-07-25 18:09:00 -05:00
Christopher Jeffrey
19dd8a47d0 fix scrolling obfuscation for elements with borders. 2013-07-25 01:20:47 -05:00
Christopher Jeffrey
25133923e3 allow text to be obfuscated within child elements during a scroll. 2013-07-24 22:47:03 -05:00
Christopher Jeffrey
11d7a98303 make textbox inherit from textarea. 2013-07-24 20:41:11 -05:00
Christopher Jeffrey
633b76cec5 more textbox/textarea refactoring. 2013-07-24 18:20:30 -05:00
Christopher Jeffrey
c1f17e866c refactor textbox and textarea render/setValue. 2013-07-24 18:05:56 -05:00
Christopher Jeffrey
6fde3e3a38 misc fixes for radiobutton, textarea, textbox, checkbox. 2013-07-24 17:16:55 -05:00
Christopher Jeffrey
1c9d25780a add a scrollable option. 2013-07-24 15:39:22 -05:00
Christopher Jeffrey
5e2f1061d1 misc - add a blessed.js file. 2013-07-24 14:41:02 -05:00
Christopher Jeffrey
1b5155cfae refactor and clean up program.js. 2013-07-24 14:17:52 -05:00
Christopher Jeffrey
0372788f2d add a buffering write function for program. 2013-07-24 13:23:35 -05:00
Christopher Jeffrey
2f7967031e readme. move Box methods onto Element. add clearBaseLine and getContent. 2013-07-23 18:38:55 -05:00
Christopher Jeffrey
31030113cf buffer everything - this prevents flickering on xterm and may improve terminal rendering speed. 2013-07-23 18:04:22 -05:00
Christopher Jeffrey
65829a2234 use csr on fm test. 2013-07-23 17:06:01 -05:00
Christopher Jeffrey
b6bee303a9 fix scroll obfuscation. 2013-07-23 16:57:30 -05:00
Christopher Jeffrey
9aaabacf68 fix initial setContent call. fix spawn() cursor handling. 2013-07-23 16:37:54 -05:00
Christopher Jeffrey
da49a89b28 refactor wrapContent. fix/use/improve getCoords(), scroll(), hide(). 2013-07-23 15:40:53 -05:00
Christopher Jeffrey
76cc6d37e7 make text wrapping optional. 2013-07-23 14:43:14 -05:00
Christopher Jeffrey
f56d7386c6 more pre-wrap line handling improvements. 2013-07-23 14:37:44 -05:00
Christopher Jeffrey
36c5351fde allow handling of pre-wrapped text for line methods. 2013-07-23 14:16:20 -05:00
Christopher Jeffrey
6bfb47632e list.items fix. box line methods. 2013-07-23 13:31:05 -05:00
Christopher Jeffrey
b8f1241bca fix scrolling glitch. 2013-07-23 10:38:54 -05:00
Christopher Jeffrey
73939984b4 misc scrollable positioning. 2013-07-23 09:38:30 -05:00
Christopher Jeffrey
add8aaa664 stop using the options object for positioning. 2013-07-23 07:04:52 -05:00
Christopher Jeffrey
11c6e7269f matchColor and BCE tput check. 2013-07-23 06:34:40 -05:00
Christopher Jeffrey
77885514aa go back to using arrays for out for now. 2013-07-23 03:29:37 -05:00
Christopher Jeffrey
8c4d70d1e1 fix BCE handling. 2013-07-23 03:07:57 -05:00
Christopher Jeffrey
8f936d00b7 tput.js refactor. rename variables. 2013-07-23 00:37:13 -05:00
Christopher Jeffrey
5e2ca90f04 more tput.js work, fixes. cleanup. 2013-07-23 00:25:04 -05:00
Christopher Jeffrey
fe9406aba1 more tput fixes/improvements/refactoring. 2013-07-22 22:28:01 -05:00
Christopher Jeffrey
e771fc9fc9 improvements to tput and colors. 2013-07-22 00:59:56 -05:00
Christopher Jeffrey
346e39b723 cleanup. improve BCE. remove old code. 2013-07-21 23:53:10 -05:00
Christopher Jeffrey
00e680d413 work on adding back_color_erase handling, acs optimization, and other stuff ncurses usually handles. 2013-07-21 21:05:35 -05:00
Christopher Jeffrey
de79656b04 rewrite scrolling system a bit. 2013-07-21 05:36:45 -05:00
Christopher Jeffrey
62ebd04231 move el.focus code elsewhere. 2013-07-21 02:12:35 -05:00
Christopher Jeffrey
a98bef4c90 more scrolling improvements. scrolling form. 2013-07-21 02:03:06 -05:00
Christopher Jeffrey
7af4dbaf1c allow for left/top/right/bottom padding. 2013-07-19 03:14:36 -05:00
Christopher Jeffrey
e33838804b scrollable elements. 2013-07-19 01:58:55 -05:00
Christopher Jeffrey
0f4b60314b allow tabbing from textboxes in forms. 2013-07-18 22:49:06 -05:00
Christopher Jeffrey
df317bb472 improve position, attribute parsing. misc. 2013-07-18 22:27:18 -05:00
Christopher Jeffrey
3ae01237be fix tput string concatenation. 2013-07-18 18:09:03 -05:00
Christopher Jeffrey
b8e0fafaeb misc. options. refactor tests/bin. 2013-07-18 18:02:45 -05:00
Christopher Jeffrey
f03f51267b only emit attach if the element was not previously attached. 2013-07-18 15:06:33 -05:00
Christopher Jeffrey
48c2bae2a0 do not violate 80 col limit. 2013-07-18 15:01:42 -05:00
Christopher Jeffrey
4333952081 fix recursion in Form object. 2013-07-18 14:33:00 -05:00
Christopher Jeffrey
61653e3f19 optimize terminfo compilation by using string concatenation instead of array.join. 2013-07-18 09:31:06 -05:00
Christopher Jeffrey
6141b383f1 add a getCoords() method. 2013-07-18 03:56:12 -05:00
Christopher Jeffrey
3c42a91fc5 add wrapContent to Element prototype. 2013-07-18 02:44:31 -05:00
Christopher Jeffrey
42351724d3 move wrapContent. 2013-07-18 02:37:18 -05:00
Christopher Jeffrey
fa2206bb0a allow lowercase charset names. 2013-07-18 02:12:05 -05:00
Christopher Jeffrey
90c9484d8b remove old response() code. 2013-07-18 02:01:33 -05:00
Christopher Jeffrey
b46d1161c5 refactor responses. 2013-07-18 01:51:08 -05:00
Christopher Jeffrey
7b7330ec5a fix CHA, fix SU and SD. 2013-07-18 00:22:24 -05:00
Christopher Jeffrey
5c114b8b69 fixed shrunken centered nested elements. 2013-07-17 12:43:13 -05:00
Christopher Jeffrey
ab449a12e3 scrollbar and list attr fixes. 2013-07-17 12:01:54 -05:00
Christopher Jeffrey
54445e3f3c tests 2013-07-17 10:29:42 -05:00
Christopher Jeffrey
1838f2d720 v0.0.18 2013-07-17 10:26:34 -05:00
Christopher Jeffrey
e9f7d933bd replace shrink padding code. 2013-07-17 05:44:58 -05:00
Christopher Jeffrey
8e81ef015b refactor shrink. 2013-07-17 05:22:42 -05:00
Christopher Jeffrey
1ae6a19b35 refactor scrollbar. fix shrink comparisons. 2013-07-17 04:59:21 -05:00
Christopher Jeffrey
e13f0ce5d4 rename _lastPos to lpos. 2013-07-17 04:41:43 -05:00
Christopher Jeffrey
29cd1a376f more Box.render refactoring. docs. misc. 2013-07-17 04:32:13 -05:00
Christopher Jeffrey
6f8ab54a4f refactor. stop usign xi_, yi_. 2013-07-17 03:57:30 -05:00
Christopher Jeffrey
566b800a04 refactor shrink. 2013-07-17 03:52:21 -05:00
Christopher Jeffrey
8776ec2c2d listbar and improve shrinkBox. 2013-07-17 03:20:37 -05:00
Christopher Jeffrey
70953689e2 allow style.hover and style.focus. no autofocus on buttons. 2013-07-17 01:55:08 -05:00
Christopher Jeffrey
c805b80209 do not set lastPos on render(true). remove old code. 2013-07-17 01:34:43 -05:00
Christopher Jeffrey
7981f8d749 add shrinkBox. add forms. add RadioSet. misc refactor. 2013-07-17 01:28:42 -05:00
Christopher Jeffrey
cac1924b14 docs. fix line. fix attr objects. 2013-07-16 22:28:56 -05:00
Christopher Jeffrey
1561bdef7d add valign. simpler way of rendering padding bg. 2013-07-16 20:19:44 -05:00
Christopher Jeffrey
c8c0d1f269 have padding maintain background color. 2013-07-16 20:09:01 -05:00
Christopher Jeffrey
c61d4e6b80 v0.0.17 2013-07-16 19:25:11 -05:00
Christopher Jeffrey
fbf08e1288 fix progress bar colors. 2013-07-16 19:23:39 -05:00
Christopher Jeffrey
8a32e87cd9 remove all cens() calls. 2013-07-16 19:13:16 -05:00
Christopher Jeffrey
52042e8abc fix readme. 2013-07-16 19:12:08 -05:00
Christopher Jeffrey
2923c38dc4 v0.0.16 2013-07-16 19:08:09 -05:00
Christopher Jeffrey
aa9bd9da6a permanently rename ascii->line for borders. 2013-07-16 19:07:46 -05:00
Christopher Jeffrey
9ed9764b74 fix ACS/UTF8. use style object. rename ascii to line. 2013-07-16 19:05:44 -05:00
Christopher Jeffrey
7074d0da91 more terminfo paths. 2013-07-16 15:57:12 -05:00
Christopher Jeffrey
445e278af0 check all terminfo/termcap paths/variables. 2013-07-16 15:13:17 -05:00
Christopher Jeffrey
7e238a470e itemBg, style object, el.sattr. 2013-07-16 12:33:55 -05:00
Christopher Jeffrey
db365a2228 pass object in to attr functions. 2013-07-16 04:23:11 -05:00
Christopher Jeffrey
0aafeb2530 parseContent comment. 2013-07-16 03:50:42 -05:00
Christopher Jeffrey
28bd6ba3e4 fix textareas. 1 cell margin on content for textareas. 2013-07-16 01:57:07 -05:00
Christopher Jeffrey
c5d47187cf comments for wrapContent. 2013-07-16 01:42:21 -05:00
Christopher Jeffrey
edc216fa37 allow attributes to be functions. 2013-07-16 01:06:00 -05:00
Christopher Jeffrey
b266f389e9 fix colors. 2013-07-16 00:18:31 -05:00
Christopher Jeffrey
9881369aa1 readme screenshot. 2013-07-15 20:33:47 -05:00
Christopher Jeffrey
733b3ac8f7 screenshot. 2013-07-15 20:27:28 -05:00
Christopher Jeffrey
caf04598d2 v0.0.15 2013-07-15 20:01:39 -05:00
Christopher Jeffrey
3332e9d34e hex colors in program. another wrapContent fix. 2013-07-15 19:35:36 -05:00
Christopher Jeffrey
87dc701b46 misc. docs. 2013-07-15 18:53:04 -05:00
Christopher Jeffrey
12e7eab68d docs. key() fix. wrapContent() fix. box.{insert,delete}Line fix. 2013-07-15 17:50:27 -05:00
Christopher Jeffrey
bc99d7fc37 small refactor. 2013-07-15 13:15:41 -05:00
Christopher Jeffrey
97b442d3ec misc high level widget fixes. 2013-07-15 05:00:26 -05:00
Christopher Jeffrey
211491409b allow multiple lines for box insert/delete lines. 2013-07-15 04:40:44 -05:00
Christopher Jeffrey
51413c346e docs. smartCSR option. minor fixes. 2013-07-15 04:31:09 -05:00
Christopher Jeffrey
158572ae38 fix max scroll lines number. 2013-07-14 23:37:36 -05:00
Christopher Jeffrey
4683b1d542 remove old prepend/append code. 2013-07-14 22:13:18 -05:00
Christopher Jeffrey
aa951c640f use better cleanside detection algorithm. add insert method. 2013-07-14 22:11:48 -05:00
Christopher Jeffrey
4541fc5c50 minor change to alloc. 2013-07-14 12:21:14 -05:00
Christopher Jeffrey
caa21ee356 optimize alloc+clear. add a output dump option. 2013-07-14 12:08:03 -05:00
Christopher Jeffrey
c9c01e0805 refactor. comments. 2013-07-14 11:58:44 -05:00
Christopher Jeffrey
5ebfb4835f fix and enable cleanSides. 2013-07-14 11:39:03 -05:00
Christopher Jeffrey
fd5bd89d56 check scrollable elements for "clean" sides for CSR rendering. 2013-07-14 11:26:19 -05:00
Christopher Jeffrey
95848bafa3 automatically optimize scrollable elements for csr and il/dl. 2013-07-14 11:07:48 -05:00
Christopher Jeffrey
6a44fd9a35 misc. add sigtstp method. 2013-07-14 10:16:19 -05:00
Christopher Jeffrey
990fb0d796 minor property rename. 2013-07-14 09:32:50 -05:00
Christopher Jeffrey
04b0adac56 fix padding implementation. tests. 2013-07-14 08:57:05 -05:00
Christopher Jeffrey
9db97cd61c easier feature checking. 2013-07-14 08:37:57 -05:00
Christopher Jeffrey
3e6a89099e add mouse test. 2013-07-14 08:06:47 -05:00
Christopher Jeffrey
0c6695d236 colors, line, and mouses fixes. 2013-07-14 08:05:42 -05:00
Christopher Jeffrey
965af859b0 make mouse coords zero indexed. 2013-07-14 07:35:00 -05:00
Christopher Jeffrey
2105eb3d5b improve mouse enabling. 2013-07-14 07:16:33 -05:00
Christopher Jeffrey
155eac8677 potential cursor handling during render. 2013-07-14 07:02:59 -05:00
Christopher Jeffrey
d0f99be764 lazily convert colors. other misc color fixes. 2013-07-14 06:57:15 -05:00
Christopher Jeffrey
5753d7b6ab better color reduction. 2013-07-14 06:43:17 -05:00
Christopher Jeffrey
d5f3874105 clean up old code. 2013-07-14 06:30:09 -05:00
Christopher Jeffrey
363bc44caa fix terminfo if/else. detect features. 2013-07-14 06:24:04 -05:00
Christopher Jeffrey
342ed23b66 always enabled terminfo. prop rename. 2013-07-13 23:41:47 -05:00
Christopher Jeffrey
ccf3794be2 unicode detect. docs. device attr. focus/blur. smacs checks. 2013-07-13 23:38:43 -05:00
Christopher Jeffrey
8aa718c280 comment. 2013-07-13 21:03:03 -05:00
Christopher Jeffrey
b5be1f318d remove unnecessary characters from SCLD. 2013-07-13 20:54:27 -05:00
Christopher Jeffrey
3c0582c304 first implementation of SCLD usage. 2013-07-13 20:47:29 -05:00
Christopher Jeffrey
fe39c786a6 higher level widgets. 2013-07-13 20:46:25 -05:00
Christopher Jeffrey
2b15290021 resize delay. 2013-07-12 21:51:24 -05:00
Christopher Jeffrey
0950c7e62e v0.0.14 2013-07-12 11:44:42 -05:00
Christopher Jeffrey
95c527ff73 save cursor position before spawning process. fixes textareas. 2013-07-12 11:44:04 -05:00
Christopher Jeffrey
dba2d39f80 v0.0.13 2013-07-12 11:32:42 -05:00
Christopher Jeffrey
9fd97f0b03 small pick method improvement. 2013-07-12 11:30:32 -05:00
Christopher Jeffrey
8015a8fd1c v0.0.12 2013-07-12 11:18:27 -05:00
Christopher Jeffrey
932fe2b8f6 comment. docs. 2013-07-12 10:22:06 -05:00
Christopher Jeffrey
a801b47e28 improve mouse events by sorting by index. 2013-07-12 09:14:42 -05:00
Christopher Jeffrey
7414922a76 add filemanager widget. g keys. 2013-07-12 08:28:58 -05:00
Christopher Jeffrey
28d6b096ab v0.0.11 2013-07-12 05:40:08 -05:00
Christopher Jeffrey
5dcb8f3200 action event. docs. 2013-07-12 05:39:22 -05:00
Christopher Jeffrey
ac1658ffd0 v0.0.10. 2013-07-12 05:32:30 -05:00
Christopher Jeffrey
97c582164b keys. no mouse focus events. 2013-07-12 05:11:15 -05:00
Christopher Jeffrey
87a5188de9 docs. keys. misc. 2013-07-12 04:59:58 -05:00
Christopher Jeffrey
b92c0b7758 drop old insert/delete line methods. 2013-07-12 03:54:01 -05:00
Christopher Jeffrey
933b5442bd insert, set, get, delete, clear lines. 2013-07-12 03:52:14 -05:00
Christopher Jeffrey
42399b17ab setEffects. misc fixes. 2013-07-12 03:34:32 -05:00
Christopher Jeffrey
3ef2048289 omove. misc. 2013-07-12 01:13:29 -05:00
Christopher Jeffrey
ead26b4a66 start using zero-indexed instance of Program. 2013-07-12 00:36:36 -05:00
Christopher Jeffrey
5a96c3611d misc. remove old code. 2013-07-12 00:21:40 -05:00
Christopher Jeffrey
cc863af2cf zero indexed program to mirror tput. 2013-07-12 00:03:48 -05:00
Christopher Jeffrey
d452b72dd8 optimize updateCursor with CUU, CUD, CUF, and CUB. 2013-07-11 23:17:10 -05:00
Christopher Jeffrey
2356d30394 hide focus. public index prop. select item on dbl click. 2013-07-11 22:52:46 -05:00
Christopher Jeffrey
3eb382e8f1 color names. tabs in textareas/boxes. cleanup old code. focus behavior. 2013-07-11 20:54:52 -05:00
Christopher Jeffrey
150a7c2439 v0.0.9 2013-07-10 12:48:35 -05:00
Christopher Jeffrey
2c43b2ccec fix hover effects. refactor. 2013-07-10 12:48:18 -05:00
Christopher Jeffrey
31a0a0a2e6 fix textarea cursor position. 2013-07-06 02:54:04 -05:00
Christopher Jeffrey
0db80e844b v0.0.8 2013-07-04 02:18:27 -05:00
Christopher Jeffrey
9b363b47de remove old code. 2013-07-04 02:18:27 -05:00
Christopher Jeffrey
e7e8216611 clearPos. fix textarea. 2013-07-04 02:18:26 -05:00
Christopher Jeffrey
06400d089f add multiline textareas. remove old hoverBg code. 2013-07-04 02:18:26 -05:00
Christopher Jeffrey
6355b1259f docs, tests, examples, misc, editor. 2013-07-04 02:18:26 -05:00
Christopher Jeffrey
05216eadbb remove _isScreen. 2013-07-04 02:18:26 -05:00
Christopher Jeffrey
6ec3534fcd misc fixes. remove dead code. 2013-07-04 02:18:26 -05:00
Christopher Jeffrey
1a62484509 Merge pull request #1 from demands/readme_fix
Re-render screen after clicking on example box in README
2013-06-30 10:35:26 -07:00
Max Edmands
a39092df49 Re-render screen after clicking on example box in README
It seems like this is necessary for your example to work.
Is there a way to re-render a portion of the screen instead of the entire thing?
2013-06-30 10:17:27 -07:00
Christopher Jeffrey
1d562debc9 v0.0.7 2013-06-29 17:26:12 -07:00
Christopher Jeffrey
44904082ad blank line 2013-06-29 15:56:32 -07:00
Christopher Jeffrey
888ba0d1a4 remove old code. 2013-06-29 15:46:47 -07:00
Christopher Jeffrey
7908b34f2e compare indexes for render order on mouseover. 2013-06-29 11:09:22 -07:00
Christopher Jeffrey
5d5c522577 fix hover and mouse events. 2013-06-29 10:07:51 -07:00
Christopher Jeffrey
6663c6c3f0 potential wrap content fix. 2013-06-26 19:15:49 -05:00
Christopher Jeffrey
a1e9ec5a55 cleanup render. ignore border option on scrollbar. 2013-06-25 18:23:15 -05:00
Christopher Jeffrey
edc5535682 add an optional scrollbar for scrollable-box. 2013-06-25 18:17:21 -05:00
Christopher Jeffrey
c265194182 change screen keypress behavior. 2013-06-25 17:31:13 -05:00
Christopher Jeffrey
77593efd05 readme, tput, mouse, types, misc. 2013-06-25 06:35:15 -05:00
Christopher Jeffrey
07334af6fc readme. reduce screen events. 2013-06-24 06:16:02 -05:00
Christopher Jeffrey
e094f843db save/restore focus. 2013-06-20 13:03:31 -05:00
Christopher Jeffrey
5265275d0d cleaner content parsing. 2013-06-20 12:07:35 -05:00
Christopher Jeffrey
38c9f1f177 textbox hidden. insert lines. 2013-06-20 11:48:12 -05:00
Christopher Jeffrey
8a39e9aaf4 check for parseTags in wrapContent. recenter shrunken elements. 2013-06-20 08:12:39 -05:00
Christopher Jeffrey
dc623ee0d1 vshrink and hshrink checks. 2013-06-20 07:55:52 -05:00
Christopher Jeffrey
5ef468c192 cleanup textbox. 2013-06-20 07:47:42 -05:00
Christopher Jeffrey
4f0f9e53d7 major cleanup. remove old code. 2013-06-20 07:18:04 -05:00
Christopher Jeffrey
f431e98c03 major changes. better content formatting and parsing. 2013-06-20 06:43:56 -05:00
Christopher Jeffrey
5b8a16df23 readme. example. 2013-06-18 11:00:41 -05:00
Christopher Jeffrey
d4ce9322cd more events. setItems. predefined keys. docs. 2013-06-18 10:52:48 -05:00
Christopher Jeffrey
ef9178f7d0 docs. better cleanup. 2013-06-18 06:30:26 -05:00
Christopher Jeffrey
787c7c6945 more scroll fixing. 2013-06-18 05:44:36 -05:00
Christopher Jeffrey
3d52833fa3 numerous improvements. 2013-06-18 05:33:24 -05:00
Christopher Jeffrey
f59f7dc0e0 colors.js refactor. 2013-06-16 10:49:54 -05:00
Christopher Jeffrey
188561c9ca fix colors.js. 2013-06-16 10:16:34 -05:00
Christopher Jeffrey
44b290b86c color handling. 2013-06-16 10:13:39 -05:00
Christopher Jeffrey
dc2bfda057 mousemove and mouse refactor. fixes. 2013-06-16 10:12:47 -05:00
Christopher Jeffrey
f0b107978b button and shrink work. 2013-06-16 08:38:14 -05:00
Christopher Jeffrey
2c632522e7 sattr changes. 2013-06-14 20:22:20 -05:00
Christopher Jeffrey
5247b41d8b constructor and options handling. 2013-06-14 15:58:54 -05:00
Christopher Jeffrey
8cf00fe1b7 rename Screen._default. 2013-06-14 03:51:12 -05:00
Christopher Jeffrey
59b13fae82 alignment refactor. 2013-06-14 03:46:40 -05:00
Christopher Jeffrey
4f199c26aa replace Text with Box element .shrink=true. 2013-06-14 03:35:45 -05:00
Christopher Jeffrey
b0b949b301 list resizing. 2013-06-14 03:28:59 -05:00
Christopher Jeffrey
b597bdd1c1 minor changes. 2013-06-14 02:58:12 -05:00
Christopher Jeffrey
268fbfef6a minor changes to sgr handling. 2013-06-14 00:38:36 -05:00
Christopher Jeffrey
9eaf45acab parsable attribute tags. 2013-06-13 20:21:41 -05:00
Christopher Jeffrey
6669d199ef add padding option. 2013-06-13 19:02:02 -05:00
Christopher Jeffrey
05a8c9897b docs. 2013-06-13 16:49:48 -05:00
Christopher Jeffrey
aca4fd9833 default fg/bg. 2013-06-13 14:58:50 -05:00
Christopher Jeffrey
c70ec71e07 Revert "setCell function."
This reverts commit 34b7520c44.
2013-06-13 14:58:00 -05:00
Christopher Jeffrey
34b7520c44 setCell function. 2013-06-13 14:57:46 -05:00
Christopher Jeffrey
1c6681e99d different border drawing. 2013-06-13 05:30:21 -05:00
Christopher Jeffrey
fccb1627a6 fix text alignment. 2013-06-13 04:44:00 -05:00
Christopher Jeffrey
831425d5af add example online game created with blessed. 2013-06-13 04:32:35 -05:00
Christopher Jeffrey
54bde3badd insert test: from bottom to the top, top to bottom and back. 2013-06-13 04:24:22 -05:00
Christopher Jeffrey
1765d44a69 add shrink option to Box. 2013-06-13 04:22:45 -05:00
Christopher Jeffrey
d9a0b49bce text alignment. first step to deprecate Text. 2013-06-13 04:14:14 -05:00
Christopher Jeffrey
bca271fbe6 refactor attr swap. 2013-06-13 02:26:09 -05:00
Christopher Jeffrey
607013b22b blink, inverse, invisible. 2013-06-13 02:22:01 -05:00
Christopher Jeffrey
461af61a59 refactor colors/attr. 2013-06-13 02:16:32 -05:00
Christopher Jeffrey
761e2a2aaf insert and delete line functions utilizing csr. 2013-06-13 01:33:10 -05:00
Christopher Jeffrey
9963df5343 optimize setters. 2013-06-12 14:31:48 -05:00
Christopher Jeffrey
843736d5b1 allow vertical progress bars. 2013-06-12 04:18:47 -05:00
Christopher Jeffrey
796a3f0ddd fix hide/show error. 2013-06-12 03:47:35 -05:00
Christopher Jeffrey
db001078b2 minor. 2013-06-11 20:16:18 -05:00
Christopher Jeffrey
9eaac2045b improve parsed content handling. 2013-06-11 15:16:41 -05:00
Christopher Jeffrey
0eb04e4e6e fix scroll resizing. 2013-06-11 14:30:36 -05:00
Christopher Jeffrey
b4566dc48b comment. 2013-06-11 14:23:39 -05:00
Christopher Jeffrey
6357b4dfff stop reverting to el.height for offsets if it is bigger than parent.height. 2013-06-11 14:00:18 -05:00
Christopher Jeffrey
94426dfd79 remove old code. comments. 2013-06-11 13:57:06 -05:00
Christopher Jeffrey
02c57a34ce emit more events. use tput. 2013-06-11 13:51:01 -05:00
Christopher Jeffrey
495060e074 typo 2013-06-11 12:53:28 -05:00
Christopher Jeffrey
3bdbca77a9 docs formatting. 2013-06-11 12:52:18 -05:00
Christopher Jeffrey
6bf8afb357 docs. minor changes. 2013-06-11 12:05:14 -05:00
Christopher Jeffrey
39b7ae7546 multiple positioning improvements. tests. 2013-06-11 10:37:22 -05:00
Christopher Jeffrey
a7f2823df2 stop hooking addListener. 2013-06-11 09:27:50 -05:00
Christopher Jeffrey
8f4e23130e positioning test. fix screen key listening. 2013-06-11 09:23:42 -05:00
Christopher Jeffrey
f463aa7b52 moving. resizing. fix scrolling. 2013-06-11 09:09:57 -05:00
Christopher Jeffrey
e3571d1281 setContent content handling for scrollable text. 2013-06-09 21:35:18 -05:00
Christopher Jeffrey
c9d09547ac add test content. 2013-06-09 20:41:25 -05:00
Christopher Jeffrey
07351bdcb0 cleanup recent scroll work. fix max. 2013-06-09 20:33:57 -05:00
Christopher Jeffrey
ee739c6e7a better content parsing and scrolling. 2013-06-09 20:19:32 -05:00
Christopher Jeffrey
c260bb9a02 add focus history. 2013-06-09 15:52:22 -05:00
Christopher Jeffrey
a19d9baf48 global element events. automatically focus on click. 2013-06-09 15:24:57 -05:00
Christopher Jeffrey
b04f8d04b2 fix textbox focusing. 2013-06-09 15:02:12 -05:00
Christopher Jeffrey
87aef67274 cleanup old textbox code. 2013-06-09 14:34:13 -05:00
Christopher Jeffrey
b29dddc547 refactor progressbar. horizontal scroll for textbox. 2013-06-09 14:32:29 -05:00
Christopher Jeffrey
41c4560a6f add text input and setContent. 2013-06-09 13:17:24 -05:00
Christopher Jeffrey
812aa7fa42 automatically use alternate buffer etc. 2013-06-09 11:48:36 -05:00
Christopher Jeffrey
2cbbe786fb better screen and parent handling. scroll improvements. 2013-06-09 11:39:05 -05:00
Christopher Jeffrey
48658c4cf9 fix progressbar. 2013-06-07 07:12:53 -05:00
Christopher Jeffrey
8cca60beac add workaround for screen-256color terminfo. use correct terminfo fallback. 2013-06-07 06:47:17 -05:00
Christopher Jeffrey
8f0025c650 comments. 2013-06-07 06:17:15 -05:00
Christopher Jeffrey
3eee2599b7 more efficient content scrolling. 2013-06-07 05:58:00 -05:00
Christopher Jeffrey
7fb6b2cc3b fix mouse events for overlapping elements. 2013-06-06 10:27:19 -05:00
Christopher Jeffrey
0477f38a2d escape code and newline handling for Text. 2013-06-06 10:14:00 -05:00
Christopher Jeffrey
5902e224e5 better escape/newline handling. 2013-06-06 09:37:39 -05:00
Christopher Jeffrey
cbda45ae11 positioning 2013-06-06 08:18:46 -05:00
Christopher Jeffrey
b7f18f6f61 escape codes and newline handling. 2013-06-06 07:57:50 -05:00
Christopher Jeffrey
2cf1e5ee44 fix mousewheel on scrollables. 2013-06-06 05:49:47 -05:00
Christopher Jeffrey
5d67e189a8 allow element hiding. 2013-06-06 05:38:30 -05:00
Christopher Jeffrey
ac10c408e3 optimize rendering even more. 2013-06-06 05:19:52 -05:00
Christopher Jeffrey
d0473749c9 potentially allow newlines in text content. 2013-06-06 04:40:06 -05:00
Christopher Jeffrey
ed2b9ae4d0 major improvements. 2013-06-06 04:03:25 -05:00
Christopher Jeffrey
1d37b2b6e2 reorganize 2013-06-03 20:33:08 -05:00
Christopher Jeffrey
dbacb6f8ed Revert "auto calculate top for lists."
This reverts commit 5ec1f2808c.
2013-06-03 20:06:58 -05:00
Christopher Jeffrey
5ec1f2808c auto calculate top for lists. 2013-06-03 20:06:55 -05:00
Christopher Jeffrey
45dec1039c first working scrollable box. 2013-06-02 22:32:34 -05:00
Christopher Jeffrey
4b61da17c9 full list item fix. 2013-06-01 06:43:09 -05:00
Christopher Jeffrey
210d956214 border measures. 2013-06-01 06:08:18 -05:00
Christopher Jeffrey
493004b521 fixes. scrollble work. 2013-06-01 05:47:18 -05:00
Christopher Jeffrey
4fe0e98704 lists. misc. 2013-06-01 02:06:04 -05:00
Christopher Jeffrey
7e85f82426 first working highlevel example. 2013-06-01 00:29:31 -05:00
Christopher Jeffrey
58b2bf8f74 example. resize. 2013-05-31 21:44:43 -05:00
Christopher Jeffrey
0b77cb0d27 more cleanup 2013-05-31 21:40:04 -05:00
Christopher Jeffrey
4c52543f98 example, fix scrollable, cleanup, percentage positions. 2013-05-31 21:39:15 -05:00
Christopher Jeffrey
342f56a822 finally commit experimental high level interface. 2013-05-31 21:09:07 -05:00
Christopher Jeffrey
a1c82b1aa7 set-title for screen. 2013-04-28 17:39:46 -05:00
Christopher Jeffrey
110059704d fix else...then. 2013-03-09 04:57:39 -06:00
Christopher Jeffrey
9ee2cbb5ed v0.0.6 2013-03-06 04:53:39 -06:00
Christopher Jeffrey
00b5a5b6f7 have extended area start on an even byte. 2013-03-06 04:53:08 -06:00
Christopher Jeffrey
b664a21cdd v0.0.5 2013-03-06 04:49:38 -06:00
Christopher Jeffrey
2c41e0b862 include extended header in output. 2013-03-06 04:44:48 -06:00
Christopher Jeffrey
ca1bf91c52 add xterm-256color terminfo. 2013-03-06 04:28:03 -06:00
Christopher Jeffrey
42815f72fa add extended xterm features. 2013-03-06 04:27:42 -06:00
Christopher Jeffrey
e2621f4025 use git diff for test. 2013-03-06 04:13:12 -06:00
Christopher Jeffrey
78c2803523 do not gracefully handle bad parse errors. 2013-03-06 04:03:54 -06:00
Christopher Jeffrey
134ebe28c0 Revert "misc changes."
This reverts commit 20121bec954e6744d9756e3f60a65f04fd897bbc.
2013-03-05 21:49:45 -06:00
Christopher Jeffrey
14c3e82d16 misc changes. 2013-03-05 18:16:14 -06:00
Christopher Jeffrey
962a7bdcc6 handle terminfo fallback better. 2013-03-05 17:38:41 -06:00
Christopher Jeffrey
87ffe00a06 comment 2013-03-05 14:31:34 -06:00
Christopher Jeffrey
0adfd54133 add compiled xterm terminfo. 2013-03-05 13:09:23 -06:00
Christopher Jeffrey
1d00832772 comments 2013-03-05 03:04:06 -06:00
Christopher Jeffrey
83053e7fe4 script 2013-03-05 02:48:31 -06:00
Christopher Jeffrey
464451859a comments. 2013-03-05 02:40:00 -06:00
Christopher Jeffrey
7f0ab93e0d cleanup 2013-03-05 02:28:20 -06:00
Christopher Jeffrey
176df61343 refactor 2013-03-04 20:03:00 -06:00
Christopher Jeffrey
c7f68baec6 improve test. add configurable termcap/info file options. 2013-03-04 18:22:23 -06:00
Christopher Jeffrey
0e7e6f853b xterm terminfo/termcap 2013-03-04 15:11:49 -06:00
Christopher Jeffrey
f7a569c628 refactor. assert. 2013-03-04 13:00:14 -06:00
Christopher Jeffrey
51bc7c388c comments. misc. 2013-03-01 07:02:14 -06:00
Christopher Jeffrey
f460c99015 v0.0.4 2013-02-28 18:03:48 -06:00
Christopher Jeffrey
36971ed715 minor 2013-02-28 18:01:07 -06:00
Christopher Jeffrey
a3bf0984ca fix termcap aliases. 2013-02-28 01:41:25 -06:00
Christopher Jeffrey
36df8ef3ca fix termcap aliases. 2013-02-28 01:36:27 -06:00
Christopher Jeffrey
4ed0bda9ff recursively inherit from other termcap entries. 2013-02-28 01:26:08 -06:00
Christopher Jeffrey
6acb18fba4 improve compileTerminfo. try to read from $TERMCAP. 2013-02-28 01:17:37 -06:00
Christopher Jeffrey
76fa728a89 fix %r. remove comment. 2013-02-27 19:55:03 -06:00
Christopher Jeffrey
629995a669 add an assert. 2013-02-27 19:40:57 -06:00
Christopher Jeffrey
086414a5c5 fix printf %c. 2013-02-27 19:39:08 -06:00
Christopher Jeffrey
f2c4c01d9e expose data for debugging. 2013-02-27 19:28:59 -06:00
Christopher Jeffrey
fbd85c660b fix test. 2013-02-27 18:31:22 -06:00
Christopher Jeffrey
d5208b758f refactor 2013-02-27 18:25:59 -06:00
Christopher Jeffrey
df0aeb5005 more work 2013-02-27 17:43:28 -06:00
Christopher Jeffrey
fe004fff34 work 2013-02-27 17:26:34 -06:00
Christopher Jeffrey
3897e49ef8 more termcap work. 2013-02-27 17:17:26 -06:00
Christopher Jeffrey
8f09c278f1 translate termcap caps to terminfo. 2013-02-27 16:57:11 -06:00
Christopher Jeffrey
1f979b35ac cleanup 2013-02-27 16:36:02 -06:00
Christopher Jeffrey
f1fe73e974 termcap compilation 2013-02-27 16:34:57 -06:00
Christopher Jeffrey
8a3f29fddb refactor 2013-02-27 12:26:33 -06:00
Christopher Jeffrey
983dfa943e inherit tput objects properties. 2013-02-27 12:23:55 -06:00
Christopher Jeffrey
f7e8cde45e misc 2013-02-27 12:17:15 -06:00
Christopher Jeffrey
ea85c1778f remove comments. 2013-02-25 19:10:51 -06:00
Christopher Jeffrey
44ca13c291 refactor. misc fixes. 2013-02-25 19:10:19 -06:00
Christopher Jeffrey
618ba14369 optional printf. 2013-02-25 06:29:46 -06:00
Christopher Jeffrey
ce69995f1d enable extended for testing by default. 2013-02-25 06:15:17 -06:00
Christopher Jeffrey
1684a267dc Revert "use sprintf"
This reverts commit af1ad01b99.
2013-02-25 06:12:52 -06:00
Christopher Jeffrey
af1ad01b99 use sprintf 2013-02-25 06:12:28 -06:00
Christopher Jeffrey
36fa2fc1db remove unused code. 2013-02-25 06:10:56 -06:00
Christopher Jeffrey
49a8f59091 fix printf. 2013-02-25 06:06:34 -06:00
Christopher Jeffrey
b71203be18 refactor. comment. 2013-02-25 02:16:33 -06:00
Christopher Jeffrey
ea4542027b fix clr_eos/ed and other possible collisions. 2013-02-25 02:05:27 -06:00
Christopher Jeffrey
68911aa357 more tput usage. 2013-02-25 01:47:32 -06:00
Christopher Jeffrey
55ba68195e start using tput. 2013-02-25 01:14:38 -06:00
Christopher Jeffrey
edf2dfa5dc remove fallback prop name. comments. 2013-02-25 00:40:46 -06:00
Christopher Jeffrey
7f99d7a8e1 move tput test. 2013-02-24 20:58:08 -06:00
Christopher Jeffrey
13a4f59ef6 handle empty strings in compiler. 2013-02-24 19:24:57 -06:00
Christopher Jeffrey
7a7bc00777 add comments explaining extended parsing. 2013-02-24 19:15:53 -06:00
Christopher Jeffrey
a549b6e56f disable extended parsing in test for now. 2013-02-24 18:53:25 -06:00
Christopher Jeffrey
bf60ca69e7 final cleanup 2013-02-24 18:48:36 -06:00
Christopher Jeffrey
d89f9845ab fix finding end of string table. 2013-02-24 18:43:04 -06:00
Christopher Jeffrey
1bd2a71946 cleanup 2013-02-24 18:22:32 -06:00
Christopher Jeffrey
8d92eb49c6 more ext work 2013-02-24 18:20:31 -06:00
Christopher Jeffrey
eefc2842a6 cleanup 2013-02-24 16:43:26 -06:00
Christopher Jeffrey
c4de02651e more messy work 2013-02-24 16:31:33 -06:00
Christopher Jeffrey
8b479fb169 messy work on extended parser. 2013-02-24 15:07:54 -06:00
Christopher Jeffrey
38d3a6445a add _print(). 2013-02-24 12:58:29 -06:00
Christopher Jeffrey
58d2c383e8 bin, readme. 2013-02-24 12:53:37 -06:00
Christopher Jeffrey
c9dc4f2d98 add unsupported property on unsupported capabilties. 2013-02-24 12:49:48 -06:00
Christopher Jeffrey
5f9df53708 sprintf 2013-02-24 12:44:53 -06:00
Christopher Jeffrey
9b8983d355 add bin/tput.js 2013-02-24 12:20:24 -06:00
Christopher Jeffrey
06d6734622 allow options object for Program constructor. 2013-02-24 12:05:24 -06:00
Christopher Jeffrey
1d2c2f182b first attempt at an sprintf function. 2013-02-24 11:56:27 -06:00
Christopher Jeffrey
b41ac01700 potentially use sprintf function. 2013-02-24 11:20:30 -06:00
Christopher Jeffrey
318bc09cf2 add all terminfo aliases 2013-02-24 10:59:20 -06:00
Christopher Jeffrey
5d9c3cccda fix printf command 2013-02-24 08:22:37 -06:00
Christopher Jeffrey
5075fa6efb fix escaped chars 2013-02-24 08:19:38 -06:00
Christopher Jeffrey
f80fb93419 fix comments 2013-02-24 08:14:54 -06:00
Christopher Jeffrey
59de26fcbe fix and test padding. 2013-02-24 08:13:25 -06:00
Christopher Jeffrey
6913cb9363 display max colors. 2013-02-24 08:04:07 -06:00
Christopher Jeffrey
60edb202a3 fix types. 2013-02-24 08:02:07 -06:00
Christopher Jeffrey
6c6b4f8f66 refactor, options, comments. flags. 2013-02-24 07:55:24 -06:00
Christopher Jeffrey
587443f9e3 clean up compiler 2013-02-24 07:44:48 -06:00
Christopher Jeffrey
4000eb0412 fix readme and test. 2013-02-24 07:43:19 -06:00
Christopher Jeffrey
f8569144ea fix termcap parser 2013-02-24 07:40:42 -06:00
Christopher Jeffrey
4703d45fef cleanup parsers 2013-02-24 07:39:29 -06:00
Christopher Jeffrey
bc20f65f85 readme 2013-02-23 20:52:49 -06:00
Christopher Jeffrey
857a83a3fb add parsePadding 2013-02-23 20:48:24 -06:00
Christopher Jeffrey
f83e3304d1 refactor readTermcap 2013-02-23 16:03:39 -06:00
Christopher Jeffrey
fb752f1783 add names array to terminfo data. 2013-02-23 16:01:50 -06:00
Christopher Jeffrey
fe0e82f046 add references to termcap data for all term names. 2013-02-23 15:58:59 -06:00
Christopher Jeffrey
26440e76e1 reorganize termcap object. 2013-02-23 15:56:02 -06:00
Christopher Jeffrey
07cb619214 move terminfo test file. 2013-02-22 17:53:08 -06:00
Christopher Jeffrey
f26d4dd93a rename. 2013-02-22 16:12:34 -06:00
Christopher Jeffrey
6dad574249 cleanup 2013-02-22 15:54:10 -06:00
Christopher Jeffrey
c477f71dd2 add termcap parser. 2013-02-22 15:51:13 -06:00
Christopher Jeffrey
a784ca6a2b minor 2013-02-22 11:12:05 -06:00
Christopher Jeffrey
d04c335aa9 refactor 2013-02-22 05:20:50 -06:00
Christopher Jeffrey
17891e74c7 refactor ^c handling 2013-02-22 04:11:04 -06:00
Christopher Jeffrey
f17634dfa7 more helper functions 2013-02-22 03:40:58 -06:00
Christopher Jeffrey
1988c22cab better escaping. 2013-02-21 05:39:29 -06:00
Christopher Jeffrey
badfaf95aa optimzations. fix escape. 2013-02-21 03:08:39 -06:00
Christopher Jeffrey
6c6c652638 use out.push instead of o() 2013-02-20 14:01:01 -06:00
Christopher Jeffrey
c1d9868b49 fixes 2013-02-20 08:11:32 -06:00
Christopher Jeffrey
270a5af7e8 refactor. 2013-02-19 19:22:43 -06:00
Christopher Jeffrey
40d89449f6 padding. flags. all methods. 2013-02-19 13:21:28 -06:00
Christopher Jeffrey
2984a58930 test file 2013-02-18 15:24:55 -06:00
Christopher Jeffrey
29720f05d1 more cleanup 2013-02-18 15:17:30 -06:00
Christopher Jeffrey
ef991d5a26 cleanup 2013-02-18 11:00:44 -06:00
Christopher Jeffrey
d35e49afb0 refactor 2013-02-17 16:40:45 -06:00
Christopher Jeffrey
1d26b0a6c1 fix a few commands. 2013-02-17 14:55:27 -06:00
Christopher Jeffrey
80b330a2be finally working 2013-02-17 13:25:58 -06:00
Christopher Jeffrey
fe2d881a08 more work 2013-02-16 17:54:20 -06:00
Christopher Jeffrey
59cc5d73c3 refactor compile 2013-02-16 15:12:53 -06:00
Christopher Jeffrey
214c10e547 more code refactoring 2013-02-16 12:18:45 -06:00
Christopher Jeffrey
c083164e33 better code 2013-02-15 17:08:36 -06:00
Christopher Jeffrey
14df28fb35 code 2013-02-15 14:10:23 -06:00
Christopher Jeffrey
f5fdf2a9c0 clean up comments 2013-02-15 11:50:08 -06:00
Christopher Jeffrey
3e8cea6a23 tput work 2013-02-14 09:39:08 -06:00
Christopher Jeffrey
7b067f2e65 helpers 2013-02-07 14:24:30 -06:00
Christopher Jeffrey
48d7d73116 minor 2013-02-07 12:43:51 -06:00
Christopher Jeffrey
9020f645af lazily set raw mode. 2013-02-07 12:33:50 -06:00
Christopher Jeffrey
1428b7137b refactor. clean up. more colors. 2013-02-07 12:19:49 -06:00
Christopher Jeffrey
04f4145524 v0.0.3 2013-02-01 21:00:51 -06:00
Christopher Jeffrey
f03d84bb7b readme. example. fixes. response codes. 2013-01-29 23:26:27 -06:00
Christopher Jeffrey
0b62eabfce fix xterm mouse quirk 2013-01-29 18:07:52 -06:00
Christopher Jeffrey
61b9a58368 comments. urxvt mouse support. 2013-01-29 17:57:47 -06:00
136 changed files with 72312 additions and 523 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

15
.jscsrc Normal file
View File

@ -0,0 +1,15 @@
{
"preset": "airbnb",
"esnext": false,
"requireTrailingComma": null,
"requireCommaBeforeLineBreak": null,
"requireCamelCaseOrUpperCaseIdentifiers": null,
"requirePaddingNewLinesBeforeLineComments": null,
"requirePaddingNewLinesAfterBlocks": null,
"safeContextKeyword": "self",
"maximumLineLength": 110,
"maxErrors": 1000,
"requireSpaceAfterLineComment": true
}

41
.jshintrc Normal file
View File

@ -0,0 +1,41 @@
{
"bitwise": false,
"curly": false,
"eqeqeq": true,
"freeze": true,
"latedef": "nofunc",
"maxparams": 7,
"noarg": true,
"shadow": "inner",
"undef": true,
"unused": true,
"boss": true,
"expr": true,
"eqnull": true,
"evil": true,
"loopfunc": true,
"proto": true,
"supernew": true,
"-W018": true,
"-W064": true,
"-W086": true,
"+W032": true,
"browser": false,
"browserify": false,
"node": true,
"nonstandard": true,
"typed": true,
"worker": false,
"camelcase": false,
"indent": 2,
"maxlen": 110,
"newcap": true,
"quotmark": "single",
"laxbreak": true,
"laxcomma": true
}

6
.npmignore Normal file
View File

@ -0,0 +1,6 @@
.git*
test/
img/
node_modules/
.jshintrc
.jscsrc

83
CHANGELOG.md Normal file
View File

@ -0,0 +1,83 @@
# Blessed v0.1.0 - new terminal goodies for node.js
![blessed](https://raw.githubusercontent.com/chjj/blessed/master/img/v0.1.0-3.gif)
The features demonstrated in the above gif __element transparency/shadow__ and
__border docking__.
## New useful options for your typewriter application:
- __`transparent` option__ - Lower element opacity to 50%. This will display
dimmed elements and content behind the foreground element using a naive color
blending function (good enough for a terminal's limited amount of colors).
works best with 256color terminals. (see widget-shadow.js)
- __`shadow` option__ - Give the element a translucent shadow. Automatically
darkens the background behind it. (see widget-shadow.js)
- __`dockBorders` option__ - Element borders will automatically "dock" to each
other. Instead of overlapping the borders end up connecting. (see
widget-dock.js)
- __`autoPadding` default__ - Auto padding is now enabled by default, meaning
blessed will automatically position elements inside their parent's border.
- __`rleft` property__ - Relative offsets are now default element properties
(`left` instead of `rleft`).
- __`draggable` property__ - Make any element draggable with the mouse. (see
widget-shadow.js or widget-dock.js)
- __`Table` and `ListTable` elements__ - Tables with a high quality rendering.
(see widget-table.js and widget-listtable.js)
- __`Log` element__ - A top to bottom logger box with scrollback and other
features. (see widget-log.js)
- __Obscurable borders__ - In addition to docking borders, it's possible to
obscure borders by sliding them off the screen with negative offsets. (see
widget-dock.js)
- __Percentage expressions__ - Like CSS, arithmetic can now be performed on
percentages. e.g. `width: '50%-1'`. This is useful for overlapping borders on
elements with a percentage width. (see widget-dock.js)
## Other features that weren't mentioned before:
- __`setHover` option__ - Set a hover text box to follow cursor on mouseover,
similar to how a web browser handles the "title" attribute. (see widget.js)
- __`Terminal` element__ - Spin up a pseudo terminal as a blessed element.
useful for writing a terminal multiplexer. (requires term.js and pty.js as
optional dependencies). (see example/multiplex.js)
- __`Image` element__ - Uses `w3mimgdisplay` to draw real images your terminal.
this is much easier than calling w3mimgdisplay by hand. Image elements behave
like any other element, although it is wise to use `width: 'shrink', height:
'shrink'`. (see widget-image.js)
---
The major things that justified the 0.1.0 release were fixes and stabilization
of api (`autoPadding`/`rleft`/`left`). Scrolling boxes were almost completely
revamped to work a bit smarter.
---
## Things yet to come:
- __@secrettriangle's [improvements](https://github.com/slap-editor/slap) for
textareas__ - This allows for real text navigation.
- __Gravity and margin layouts__
This is something that's been in the idea bin for a while. Every element could
potentially have properties like:
```
gravity: 'bottomleft',
margin: 5,
``
In other words, just a more complex `float` system than what the CSSOM is used
to.

View File

@ -1,4 +1,5 @@
Copyright (c) 2013, Christopher Jeffrey (https://github.com/chjj/)
Copyright (c) 2013-2015, Christopher Jeffrey and contributors
https://github.com/chjj/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

2407
README.md

File diff suppressed because it is too large Load Diff

16
bin/tput.js Executable file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env node
var blessed = require('../')
, argv = process.argv.slice(2)
, cmd = argv.shift()
, tput;
tput = blessed.tput({
terminal: process.env.TERM,
termcap: !!process.env.USE_TERMCAP,
extended: true
});
if (tput[cmd]) {
process.stdout.write(tput[cmd].apply(tput, argv));
}

7
browser/Makefile Normal file
View File

@ -0,0 +1,7 @@
all:
@cd .. && browserify -e index.js -o browser/blessed.js
clean:
@rm -f blessed.js
.PHONY: clean all

105
browser/transform.js Normal file
View File

@ -0,0 +1,105 @@
/**
* transform.js - browserify workaround for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
var Transform = require('stream').Transform
, path = require('path')
, fs = require('fs');
/**
* Transformer
*/
function transformer(code) {
var stream = new Transform;
stream._transform = function(chunk, encoding, callback) {
return callback(null, chunk);
};
stream._flush = function(callback) {
if (code) {
stream.push(code);
}
return callback();
};
return stream;
}
/**
* Explicitly require all widgets in widget.js
*/
var widgets = fs.readdirSync(__dirname + '/../lib/widgets');
var requireWidgets = widgets.reduce(function(out, name) {
name = path.basename(name, '.js');
out += '\nrequire(\'./widgets/' + name + '\');';
return out;
}, '');
/**
* Do not make filesystem calls in tput.js for
* terminfo or termcap, just use xterm terminfo/cap.
*/
var infoPath = path.resolve(__dirname, '..', 'usr', 'xterm-256color')
, capPath = path.resolve(__dirname, '..', 'usr', 'xterm.termcap');
var infoPathFake = path.resolve(
path.sep, 'usr', 'share', 'terminfo',
path.basename(infoPath)[0],
path.basename(infoPath)
);
function readMethods() {
Tput._infoBuffer = new Buffer(TERMINFO, 'base64');
Tput.prototype.readTerminfo = function() {
this.terminal = TERMINFO_NAME;
return this.parseTerminfo(Tput._infoBuffer, TERMINFO_PATH);
};
Tput.cpaths = [];
Tput.termcap = TERMCAP;
Tput.prototype._readTermcap = Tput.prototype.readTermcap;
Tput.prototype.readTermcap = function() {
this.terminal = TERMCAP_NAME;
return this._readTermcap(this.terminal);
};
Tput.prototype.detectUnicode = function() {
return true;
};
}
readMethods = readMethods.toString().slice(24, -2)
.replace(/^ /gm, '')
.replace('TERMINFO', JSON.stringify(fs.readFileSync(infoPath, 'base64')))
.replace('TERMINFO_NAME', JSON.stringify(path.basename(infoPath)))
.replace('TERMINFO_PATH', JSON.stringify(infoPathFake))
.replace('TERMCAP', JSON.stringify(fs.readFileSync(capPath, 'utf8')))
.replace('TERMCAP_NAME', JSON.stringify(path.basename(capPath, '.termcap')));
/**
* Helpers
*/
function end(file, offset) {
return file.split(path.sep).slice(-offset).join('/');
}
/**
* Expose
*/
module.exports = function(file) {
if (end(file, 2) === 'lib/widget.js') {
return transformer(requireWidgets);
}
if (end(file, 2) === 'lib/tput.js') {
return transformer(readMethods);
}
return transformer();
};

View File

@ -0,0 +1,20 @@
Copyright (c) 2015, Christopher Jeffrey
https://github.com/chjj/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,17 @@
# ansi-viewer
A terminal app to view ANSI art from http://artscene.textfiles.com/ansi/.
![ansi-viewer](https://raw.githubusercontent.com/chjj/blessed/master/img/ansi-viewer.png)
## Contribution and License Agreement
If you contribute code to this project, you are implicitly allowing your code
to be distributed under the MIT license. You are also implicitly verifying that
all code is your original work. `</legalese>`
## License
Copyright (c) 2015, Christopher Jeffrey. (MIT License)
See LICENSE for more info.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
/**
* ansi-viewer
* ANSI art viewer for node.
* Copyright (c) 2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
var blessed = require('blessed')
, request = require('request')
, singlebyte = require('./singlebyte')
, fs = require('fs');
// $ wget -r -o log --tries=10 'http://artscene.textfiles.com/ansi/'
// $ grep 'http.*\.ans$' log | awk '{ print $3 }' > ansi-art.list
var urls = fs.readFileSync(__dirname + '/ansi-art.list', 'utf8').trim().split('\n');
var map = urls.reduce(function(map, url) {
map[/([^.\/]+\/[^.\/]+)\.ans$/.exec(url)[1]] = url;
return map;
}, {});
var max = Object.keys(map).reduce(function(out, text) {
return Math.max(out, text.length);
}, 0) + 6;
var screen = blessed.screen({
smartCSR: true,
dockBorders: true
});
var art = blessed.terminal({
parent: screen,
left: 0,
top: 0,
height: 60,
// some are 78/80, some are 80/82
width: 82,
border: 'line',
tags: true,
label: ' {bold}{cyan-fg}ANSI Art{/cyan-fg}{/bold} (Drag Me) ',
handler: function() {},
draggable: true
});
var list = blessed.list({
parent: screen,
label: ' {bold}{cyan-fg}Art List{/cyan-fg}{/bold} (Drag Me) ',
tags: true,
draggable: true,
top: 0,
right: 0,
width: max,
height: '50%',
keys: true,
vi: true,
mouse: true,
border: 'line',
scrollbar: {
ch: ' ',
track: {
bg: 'cyan'
},
style: {
inverse: true
}
},
style: {
item: {
hover: {
bg: 'blue'
}
},
selected: {
bg: 'blue',
bold: true
}
},
search: function(callback) {
prompt.input('Search:', '', function(err, value) {
if (err) return;
return callback(null, value);
});
}
});
var status = blessed.box({
parent: screen,
bottom: 0,
right: 0,
height: 1,
width: 'shrink',
style: {
bg: 'blue'
},
content: 'Select your piece of ANSI art (`/` to search).'
});
var loader = blessed.loading({
parent: screen,
top: 'center',
left: 'center',
height: 5,
align: 'center',
width: '50%',
tags: true,
hidden: true,
border: 'line'
});
var msg = blessed.message({
parent: screen,
top: 'center',
left: 'center',
height: 'shrink',
width: '50%',
align: 'center',
tags: true,
hidden: true,
border: 'line'
});
var prompt = blessed.prompt({
parent: screen,
top: 'center',
left: 'center',
height: 'shrink',
width: 'shrink',
keys: true,
vi: true,
mouse: true,
tags: true,
border: 'line',
hidden: true
});
list.setItems(Object.keys(map));
list.on('select', function(el, selected) {
if (list._.rendering) return;
var name = el.getText();
var url = map[name];
status.setContent(url);
list._.rendering = true;
loader.load('Loading...');
request({
uri: url,
encoding: null
}, function(err, res, body) {
list._.rendering = false;
loader.stop();
if (err) {
return msg.error(err.message);
}
if (!body) {
return msg.error('No body.');
}
return cp437ToUtf8(body, function(err, body) {
if (err) {
return msg.error(err.message);
}
if (process.argv[2] === '--debug') {
var filename = name.replace(/\//g, '.') + '.ans';
fs.writeFileSync(__dirname + '/' + filename, body);
}
// Remove text:
body = body.replace('Downloaded From P-80 International Information Systems 304-744-2253', '');
// Remove MCI codes:
body = body.replace(/%[A-Z0-9]{2}/g, '');
// ^A (SOH) seems to need to produce CRLF in some cases??
// body = body.replace(/\x01/g, '\r\n');
// Reset and write the art:
art.term.reset();
art.term.write(body);
art.term.cursorHidden = true;
screen.render();
if (process.argv[2] === '--debug' || process.argv[2] === '--save') {
takeScreenshot(name);
}
});
});
});
list.items.forEach(function(item, i) {
var text = item.getText();
item.setHover(map[text]);
});
list.focus();
list.enterSelected(0);
screen.key('h', function() {
list.toggle();
if (list.visible) list.focus();
});
screen.key('r', function() {
shuffle();
});
screen.key('S-s', function() {
takeScreenshot(list.ritems[list.selected]);
});
screen.key('s', function() {
slideshow();
});
screen.key('q', function() {
return process.exit(0);
});
screen.render();
/**
* Helpers
*/
// https://github.com/chjj/blessed/issues/127
// https://github.com/Mithgol/node-singlebyte
function cp437ToUtf8(buf, callback) {
try {
return callback(null, singlebyte.bufToStr(buf, 'cp437'));
} catch (e) {
return callback(e);
}
}
// Animating ANSI art doesn't work for screenshots.
var ANIMATING = [
'bbs/void3',
'holiday/xmasfwks',
'unsorted/diver',
'unsorted/mash-chp',
'unsorted/ryans47',
'unsorted/xmasfwks'
];
function takeScreenshot(name) {
var filename = name.replace(/\//g, '.') + '.ans.sgr';
var image;
// Animating art hangs terminal during screenshot as of right now.
if (~ANIMATING.indexOf(name)) {
image = blessed.element.prototype.screenshot.call(art,
0 - art.ileft, art.width - art.iright,
0 - art.itop, art.height - art.ibottom);
} else {
image = art.screenshot();
}
fs.writeFileSync(__dirname + '/' + filename, image);
msg.display('Screenshot taken.');
}
function slideshow() {
if (!screen._.slideshow) {
screen._.slideshow = setInterval(function slide() {
if (screen.lockKeys) return;
var i = (list.items.length - 1) * Math.random() | 0;
list.enterSelected(i);
return slide;
}(), 3000);
msg.display('Slideshow started.');
} else {
clearInterval(screen._.slideshow);
delete screen._.slideshow;
msg.display('Slideshow stopped.');
}
}
function shuffle() {
var items = Object.keys(map).sort(function(key) {
return Math.random() > 0.5 ? 1 : -1;
});
list.setItems(items);
screen.render();
msg.display('Shuffled items.');
}

View File

@ -0,0 +1,19 @@
{
"name": "ansi-viewer",
"description": "ANSI art viewer for node",
"author": "Christopher Jeffrey",
"version": "0.0.1",
"main": "./index.js",
"bin": "./index.js",
"preferGlobal": false,
"repository": "git://github.com/chjj/blessed.git",
"homepage": "https://github.com/chjj/blessed",
"bugs": { "url": "http://github.com/chjj/blessed/issues" },
"keywords": ["ansi", "art"],
"tags": ["ansi", "art"],
"dependencies": {
"blessed": ">=0.1.5",
"term.js": "0.0.4",
"request": "2.55.0"
}
}

View File

@ -0,0 +1,406 @@
/**
* node-singlebyte
*/
// The MIT License (MIT)
//
// Copyright (c) 2013, Sergey Sokoloff (aka Mithgol the Webmaster).
// https://github.com/Mithgol/node-singlebyte
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var extend = function(target) {
target = target || {};
Array.prototype.slice.call(arguments, 1).forEach(function(obj) {
Object.keys(obj || {}).forEach(function(key) {
target[key] = obj[key];
});
});
return target;
};
var singlebyte = function(){
/* jshint indent: false */
if(!( this instanceof singlebyte )){
return new singlebyte();
}
this.encodings = [];
// CP437
this.learnEncoding('cp437', this.extendASCII([
0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
0xFF, 0xD6, 0xDC, 0xA2, 0xA3, 0xA5, 0x20A7, 0x192,
0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
0xBF, 0x2310, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x3B1, 0x3B2, 0x393, 0x3C0, 0x3A3, 0x3C3, 0x3BC, 0x3C4,
0x3A6, 0x398, 0x3A9, 0x3B4, 0x221E, 0x3C6, 0x3B5, 0x2229,
0x2261, 0xB1, 0x2265, 0x2264, 0x2320, 0x2321, 0xF7, 0x2248,
0xB0, 0x2219, 0xB7, 0x221A, 0x207F, 0xB2, 0x25A0, 0xA0
]));
// CP850
this.learnEncoding('cp850', this.extendASCII([
0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
0xFF, 0xD6, 0xDC, 0xF8, 0xA3, 0xD8, 0xD7, 0x192,
0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
0xBF, 0xAE, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0xC1, 0xC2, 0xC0,
0xA9, 0x2563, 0x2551, 0x2557, 0x255D, 0xA2, 0xA5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0xE3, 0xC3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0xA4,
0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x131, 0xCD, 0xCE,
0xCF, 0x2518, 0x250C, 0x2588, 0x2584, 0xA6, 0xCC, 0x2580,
0xD3, 0xDF, 0xD4, 0xD2, 0xF5, 0xD5, 0xB5, 0xFE,
0xDE, 0xDA, 0xDB, 0xD9, 0xFD, 0xDD, 0xAF, 0xB4,
0xAD, 0xB1, 0x2017, 0xBE, 0xB6, 0xA7, 0xF7, 0xB8,
0xB0, 0xA8, 0xB7, 0xB9, 0xB3, 0xB2, 0x25A0, 0xA0
]));
// CP858
this.learnEncoding('cp858', this.extendASCII([
0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
0xFF, 0xD6, 0xDC, 0xF8, 0xA3, 0xD8, 0xD7, 0x192,
0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
0xBF, 0xAE, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0xC1, 0xC2, 0xC0,
0xA9, 0x2563, 0x2551, 0x2557, 0x255D, 0xA2, 0xA5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0xE3, 0xC3,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0xA4,
0xF0, 0xD0, 0xCA, 0xCB, 0xC8, 0x20AC, 0xCD, 0xCE,
0xCF, 0x2518, 0x250C, 0x2588, 0x2584, 0xA6, 0xCC, 0x2580,
0xD3, 0xDF, 0xD4, 0xD2, 0xF5, 0xD5, 0xB5, 0xFE,
0xDE, 0xDA, 0xDB, 0xD9, 0xFD, 0xDD, 0xAF, 0xB4,
0xAD, 0xB1, 0x2017, 0xBE, 0xB6, 0xA7, 0xF7, 0xB8,
0xB0, 0xA8, 0xB7, 0xB9, 0xB3, 0xB2, 0x25A0, 0xA0
]));
// CP808
this.learnEncoding('cp808', this.extendASCII([
0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417,
0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F,
0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427,
0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F,
0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437,
0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447,
0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F,
0x401, 0x451, 0x404, 0x454, 0x407, 0x457, 0x40E, 0x45E,
0xB0, 0x2219, 0xB7, 0x221A, 0x2116, 0x20AC, 0x25A0, 0xA0
]));
// CP866
this.learnEncoding('cp866', this.extendASCII([
0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417,
0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F,
0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427,
0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F,
0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437,
0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447,
0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F,
0x401, 0x451, 0x404, 0x454, 0x407, 0x457, 0x40E, 0x45E,
0xB0, 0x2219, 0xB7, 0x221A, 0x2116, 0xA4, 0x25A0, 0xA0
]));
// CP1125
this.learnEncoding('cp1125', this.extendASCII([
0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417,
0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E, 0x41F,
0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427,
0x428, 0x429, 0x42A, 0x42B, 0x42C, 0x42D, 0x42E, 0x42F,
0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437,
0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x43E, 0x43F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447,
0x448, 0x449, 0x44A, 0x44B, 0x44C, 0x44D, 0x44E, 0x44F,
0x401, 0x451, 0x490, 0x491, 0x404, 0x454, 0x406, 0x456,
0x407, 0x457, 0xB7, 0x221A, 0x2116, 0xA4, 0x25A0, 0xA0
]));
// KOI8-R
this.learnEncoding('koi8-r', this.extendASCII([
0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
0x2264, 0x2265, 0xA0, 0x2321, 0xB0, 0xB2, 0xB7, 0xF7,
0x2550, 0x2551, 0x2552, 0x451, 0x2553, 0x2554, 0x2555, 0x2556,
0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
0x255F, 0x2560, 0x2561, 0x401, 0x2562, 0x2563, 0x2564, 0x2565,
0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0xA9,
0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433,
0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x043E,
0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432,
0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A,
0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413,
0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E,
0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412,
0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A
]));
// KOI8-U
this.learnEncoding('koi8-u', this.extendASCII([
0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
0x2264, 0x2265, 0xA0, 0x2321, 0xB0, 0xB2, 0xB7, 0xF7,
0x2550, 0x2551, 0x2552, 0x451, 0x454, 0x2554, 0x456, 0x457,
0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x491, 0x255D, 0x255E,
0x255F, 0x2560, 0x2561, 0x401, 0x404, 0x2563, 0x406, 0x407,
0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x490, 0x256C, 0xA9,
0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433,
0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x043E,
0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432,
0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A,
0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413,
0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E,
0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412,
0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A
]));
// KOI8-RU
this.learnEncoding('koi8-ru', this.extendASCII([
0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524,
0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590,
0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
0x2264, 0x2265, 0xA0, 0x2321, 0xB0, 0xB2, 0xB7, 0xF7,
0x2550, 0x2551, 0x2552, 0x451, 0x454, 0x2554, 0x456, 0x457,
0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x491, 0x45E, 0x255E,
0x255F, 0x2560, 0x2561, 0x401, 0x404, 0x2563, 0x406, 0x407,
0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x490, 0x40E, 0xA9,
0x44E, 0x430, 0x431, 0x446, 0x434, 0x435, 0x444, 0x433,
0x445, 0x438, 0x439, 0x43A, 0x43B, 0x43C, 0x43D, 0x043E,
0x43F, 0x44F, 0x440, 0x441, 0x442, 0x443, 0x436, 0x432,
0x44C, 0x44B, 0x437, 0x448, 0x44D, 0x449, 0x447, 0x44A,
0x42E, 0x410, 0x411, 0x426, 0x414, 0x415, 0x424, 0x413,
0x425, 0x418, 0x419, 0x41A, 0x41B, 0x41C, 0x41D, 0x41E,
0x41F, 0x42F, 0x420, 0x421, 0x422, 0x423, 0x416, 0x412,
0x42C, 0x42B, 0x417, 0x428, 0x42D, 0x429, 0x427, 0x42A
]));
// LATIN-1 aka ISO 8859-1 (Western European)
this.learnEncoding('latin-1', this.extendASCII([
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
]));
// Windows-1252
this.learnEncoding('cp1252', this.extendASCII([
0x20AC, 0x81, 0x201A, 0x192, 0x201E, 0x2026, 0x2020, 0x2021,
0x2C6, 0x2030, 0x160, 0x2039, 0x152, 0x8D, 0x017D, 0x8F,
0x90, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x02DC, 0x2122, 0x161, 0x203A, 0x0153, 0x9D, 0x17E, 0x178,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
]));
};
singlebyte.prototype.isEncoding = function(encodingName){
if( Buffer.isEncoding(encodingName) ) return true;
for( var i = 0; i < this.encodings.length; i++ ){
if( this.encodings[i].name === encodingName ) return true;
}
return false;
};
singlebyte.prototype.learnEncoding = function(encodingName, encodingTable){
/*jshint bitwise: false */
if( Buffer.isEncoding(encodingName) ){
throw new Error(this.errors.BUFFER_ENCODING);
}
if( encodingTable.length !== 256 ){
throw new Error(this.errors.INVALID_TABLE_LENGTH);
}
var _this = this;
encodingTable = encodingTable.map(function(item){
var nextCode = item |0;
if( 0 > nextCode || nextCode > 0x10FFFF ){
throw new Error(_this.errors.OUT_OF_UNICODE);
}
return item;
});
if( this.isEncoding(encodingName) ){
for( var i = 0; i < this.encodings.length; i++ ){
if( this.encodings[i].name === encodingName ){
this.encodings[i].table = encodingTable;
return;
}
}
} else {
this.encodings.push({
name: encodingName,
table: encodingTable
});
}
};
singlebyte.prototype.getEncodingTable = function(encodingName){
for( var i = 0; i < this.encodings.length; i++ ){
if( this.encodings[i].name === encodingName ){
return this.encodings[i].table;
}
}
return null;
};
singlebyte.prototype.extendASCII = function(extensionTable){
if( extensionTable.length !== 128 ){
throw new Error(this.errors.INVALID_EXTENSION);
}
var output = [];
for( var i = 0; i < 128; i++ ) output.push(i);
return output.concat(extensionTable);
};
singlebyte.prototype.bufToStr = function(buf, encoding, start, end){
/* jshint bitwise: false */
if(!( Buffer.isBuffer(buf) )){
throw new Error(this.errors.NOT_A_BUFFER);
}
if( Buffer.isEncoding(encoding) ){
return buf.toString(encoding, start, end);
}
var table = this.getEncodingTable(encoding);
if( table === null ) throw new Error(this.errors.UNKNOWN_ENCODING);
if( typeof end === 'undefined' ) end = buf.length;
if( typeof start === 'undefined' ) start = 0;
var output = '';
var sourceValue;
for( var i = start; i < end; i++ ){
sourceValue = table[ buf[i] ];
if( sourceValue <= 0xFFFF ){
output += String.fromCharCode(sourceValue);
} else if( 0x10000 <= sourceValue && sourceValue <= 0x10FFFF ){
sourceValue -= 0x10000;
output += String.fromCharCode( 0xD800 + (sourceValue >> 10) );
output += String.fromCharCode( 0xDC00 + (sourceValue & 0x3FF) );
} else throw new Error(this.errors.OUT_OF_UNICODE);
}
return output;
};
var strToBufDefaults = {
defaultCode: 0x3F // '?'
};
singlebyte.prototype.strToBuf = function(str, encoding, encodingOptions){
if( Buffer.isEncoding(encoding) ){
return new Buffer(str, encoding);
}
str = '' + str;
var options = extend({}, strToBufDefaults, encodingOptions);
var table = this.getEncodingTable(encoding);
if( table === null ) throw new Error(this.errors.UNKNOWN_ENCODING);
var output = [];
for( var i = 0; i < str.length; i++ ){
var charUnicode;
var thisCharCode = str.charCodeAt(i);
if( 0xD800 <= thisCharCode && thisCharCode <= 0xDBFF &&
i+1 < str.length
){
var nextCharCode = str.charCodeAt(i+1);
if( 0xDC00 <= nextCharCode && nextCharCode <= 0xDFFF ){
charUnicode = 0x10000 + (thisCharCode - 0xD800)*0x400 +
(nextCharCode - 0xDC00);
i++;
} else {
charUnicode = thisCharCode;
}
} else {
charUnicode = thisCharCode;
}
var codeFoundIndex = table.indexOf(charUnicode);
if( codeFoundIndex < 0 ){
output.push(options.defaultCode);
} else {
output.push(codeFoundIndex);
}
}
return new Buffer(output);
};
singlebyte.prototype.errors = {
NOT_A_BUFFER : 'The given source is not a buffer!',
UNKNOWN_ENCODING : 'The given encoding is not defined!',
INVALID_TABLE_LENGTH : 'The encoding table must have 256 elements!',
INVALID_EXTENSION : 'The ASCII extension table must have 128 elements!',
BUFFER_ENCODING : "Cannot redefine a Node's encoding!",
OUT_OF_UNICODE : "An encoding table's element is greater than 0x10FFFF!"
};
module.exports = singlebyte();

99
example/blessed-telnet.js Executable file
View File

@ -0,0 +1,99 @@
#!/usr/bin/env node
/**
* blessed-telnet.js
* https://github.com/chjj/blessed
* Copyright (c) 2013-2015, Christopher Jeffrey (MIT License)
* A blessed telnet server.
* See: https://github.com/TooTallNate/node-telnet
*/
process.title = 'blessed-telnet';
var fs = require('fs');
var path = require('path');
var blessed = require('blessed');
var telnet = require('telnet2');
var server = telnet({ tty: true }, function(client) {
client.on('debug', function(msg) {
console.error(msg);
});
client.on('term', function(terminal) {
screen.terminal = terminal;
screen.render();
});
client.on('size', function(width, height) {
client.columns = width;
client.rows = height;
client.emit('resize');
});
var screen = blessed.screen({
smartCSR: true,
input: client,
output: client,
terminal: 'xterm-256color',
fullUnicode: true
});
client.on('close', function() {
if (!screen.destroyed) {
screen.destroy();
}
});
screen.on('destroy', function() {
if (client.writable) {
client.destroy();
}
});
if (test === 'widget-simple') {
return simpleTest(screen);
}
loadTest(screen, test);
});
function simpleTest(screen) {
screen.data.main = blessed.box({
parent: screen,
width: '80%',
height: '90%',
border: 'line',
content: 'Welcome to my server. Here is your own private session.',
style: {
bg: 'red'
}
});
screen.key('i', function() {
screen.data.main.style.bg = 'blue';
screen.render();
});
screen.key(['C-c', 'q'], function(ch, key) {
screen.destroy();
});
screen.render();
}
var test = process.argv[2] || path.resolve(__dirname, '../test/widget-shadow.js');
if (~test.indexOf('widget-png.js')) process.argv.length = 2;
test = path.resolve(process.cwd(), test);
function loadTest(screen, name) {
var Screen = blessed.screen;
blessed.screen = function() { return screen; };
var path = require.resolve(name);
delete require.cache[path];
require(name);
blessed.screen = Screen;
}
server.listen(2300);
console.log('Listening on 2300...');

77
example/index.js Normal file
View File

@ -0,0 +1,77 @@
/**
* Example Program for Blessed
* Copyright (c) 2013, Christopher Jeffrey (MIT License).
* https://github.com/chjj/blessed
*/
var blessed = require('../')
, program = blessed.program();
process.title = 'blessed';
program.on('keypress', function(ch, key) {
if (key.name === 'q') {
program.clear();
program.disableMouse();
program.showCursor();
program.normalBuffer();
process.exit(0);
}
});
program.on('mouse', function(data) {
if (data.action === 'mouseup') return;
program.move(1, program.rows);
program.eraseInLine('right');
if (data.action === 'wheelup') {
program.write('Mouse wheel up at: ' + data.x + ', ' + data.y);
} else if (data.action === 'wheeldown') {
program.write('Mouse wheel down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'left') {
program.write('Left button down at: ' + data.x + ', ' + data.y);
} else if (data.action === 'mousedown' && data.button === 'right') {
program.write('Right button down at: ' + data.x + ', ' + data.y);
} else {
program.write('Mouse at: ' + data.x + ', ' + data.y);
}
program.move(data.x, data.y);
program.bg('red');
program.write(' ');
program.bg('!red');
});
program.on('focus', function() {
program.move(1, program.rows);
program.write('Gained focus.');
});
program.on('blur', function() {
program.move(1, program.rows);
program.write('Lost focus.');
});
program.alternateBuffer();
program.enableMouse();
program.hideCursor();
program.clear();
program.move(1, 1);
program.bg('black');
program.write('Hello world', 'blue fg');
program.setx((program.cols / 2 | 0) - 4);
program.down(5);
program.write('Hi again!');
program.bg('!black');
program.feed();
program.getCursor(function(err, data) {
if (!err) {
program.write('Cursor is at: ' + data.x + ', ' + data.y + '.');
program.feed();
}
program.charset('SCLD');
program.write('abcdefghijklmnopqrstuvwxyz0123456789');
program.charset('US');
program.setx(1);
});

142
example/multiplex.js Executable file
View File

@ -0,0 +1,142 @@
#!/usr/bin/env node
/**
* multiplex.js
* https://github.com/chjj/blessed
* Copyright (c) 2013-2015, Christopher Jeffrey (MIT License)
* A terminal multiplexer created by blessed.
*/
process.title = 'multiplex.js';
var blessed = require('blessed')
, screen;
screen = blessed.screen({
smartCSR: true,
log: process.env.HOME + '/blessed-terminal.log',
fullUnicode: true,
dockBorders: true,
ignoreDockContrast: true
});
var topleft = blessed.terminal({
parent: screen,
cursor: 'line',
cursorBlink: true,
screenKeys: false,
label: ' multiplex.js ',
left: 0,
top: 0,
width: '50%',
height: '50%',
border: 'line',
style: {
fg: 'default',
bg: 'default',
focus: {
border: {
fg: 'green'
}
}
}
});
topleft.pty.on('data', function(data) {
screen.log(JSON.stringify(data));
});
var topright = blessed.terminal({
parent: screen,
cursor: 'block',
cursorBlink: true,
screenKeys: false,
label: ' multiplex.js ',
left: '50%-1',
top: 0,
width: '50%+1',
height: '50%',
border: 'line',
style: {
fg: 'red',
bg: 'black',
focus: {
border: {
fg: 'green'
}
}
}
});
var bottomleft = blessed.terminal({
parent: screen,
cursor: 'block',
cursorBlink: true,
screenKeys: false,
label: ' multiplex.js ',
left: 0,
top: '50%-1',
width: '50%',
height: '50%+1',
border: 'line',
style: {
fg: 'default',
bg: 'default',
focus: {
border: {
fg: 'green'
}
}
}
});
var bottomright = blessed.terminal({
parent: screen,
cursor: 'block',
cursorBlink: true,
screenKeys: false,
label: ' multiplex.js ',
left: '50%-1',
top: '50%-1',
width: '50%+1',
height: '50%+1',
border: 'line',
style: {
fg: 'default',
bg: 'default',
focus: {
border: {
fg: 'green'
}
}
}
});
[topleft, topright, bottomleft, bottomright].forEach(function(term) {
term.enableDrag(function(mouse) {
return !!mouse.ctrl;
});
term.on('title', function(title) {
screen.title = title;
term.setLabel(' ' + title + ' ');
screen.render();
});
term.on('click', term.focus.bind(term));
});
topleft.focus();
screen.key('C-q', function() {
topleft.kill();
topright.kill();
bottomleft.kill();
bottomright.kill();
return screen.destroy();
});
screen.program.key('S-tab', function() {
screen.focusNext();
screen.render();
});
screen.render();

448
example/ping Executable file
View File

@ -0,0 +1,448 @@
#!/usr/bin/env node
/**
* ping
* https://github.com/chjj/blessed
* Copyright (c) 2013, Christopher Jeffrey (MIT License)
* Online (ping)pong in your terminal.
*/
// Example Usage:
// Server: $ ./example/ping 3000
// Client: $ ./example/ping 127.0.0.1 3000
// Demo: $ ./example/ping
process.title = 'ping';
if (/^(-h|--help|-\?)$/.test(process.argv[2])) {
console.log('node-ping');
console.log('Example Usage:');
console.log('Server: $ node-ping 3000');
console.log('Client: $ node-ping 127.0.0.1 3000');
console.log('Demo: $ node-ping');
return process.exit(0);
}
var blessed = require('blessed')
, nssocket;
try {
nssocket = require('nssocket');
} catch (e) {
;
}
var server
, socket;
/**
* Screen Layout
*/
var screen = blessed.screen();
var table = blessed.box({
left: 0,
top: 0,
width: screen.width,
height: screen.height
});
var ball = blessed.box({
width: 1,
height: 1,
bg: 'white',
top: 0,
left: 0
});
var lpaddle = blessed.box({
width: 1,
height: 3,
bg: 'yellow',
top: 0,
left: 0
});
var rpaddle = blessed.box({
width: 1,
height: 3,
bg: 'yellow',
top: 0,
right: 0
});
var score = blessed.box({
top: 0,
left: 4,
height: 3,
width: 'shrink',
border: {
type: 'line'
},
//align: 'center',
style: {
bold: true
},
tags: true
});
score.lwins = 0;
score.rwins = 0;
var net = blessed.box({
width: 1,
height: '100%',
bg: 'yellow',
top: 0,
left: 'center'
});
var message = blessed.box({
width: '50%',
height: 3,
border: {
type: 'line'
},
top: 'center',
left: 'center'
});
var text = blessed.box({
top: 'center',
left: 1,
right: 1,
height: 1,
align: 'center',
content: 'Waiting for players to connect...'
});
message.append(text);
screen.append(table);
table.append(score);
table.append(lpaddle);
table.append(rpaddle);
table.append(net);
table.append(ball);
table.append(message);
screen.on('resize', function() {
table.width = screen.width;
table.height = screen.height;
[ball, lpaddle, rpaddle].forEach(function(el) {
if (el.rbottom < 0) el.rtop = table.height - 1 - el.height;
if (el.rright < 0) el.rleft = table.width - 1;
});
screen.render();
sync();
});
/**
* Options
*/
ball.speed = 2;
ball.unpredictable = true;
lpaddle.speed = 2;
rpaddle.speed = 2;
/**
* Game
*/
function sync() {
if (!socket) return;
socket.send(['update'], {
table: { width: table.width, height: table.height },
lpaddle: { rleft: lpaddle.rleft, rtop: lpaddle.rtop, speed: lpaddle.speed },
rpaddle: { rleft: rpaddle.rleft, rtop: rpaddle.rtop, speed: rpaddle.speed },
score: { lwins: score.lwins, rwins: score.rwins }
});
}
function reset() {
text.setContent('Waiting for players to connect...');
message.hide();
ball.moving = true;
ball.direction = 'right';
ball.angle = 'down';
ball.rtop = 1;
ball.rleft = 1;
if ((score.lwins + score.rwins) % 2 !== 0) {
ball.direction = 'left';
ball.rleft = table.width - 1;
}
lpaddle.rtop = 0;
rpaddle.rtop = 0;
score.setContent('{green-fg}Score:{/} ' + score.lwins + ' | ' + score.rwins);
rpaddle.movable = true;
screen.render();
if (server && socket) {
socket.send(['reset']);
}
}
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function startGame() {
reset();
if (startGame._bound) return;
startGame._bound = true;
screen.on('keypress', function(ch, key) {
if (!ball.moving) return;
if (key.name === 'up' || key.name === 'k') {
if (socket) socket.send(['up']);
if (lpaddle.rtop > 0) lpaddle.rtop -= lpaddle.speed;
if (!socket) if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
if (lpaddle.rtop < 0) lpaddle.rtop = 0;
if (rpaddle.rtop < 0) rpaddle.rtop = 0;
screen.render();
} else if (key.name === 'down' || key.name === 'j') {
if (socket) socket.send(['down']);
if (lpaddle.rbottom > 0) lpaddle.rtop += lpaddle.speed;
if (!socket) if (rpaddle.rbottom > 0) rpaddle.rtop += rpaddle.speed;
if (lpaddle.rbottom < 0) lpaddle.rtop = table.height - lpaddle.height - 1;
if (rpaddle.rbottom < 0) rpaddle.rtop = table.height - rpaddle.height - 1;
screen.render();
}
});
setInterval(function() {
if (!ball.moving) return;
if (ball.direction === 'right') {
if (ball.rright > 1) {
ball.rleft += ball.speed;
} else {
if (ball.rtop >= rpaddle.rtop && ball.rtop <= rpaddle.rtop + rpaddle.height) {
ball.direction = 'left';
ball.rleft -= ball.speed;
ball.rleft -= rand(0, 3);
if (ball.angle === 'down') ball.rtop += rand(0, 3);
else if (ball.angle === 'up') ball.rtop -= rand(0, 3);
} else {
// Right loses
score.lwins++;
ball.rleft = table.width - 1;
if (socket) socket.send(['lose']);
ball.moving = false;
text.setContent('Right player loses!');
message.show();
setTimeout(reset, 3000);
screen.render();
return;
}
}
if (ball.rright < 1) ball.rleft = table.width - 2;
} else if (ball.direction === 'left') {
if (ball.rleft > 1) {
ball.rleft -= ball.speed;
} else {
if (ball.rtop >= lpaddle.rtop && ball.rtop <= lpaddle.rtop + lpaddle.height) {
ball.direction = 'right';
ball.rleft += ball.speed;
ball.rleft += rand(0, 3);
if (ball.angle === 'down') ball.rtop += rand(0, 3);
else if (ball.angle === 'up') ball.rtop -= rand(0, 3);
} else {
// Left loses
score.rwins++;
ball.rleft = 0;
if (socket) socket.send(['win']);
ball.moving = false;
text.setContent('Left player loses!');
message.show();
setTimeout(reset, 3000);
screen.render();
return;
}
}
if (ball.rleft < 1) ball.rleft = 1;
}
if (ball.angle === 'down') {
if (ball.rbottom > 0) {
ball.rtop++;
if (ball.unpredictable) ball.rtop += rand(0, 3);
} else {
ball.angle = 'up';
ball.rtop--;
}
} else if (ball.angle === 'up') {
if (ball.rtop > 0) {
ball.rtop--;
if (ball.unpredictable) ball.rtop -= rand(0, 3);
} else {
ball.angle = 'down';
ball.rtop++;
}
}
if (ball.rtop < 0) ball.rtop = 0;
if (ball.rbottom < 0) ball.rtop = table.height - 1;
if (socket) socket.send(['ball'], { rleft: ball.rleft, rtop: ball.rtop });
screen.render();
}, 100);
}
function startServer() {
server = nssocket.createServer({}, function(socket_) {
socket = socket_;
sync();
socket.data(['up'], function() {
if (!ball.moving) return;
if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
screen.render();
});
socket.data(['down'], function() {
if (!ball.moving) return;
if (rpaddle.rtop < table.height - 1) rpaddle.rtop += rpaddle.speed;
screen.render();
});
socket.on('error', function() {
socket = null;
reset();
ball.moving = false;
message.show();
screen.render();
});
startGame();
});
server.listen(+process.argv[2]);
}
function startClient() {
var socket = new nssocket.NsSocket({
reconnect: true,
maxRetries: Infinity,
retryInterval: 5000
});
socket.connect(+process.argv[3], process.argv[2]);
screen.on('keypress', function(ch, key) {
if (!rpaddle.movable) return;
if (key.name === 'up' || key.name === 'k') {
socket.send(['up']);
if (rpaddle.rtop > 0) rpaddle.rtop -= rpaddle.speed;
if (rpaddle.rtop < 0) rpaddle.rtop = 0;
screen.render();
} else if (key.name === 'down' || key.name === 'j') {
socket.send(['down']);
if (rpaddle.rbottom > 0) rpaddle.rtop += rpaddle.speed;
if (rpaddle.rbottom < 0) rpaddle.rtop = table.height - rpaddle.height - 1;
screen.render();
}
});
socket.data(['up'], function() {
if (lpaddle.rtop > 0) lpaddle.rtop -= lpaddle.speed;
screen.render();
});
socket.data(['down'], function() {
if (lpaddle.rtop < table.height - 1) lpaddle.rtop += lpaddle.speed;
screen.render();
});
socket.data(['ball'], function(data) {
ball.rleft = data.rleft;
ball.rtop = data.rtop;
screen.render();
});
socket.data(['update'], function(data) {
if (data.lpaddle) {
lpaddle.rleft = data.lpaddle.rleft;
lpaddle.rtop = data.lpaddle.rtop;
lpaddle.speed = data.lpaddle.speed;
}
if (data.rpaddle) {
rpaddle.rleft = data.rpaddle.rleft;
rpaddle.rtop = data.rpaddle.rtop;
rpaddle.speed = data.rpaddle.speed;
}
if (data.ball) {
ball.moving = data.ball.moving;
ball.rleft = data.ball.rleft;
ball.rtop = data.ball.rtop;
}
if (data.table) {
table.height = data.table.height;
table.width = data.table.width;
}
if (data.score) {
score.lwins = data.score.lwins;
score.rwins = data.score.rwins;
}
screen.render();
});
socket.data(['win'], function() {
rpaddle.movable = false;
score.rwins++;
text.setContent('Left player loses!');
message.show();
screen.render();
});
socket.data(['lose'], function() {
rpaddle.movable = false;
score.lwins++;
text.setContent('Right player loses!');
message.show();
screen.render();
});
socket.data(['reset'], reset);
reset();
}
/**
* Main
*/
function main() {
screen.on('keypress', function(ch, key) {
if (key.name === 'q' || key.name === 'escape') {
return process.exit(0);
}
});
screen.render();
// Demo Mode / Single Player
if (!nssocket || !process.argv[2]) return startGame();
// Server Mode
if (!process.argv[3]) return startServer();
// Client Mode
if (process.argv[2] && process.argv[3]) return startClient();
}
/**
* Execute
*/
main();

87
example/simple-form.js Normal file
View File

@ -0,0 +1,87 @@
var blessed = require('blessed')
, screen = blessed.screen();
var form = blessed.form({
parent: screen,
keys: true,
left: 0,
top: 0,
width: 30,
height: 4,
bg: 'green',
content: 'Submit or cancel?'
});
var submit = blessed.button({
parent: form,
mouse: true,
keys: true,
shrink: true,
padding: {
left: 1,
right: 1
},
left: 10,
top: 2,
shrink: true,
name: 'submit',
content: 'submit',
style: {
bg: 'blue',
focus: {
bg: 'red'
},
hover: {
bg: 'red'
}
}
});
var cancel = blessed.button({
parent: form,
mouse: true,
keys: true,
shrink: true,
padding: {
left: 1,
right: 1
},
left: 20,
top: 2,
shrink: true,
name: 'cancel',
content: 'cancel',
style: {
bg: 'blue',
focus: {
bg: 'red'
},
hover: {
bg: 'red'
}
}
});
submit.on('press', function() {
form.submit();
});
cancel.on('press', function() {
form.reset();
});
form.on('submit', function(data) {
form.setContent('Submitted.');
screen.render();
});
form.on('reset', function(data) {
form.setContent('Canceled.');
screen.render();
});
screen.key('q', function() {
process.exit(0);
});
screen.render();

1052
example/time.js Executable file

File diff suppressed because it is too large Load Diff

55
example/widget.js Normal file
View File

@ -0,0 +1,55 @@
var blessed = require('../');
// Create a screen object.
var screen = blessed.screen();
// Create a box perfectly centered horizontally and vertically.
var box = blessed.box({
top: 'center',
left: 'center',
width: '50%',
height: '50%',
content: 'Hello {bold}world{/bold}!',
tags: true,
border: {
type: 'line'
},
style: {
fg: 'white',
bg: 'magenta',
border: {
fg: '#ffffff'
},
hover: {
bg: 'green'
}
}
});
// Append our box to the screen.
screen.append(box);
// If our box is clicked, change the content.
box.on('click', function(data) {
box.setContent('{center}Some different {red-fg}content{/red-fg}.{/center}');
screen.render();
});
// If box is focused, handle `enter` and give us some more content.
box.key('enter', function() {
box.setContent('{right}Even different {black-fg}content{/black-fg}.{/right}\n');
box.setLine(1, 'bar');
box.insertLine(1, 'foo');
screen.render();
});
// Quit on Escape, q, or Control-C.
screen.key(['escape', 'q', 'C-c'], function(ch, key) {
return process.exit(0);
});
// Focus our element.
box.focus();
// Render the screen.
screen.render();

BIN
img/ansi-viewer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
img/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
img/v0.1.0-1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

BIN
img/v0.1.0-2.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

BIN
img/v0.1.0-3.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
img/v0.1.0-4.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

BIN
img/v0.1.0.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

View File

@ -1 +1 @@
module.exports = require('./lib/program');
module.exports = require('./lib/blessed');

526
lib/alias.js Normal file
View File

@ -0,0 +1,526 @@
/**
* alias.js - terminfo/cap aliases for blessed.
* https://github.com/chjj/blessed
* Taken from terminfo(5) man page.
*/
/* jshint maxlen: 300 */
// jscs:disable maximumLineLength
// jscs:disable
var alias = exports;
// These are the boolean capabilities:
alias.bools = {
// Variable Cap- TCap Description
// Booleans name Code
'auto_left_margin': ['bw', 'bw'], // cub1 wraps from col umn 0 to last column
'auto_right_margin': ['am', 'am'], // terminal has auto matic margins
'back_color_erase': ['bce', 'ut'], // screen erased with background color
'can_change': ['ccc', 'cc'], // terminal can re- define existing col ors
'ceol_standout_glitch': ['xhp', 'xs'], // standout not erased by overwriting (hp)
'col_addr_glitch': ['xhpa', 'YA'], // only positive motion for hpa/mhpa caps
'cpi_changes_res': ['cpix', 'YF'], // changing character pitch changes reso lution
'cr_cancels_micro_mode': ['crxm', 'YB'], // using cr turns off micro mode
'dest_tabs_magic_smso': ['xt', 'xt'], // tabs destructive, magic so char (t1061)
'eat_newline_glitch': ['xenl', 'xn'], // newline ignored after 80 cols (con cept)
'erase_overstrike': ['eo', 'eo'], // can erase over strikes with a blank
'generic_type': ['gn', 'gn'], // generic line type
'hard_copy': ['hc', 'hc'], // hardcopy terminal
'hard_cursor': ['chts', 'HC'], // cursor is hard to see
'has_meta_key': ['km', 'km'], // Has a meta key (i.e., sets 8th-bit)
'has_print_wheel': ['daisy', 'YC'], // printer needs opera tor to change char acter set
'has_status_line': ['hs', 'hs'], // has extra status line
'hue_lightness_saturation': ['hls', 'hl'], // terminal uses only HLS color notation (Tektronix)
'insert_null_glitch': ['in', 'in'], // insert mode distin guishes nulls
'lpi_changes_res': ['lpix', 'YG'], // changing line pitch changes resolution
'memory_above': ['da', 'da'], // display may be retained above the screen
'memory_below': ['db', 'db'], // display may be retained below the screen
'move_insert_mode': ['mir', 'mi'], // safe to move while in insert mode
'move_standout_mode': ['msgr', 'ms'], // safe to move while in standout mode
'needs_xon_xoff': ['nxon', 'nx'], // padding will not work, xon/xoff required
'no_esc_ctlc': ['xsb', 'xb'], // beehive (f1=escape, f2=ctrl C)
'no_pad_char': ['npc', 'NP'], // pad character does not exist
'non_dest_scroll_region': ['ndscr', 'ND'], // scrolling region is non-destructive
'non_rev_rmcup': ['nrrmc', 'NR'], // smcup does not reverse rmcup
'over_strike': ['os', 'os'], // terminal can over strike
'prtr_silent': ['mc5i', '5i'], // printer will not echo on screen
'row_addr_glitch': ['xvpa', 'YD'], // only positive motion for vpa/mvpa caps
'semi_auto_right_margin': ['sam', 'YE'], // printing in last column causes cr
'status_line_esc_ok': ['eslok', 'es'], // escape can be used on the status line
'tilde_glitch': ['hz', 'hz'], // cannot print ~'s (hazeltine)
'transparent_underline': ['ul', 'ul'], // underline character overstrikes
'xon_xoff': ['xon', 'xo'] // terminal uses xon/xoff handshaking
};
// These are the numeric capabilities:
alias.numbers = {
// Variable Cap- TCap Description
// Numeric name Code
'columns': ['cols', 'co'], // number of columns in a line
'init_tabs': ['it', 'it'], // tabs initially every # spaces
'label_height': ['lh', 'lh'], // rows in each label
'label_width': ['lw', 'lw'], // columns in each label
'lines': ['lines', 'li'], // number of lines on screen or page
'lines_of_memory': ['lm', 'lm'], // lines of memory if > line. 0 means varies
'magic_cookie_glitch': ['xmc', 'sg'], // number of blank characters left by smso or rmso
'max_attributes': ['ma', 'ma'], // maximum combined attributes terminal can handle
'max_colors': ['colors', 'Co'], // maximum number of colors on screen
'max_pairs': ['pairs', 'pa'], // maximum number of color-pairs on the screen
'maximum_windows': ['wnum', 'MW'], // maximum number of defineable windows
'no_color_video': ['ncv', 'NC'], // video attributes that cannot be used with colors
'num_labels': ['nlab', 'Nl'], // number of labels on screen
'padding_baud_rate': ['pb', 'pb'], // lowest baud rate where padding needed
'virtual_terminal': ['vt', 'vt'], // virtual terminal number (CB/unix)
'width_status_line': ['wsl', 'ws'], // number of columns in status line
// The following numeric capabilities are present in the SVr4.0 term structure, but are not yet documented in the man page. They came in with
// SVr4's printer support.
// Variable Cap- TCap Description
// Numeric name Code
'bit_image_entwining': ['bitwin', 'Yo'], // number of passes for each bit-image row
'bit_image_type': ['bitype', 'Yp'], // type of bit-image device
'buffer_capacity': ['bufsz', 'Ya'], // numbers of bytes buffered before printing
'buttons': ['btns', 'BT'], // number of buttons on mouse
'dot_horz_spacing': ['spinh', 'Yc'], // spacing of dots hor izontally in dots per inch
'dot_vert_spacing': ['spinv', 'Yb'], // spacing of pins ver tically in pins per inch
'max_micro_address': ['maddr', 'Yd'], // maximum value in micro_..._address
'max_micro_jump': ['mjump', 'Ye'], // maximum value in parm_..._micro
'micro_col_size': ['mcs', 'Yf'], // character step size when in micro mode
'micro_line_size': ['mls', 'Yg'], // line step size when in micro mode
'number_of_pins': ['npins', 'Yh'], // numbers of pins in print-head
'output_res_char': ['orc', 'Yi'], // horizontal resolu tion in units per line
'output_res_horz_inch': ['orhi', 'Yk'], // horizontal resolu tion in units per inch
'output_res_line': ['orl', 'Yj'], // vertical resolution in units per line
'output_res_vert_inch': ['orvi', 'Yl'], // vertical resolution in units per inch
'print_rate': ['cps', 'Ym'], // print rate in char acters per second
'wide_char_size': ['widcs', 'Yn'] // character step size when in double wide mode
};
// These are the string capabilities:
alias.strings = {
// Variable Cap- TCap Description
// String name Code
'acs_chars': ['acsc', 'ac'], // graphics charset pairs, based on vt100
'back_tab': ['cbt', 'bt'], // back tab (P)
'bell': ['bel', 'bl'], // audible signal (bell) (P)
'carriage_return': ['cr', 'cr'], // carriage return (P*) (P*)
'change_char_pitch': ['cpi', 'ZA'], // Change number of characters per inch to #1
'change_line_pitch': ['lpi', 'ZB'], // Change number of lines per inch to #1
'change_res_horz': ['chr', 'ZC'], // Change horizontal resolution to #1
'change_res_vert': ['cvr', 'ZD'], // Change vertical res olution to #1
'change_scroll_region': ['csr', 'cs'], // change region to line #1 to line #2 (P)
'char_padding': ['rmp', 'rP'], // like ip but when in insert mode
'clear_all_tabs': ['tbc', 'ct'], // clear all tab stops (P)
'clear_margins': ['mgc', 'MC'], // clear right and left soft margins
'clear_screen': ['clear', 'cl'], // clear screen and home cursor (P*)
'clr_bol': ['el1', 'cb'], // Clear to beginning of line
'clr_eol': ['el', 'ce'], // clear to end of line (P)
'clr_eos': ['ed', 'cd'], // clear to end of screen (P*)
'column_address': ['hpa', 'ch'], // horizontal position #1, absolute (P)
'command_character': ['cmdch', 'CC'], // terminal settable cmd character in prototype !?
'create_window': ['cwin', 'CW'], // define a window #1 from #2,#3 to #4,#5
'cursor_address': ['cup', 'cm'], // move to row #1 col umns #2
'cursor_down': ['cud1', 'do'], // down one line
'cursor_home': ['home', 'ho'], // home cursor (if no cup)
'cursor_invisible': ['civis', 'vi'], // make cursor invisi ble
'cursor_left': ['cub1', 'le'], // move left one space
'cursor_mem_address': ['mrcup', 'CM'], // memory relative cur sor addressing, move to row #1 columns #2
'cursor_normal': ['cnorm', 've'], // make cursor appear normal (undo civis/cvvis)
'cursor_right': ['cuf1', 'nd'], // non-destructive space (move right one space)
'cursor_to_ll': ['ll', 'll'], // last line, first column (if no cup)
'cursor_up': ['cuu1', 'up'], // up one line
'cursor_visible': ['cvvis', 'vs'], // make cursor very visible
'define_char': ['defc', 'ZE'], // Define a character #1, #2 dots wide, descender #3
'delete_character': ['dch1', 'dc'], // delete character (P*)
'delete_line': ['dl1', 'dl'], // delete line (P*)
'dial_phone': ['dial', 'DI'], // dial number #1
'dis_status_line': ['dsl', 'ds'], // disable status line
'display_clock': ['dclk', 'DK'], // display clock
'down_half_line': ['hd', 'hd'], // half a line down
'ena_acs': ['enacs', 'eA'], // enable alternate char set
'enter_alt_charset_mode': ['smacs', 'as'], // start alternate character set (P)
'enter_am_mode': ['smam', 'SA'], // turn on automatic margins
'enter_blink_mode': ['blink', 'mb'], // turn on blinking
'enter_bold_mode': ['bold', 'md'], // turn on bold (extra bright) mode
'enter_ca_mode': ['smcup', 'ti'], // string to start pro grams using cup
'enter_delete_mode': ['smdc', 'dm'], // enter delete mode
'enter_dim_mode': ['dim', 'mh'], // turn on half-bright mode
'enter_doublewide_mode': ['swidm', 'ZF'], // Enter double-wide mode
'enter_draft_quality': ['sdrfq', 'ZG'], // Enter draft-quality mode
'enter_insert_mode': ['smir', 'im'], // enter insert mode
'enter_italics_mode': ['sitm', 'ZH'], // Enter italic mode
'enter_leftward_mode': ['slm', 'ZI'], // Start leftward car riage motion
'enter_micro_mode': ['smicm', 'ZJ'], // Start micro-motion mode
'enter_near_letter_quality': ['snlq', 'ZK'], // Enter NLQ mode
'enter_normal_quality': ['snrmq', 'ZL'], // Enter normal-quality mode
'enter_protected_mode': ['prot', 'mp'], // turn on protected mode
'enter_reverse_mode': ['rev', 'mr'], // turn on reverse video mode
'enter_secure_mode': ['invis', 'mk'], // turn on blank mode (characters invisi ble)
'enter_shadow_mode': ['sshm', 'ZM'], // Enter shadow-print mode
'enter_standout_mode': ['smso', 'so'], // begin standout mode
'enter_subscript_mode': ['ssubm', 'ZN'], // Enter subscript mode
'enter_superscript_mode': ['ssupm', 'ZO'], // Enter superscript mode
'enter_underline_mode': ['smul', 'us'], // begin underline mode
'enter_upward_mode': ['sum', 'ZP'], // Start upward car riage motion
'enter_xon_mode': ['smxon', 'SX'], // turn on xon/xoff handshaking
'erase_chars': ['ech', 'ec'], // erase #1 characters (P)
'exit_alt_charset_mode': ['rmacs', 'ae'], // end alternate char acter set (P)
'exit_am_mode': ['rmam', 'RA'], // turn off automatic margins
'exit_attribute_mode': ['sgr0', 'me'], // turn off all attributes
'exit_ca_mode': ['rmcup', 'te'], // strings to end pro grams using cup
'exit_delete_mode': ['rmdc', 'ed'], // end delete mode
'exit_doublewide_mode': ['rwidm', 'ZQ'], // End double-wide mode
'exit_insert_mode': ['rmir', 'ei'], // exit insert mode
'exit_italics_mode': ['ritm', 'ZR'], // End italic mode
'exit_leftward_mode': ['rlm', 'ZS'], // End left-motion mode
'exit_micro_mode': ['rmicm', 'ZT'], // End micro-motion mode
'exit_shadow_mode': ['rshm', 'ZU'], // End shadow-print mode
'exit_standout_mode': ['rmso', 'se'], // exit standout mode
'exit_subscript_mode': ['rsubm', 'ZV'], // End subscript mode
'exit_superscript_mode': ['rsupm', 'ZW'], // End superscript mode
'exit_underline_mode': ['rmul', 'ue'], // exit underline mode
'exit_upward_mode': ['rum', 'ZX'], // End reverse charac ter motion
'exit_xon_mode': ['rmxon', 'RX'], // turn off xon/xoff handshaking
'fixed_pause': ['pause', 'PA'], // pause for 2-3 sec onds
'flash_hook': ['hook', 'fh'], // flash switch hook
'flash_screen': ['flash', 'vb'], // visible bell (may not move cursor)
'form_feed': ['ff', 'ff'], // hardcopy terminal page eject (P*)
'from_status_line': ['fsl', 'fs'], // return from status line
'goto_window': ['wingo', 'WG'], // go to window #1
'hangup': ['hup', 'HU'], // hang-up phone
'init_1string': ['is1', 'i1'], // initialization string
'init_2string': ['is2', 'is'], // initialization string
'init_3string': ['is3', 'i3'], // initialization string
'init_file': ['if', 'if'], // name of initializa tion file
'init_prog': ['iprog', 'iP'], // path name of program for initialization
'initialize_color': ['initc', 'Ic'], // initialize color #1 to (#2,#3,#4)
'initialize_pair': ['initp', 'Ip'], // Initialize color pair #1 to fg=(#2,#3,#4), bg=(#5,#6,#7)
'insert_character': ['ich1', 'ic'], // insert character (P)
'insert_line': ['il1', 'al'], // insert line (P*)
'insert_padding': ['ip', 'ip'], // insert padding after inserted character
'key_a1': ['ka1', 'K1'], // upper left of keypad
'key_a3': ['ka3', 'K3'], // upper right of key pad
'key_b2': ['kb2', 'K2'], // center of keypad
'key_backspace': ['kbs', 'kb'], // backspace key
'key_beg': ['kbeg', '@1'], // begin key
'key_btab': ['kcbt', 'kB'], // back-tab key
'key_c1': ['kc1', 'K4'], // lower left of keypad
'key_c3': ['kc3', 'K5'], // lower right of key pad
'key_cancel': ['kcan', '@2'], // cancel key
'key_catab': ['ktbc', 'ka'], // clear-all-tabs key
'key_clear': ['kclr', 'kC'], // clear-screen or erase key
'key_close': ['kclo', '@3'], // close key
'key_command': ['kcmd', '@4'], // command key
'key_copy': ['kcpy', '@5'], // copy key
'key_create': ['kcrt', '@6'], // create key
'key_ctab': ['kctab', 'kt'], // clear-tab key
'key_dc': ['kdch1', 'kD'], // delete-character key
'key_dl': ['kdl1', 'kL'], // delete-line key
'key_down': ['kcud1', 'kd'], // down-arrow key
'key_eic': ['krmir', 'kM'], // sent by rmir or smir in insert mode
'key_end': ['kend', '@7'], // end key
'key_enter': ['kent', '@8'], // enter/send key
'key_eol': ['kel', 'kE'], // clear-to-end-of-line key
'key_eos': ['ked', 'kS'], // clear-to-end-of- screen key
'key_exit': ['kext', '@9'], // exit key
'key_f0': ['kf0', 'k0'], // F0 function key
'key_f1': ['kf1', 'k1'], // F1 function key
'key_f10': ['kf10', 'k;'], // F10 function key
'key_f11': ['kf11', 'F1'], // F11 function key
'key_f12': ['kf12', 'F2'], // F12 function key
'key_f13': ['kf13', 'F3'], // F13 function key
'key_f14': ['kf14', 'F4'], // F14 function key
'key_f15': ['kf15', 'F5'], // F15 function key
'key_f16': ['kf16', 'F6'], // F16 function key
'key_f17': ['kf17', 'F7'], // F17 function key
'key_f18': ['kf18', 'F8'], // F18 function key
'key_f19': ['kf19', 'F9'], // F19 function key
'key_f2': ['kf2', 'k2'], // F2 function key
'key_f20': ['kf20', 'FA'], // F20 function key
'key_f21': ['kf21', 'FB'], // F21 function key
'key_f22': ['kf22', 'FC'], // F22 function key
'key_f23': ['kf23', 'FD'], // F23 function key
'key_f24': ['kf24', 'FE'], // F24 function key
'key_f25': ['kf25', 'FF'], // F25 function key
'key_f26': ['kf26', 'FG'], // F26 function key
'key_f27': ['kf27', 'FH'], // F27 function key
'key_f28': ['kf28', 'FI'], // F28 function key
'key_f29': ['kf29', 'FJ'], // F29 function key
'key_f3': ['kf3', 'k3'], // F3 function key
'key_f30': ['kf30', 'FK'], // F30 function key
'key_f31': ['kf31', 'FL'], // F31 function key
'key_f32': ['kf32', 'FM'], // F32 function key
'key_f33': ['kf33', 'FN'], // F33 function key
'key_f34': ['kf34', 'FO'], // F34 function key
'key_f35': ['kf35', 'FP'], // F35 function key
'key_f36': ['kf36', 'FQ'], // F36 function key
'key_f37': ['kf37', 'FR'], // F37 function key
'key_f38': ['kf38', 'FS'], // F38 function key
'key_f39': ['kf39', 'FT'], // F39 function key
'key_f4': ['kf4', 'k4'], // F4 function key
'key_f40': ['kf40', 'FU'], // F40 function key
'key_f41': ['kf41', 'FV'], // F41 function key
'key_f42': ['kf42', 'FW'], // F42 function key
'key_f43': ['kf43', 'FX'], // F43 function key
'key_f44': ['kf44', 'FY'], // F44 function key
'key_f45': ['kf45', 'FZ'], // F45 function key
'key_f46': ['kf46', 'Fa'], // F46 function key
'key_f47': ['kf47', 'Fb'], // F47 function key
'key_f48': ['kf48', 'Fc'], // F48 function key
'key_f49': ['kf49', 'Fd'], // F49 function key
'key_f5': ['kf5', 'k5'], // F5 function key
'key_f50': ['kf50', 'Fe'], // F50 function key
'key_f51': ['kf51', 'Ff'], // F51 function key
'key_f52': ['kf52', 'Fg'], // F52 function key
'key_f53': ['kf53', 'Fh'], // F53 function key
'key_f54': ['kf54', 'Fi'], // F54 function key
'key_f55': ['kf55', 'Fj'], // F55 function key
'key_f56': ['kf56', 'Fk'], // F56 function key
'key_f57': ['kf57', 'Fl'], // F57 function key
'key_f58': ['kf58', 'Fm'], // F58 function key
'key_f59': ['kf59', 'Fn'], // F59 function key
'key_f6': ['kf6', 'k6'], // F6 function key
'key_f60': ['kf60', 'Fo'], // F60 function key
'key_f61': ['kf61', 'Fp'], // F61 function key
'key_f62': ['kf62', 'Fq'], // F62 function key
'key_f63': ['kf63', 'Fr'], // F63 function key
'key_f7': ['kf7', 'k7'], // F7 function key
'key_f8': ['kf8', 'k8'], // F8 function key
'key_f9': ['kf9', 'k9'], // F9 function key
'key_find': ['kfnd', '@0'], // find key
'key_help': ['khlp', '%1'], // help key
'key_home': ['khome', 'kh'], // home key
'key_ic': ['kich1', 'kI'], // insert-character key
'key_il': ['kil1', 'kA'], // insert-line key
'key_left': ['kcub1', 'kl'], // left-arrow key
'key_ll': ['kll', 'kH'], // lower-left key (home down)
'key_mark': ['kmrk', '%2'], // mark key
'key_message': ['kmsg', '%3'], // message key
'key_move': ['kmov', '%4'], // move key
'key_next': ['knxt', '%5'], // next key
'key_npage': ['knp', 'kN'], // next-page key
'key_open': ['kopn', '%6'], // open key
'key_options': ['kopt', '%7'], // options key
'key_ppage': ['kpp', 'kP'], // previous-page key
'key_previous': ['kprv', '%8'], // previous key
'key_print': ['kprt', '%9'], // print key
'key_redo': ['krdo', '%0'], // redo key
'key_reference': ['kref', '&1'], // reference key
'key_refresh': ['krfr', '&2'], // refresh key
'key_replace': ['krpl', '&3'], // replace key
'key_restart': ['krst', '&4'], // restart key
'key_resume': ['kres', '&5'], // resume key
'key_right': ['kcuf1', 'kr'], // right-arrow key
'key_save': ['ksav', '&6'], // save key
'key_sbeg': ['kBEG', '&9'], // shifted begin key
'key_scancel': ['kCAN', '&0'], // shifted cancel key
'key_scommand': ['kCMD', '*1'], // shifted command key
'key_scopy': ['kCPY', '*2'], // shifted copy key
'key_screate': ['kCRT', '*3'], // shifted create key
'key_sdc': ['kDC', '*4'], // shifted delete-char acter key
'key_sdl': ['kDL', '*5'], // shifted delete-line key
'key_select': ['kslt', '*6'], // select key
'key_send': ['kEND', '*7'], // shifted end key
'key_seol': ['kEOL', '*8'], // shifted clear-to- end-of-line key
'key_sexit': ['kEXT', '*9'], // shifted exit key
'key_sf': ['kind', 'kF'], // scroll-forward key
'key_sfind': ['kFND', '*0'], // shifted find key
'key_shelp': ['kHLP', '#1'], // shifted help key
'key_shome': ['kHOM', '#2'], // shifted home key
'key_sic': ['kIC', '#3'], // shifted insert-char acter key
'key_sleft': ['kLFT', '#4'], // shifted left-arrow key
'key_smessage': ['kMSG', '%a'], // shifted message key
'key_smove': ['kMOV', '%b'], // shifted move key
'key_snext': ['kNXT', '%c'], // shifted next key
'key_soptions': ['kOPT', '%d'], // shifted options key
'key_sprevious': ['kPRV', '%e'], // shifted previous key
'key_sprint': ['kPRT', '%f'], // shifted print key
'key_sr': ['kri', 'kR'], // scroll-backward key
'key_sredo': ['kRDO', '%g'], // shifted redo key
'key_sreplace': ['kRPL', '%h'], // shifted replace key
'key_sright': ['kRIT', '%i'], // shifted right-arrow key
'key_srsume': ['kRES', '%j'], // shifted resume key
'key_ssave': ['kSAV', '!1'], // shifted save key
'key_ssuspend': ['kSPD', '!2'], // shifted suspend key
'key_stab': ['khts', 'kT'], // set-tab key
'key_sundo': ['kUND', '!3'], // shifted undo key
'key_suspend': ['kspd', '&7'], // suspend key
'key_undo': ['kund', '&8'], // undo key
'key_up': ['kcuu1', 'ku'], // up-arrow key
'keypad_local': ['rmkx', 'ke'], // leave 'key board_transmit' mode
'keypad_xmit': ['smkx', 'ks'], // enter 'key board_transmit' mode
'lab_f0': ['lf0', 'l0'], // label on function key f0 if not f0
'lab_f1': ['lf1', 'l1'], // label on function key f1 if not f1
'lab_f10': ['lf10', 'la'], // label on function key f10 if not f10
'lab_f2': ['lf2', 'l2'], // label on function key f2 if not f2
'lab_f3': ['lf3', 'l3'], // label on function key f3 if not f3
'lab_f4': ['lf4', 'l4'], // label on function key f4 if not f4
'lab_f5': ['lf5', 'l5'], // label on function key f5 if not f5
'lab_f6': ['lf6', 'l6'], // label on function key f6 if not f6
'lab_f7': ['lf7', 'l7'], // label on function key f7 if not f7
'lab_f8': ['lf8', 'l8'], // label on function key f8 if not f8
'lab_f9': ['lf9', 'l9'], // label on function key f9 if not f9
'label_format': ['fln', 'Lf'], // label format
'label_off': ['rmln', 'LF'], // turn off soft labels
'label_on': ['smln', 'LO'], // turn on soft labels
'meta_off': ['rmm', 'mo'], // turn off meta mode
'meta_on': ['smm', 'mm'], // turn on meta mode (8th-bit on)
'micro_column_address': ['mhpa', 'ZY'], // Like column_address in micro mode
'micro_down': ['mcud1', 'ZZ'], // Like cursor_down in micro mode
'micro_left': ['mcub1', 'Za'], // Like cursor_left in micro mode
'micro_right': ['mcuf1', 'Zb'], // Like cursor_right in micro mode
'micro_row_address': ['mvpa', 'Zc'], // Like row_address #1 in micro mode
'micro_up': ['mcuu1', 'Zd'], // Like cursor_up in micro mode
'newline': ['nel', 'nw'], // newline (behave like cr followed by lf)
'order_of_pins': ['porder', 'Ze'], // Match software bits to print-head pins
'orig_colors': ['oc', 'oc'], // Set all color pairs to the original ones
'orig_pair': ['op', 'op'], // Set default pair to its original value
'pad_char': ['pad', 'pc'], // padding char (instead of null)
'parm_dch': ['dch', 'DC'], // delete #1 characters (P*)
'parm_delete_line': ['dl', 'DL'], // delete #1 lines (P*)
'parm_down_cursor': ['cud', 'DO'], // down #1 lines (P*)
'parm_down_micro': ['mcud', 'Zf'], // Like parm_down_cur sor in micro mode
'parm_ich': ['ich', 'IC'], // insert #1 characters (P*)
'parm_index': ['indn', 'SF'], // scroll forward #1 lines (P)
'parm_insert_line': ['il', 'AL'], // insert #1 lines (P*)
'parm_left_cursor': ['cub', 'LE'], // move #1 characters to the left (P)
'parm_left_micro': ['mcub', 'Zg'], // Like parm_left_cur sor in micro mode
'parm_right_cursor': ['cuf', 'RI'], // move #1 characters to the right (P*)
'parm_right_micro': ['mcuf', 'Zh'], // Like parm_right_cur sor in micro mode
'parm_rindex': ['rin', 'SR'], // scroll back #1 lines (P)
'parm_up_cursor': ['cuu', 'UP'], // up #1 lines (P*)
'parm_up_micro': ['mcuu', 'Zi'], // Like parm_up_cursor in micro mode
'pkey_key': ['pfkey', 'pk'], // program function key #1 to type string #2
'pkey_local': ['pfloc', 'pl'], // program function key #1 to execute string #2
'pkey_xmit': ['pfx', 'px'], // program function key #1 to transmit string #2
'plab_norm': ['pln', 'pn'], // program label #1 to show string #2
'print_screen': ['mc0', 'ps'], // print contents of screen
'prtr_non': ['mc5p', 'pO'], // turn on printer for #1 bytes
'prtr_off': ['mc4', 'pf'], // turn off printer
'prtr_on': ['mc5', 'po'], // turn on printer
'pulse': ['pulse', 'PU'], // select pulse dialing
'quick_dial': ['qdial', 'QD'], // dial number #1 with out checking
'remove_clock': ['rmclk', 'RC'], // remove clock
'repeat_char': ['rep', 'rp'], // repeat char #1 #2 times (P*)
'req_for_input': ['rfi', 'RF'], // send next input char (for ptys)
'reset_1string': ['rs1', 'r1'], // reset string
'reset_2string': ['rs2', 'r2'], // reset string
'reset_3string': ['rs3', 'r3'], // reset string
'reset_file': ['rf', 'rf'], // name of reset file
'restore_cursor': ['rc', 'rc'], // restore cursor to position of last save_cursor
'row_address': ['vpa', 'cv'], // vertical position #1 absolute (P)
'save_cursor': ['sc', 'sc'], // save current cursor position (P)
'scroll_forward': ['ind', 'sf'], // scroll text up (P)
'scroll_reverse': ['ri', 'sr'], // scroll text down (P)
'select_char_set': ['scs', 'Zj'], // Select character set, #1
'set_attributes': ['sgr', 'sa'], // define video attributes #1-#9 (PG9)
'set_background': ['setb', 'Sb'], // Set background color #1
'set_bottom_margin': ['smgb', 'Zk'], // Set bottom margin at current line
'set_bottom_margin_parm': ['smgbp', 'Zl'], // Set bottom margin at line #1 or (if smgtp is not given) #2 lines from bottom
'set_clock': ['sclk', 'SC'], // set clock, #1 hrs #2 mins #3 secs
'set_color_pair': ['scp', 'sp'], // Set current color pair to #1
'set_foreground': ['setf', 'Sf'], // Set foreground color #1
'set_left_margin': ['smgl', 'ML'], // set left soft margin at current col umn. See smgl. (ML is not in BSD termcap).
'set_left_margin_parm': ['smglp', 'Zm'], // Set left (right) margin at column #1
'set_right_margin': ['smgr', 'MR'], // set right soft margin at current column
'set_right_margin_parm': ['smgrp', 'Zn'], // Set right margin at column #1
'set_tab': ['hts', 'st'], // set a tab in every row, current columns
'set_top_margin': ['smgt', 'Zo'], // Set top margin at current line
'set_top_margin_parm': ['smgtp', 'Zp'], // Set top (bottom) margin at row #1
'set_window': ['wind', 'wi'], // current window is lines #1-#2 cols #3-#4
'start_bit_image': ['sbim', 'Zq'], // Start printing bit image graphics
'start_char_set_def': ['scsd', 'Zr'], // Start character set defi nition #1, with #2 charac ters in the set
'stop_bit_image': ['rbim', 'Zs'], // Stop printing bit image graphics
'stop_char_set_def': ['rcsd', 'Zt'], // End definition of charac ter set #1
'subscript_characters': ['subcs', 'Zu'], // List of subscriptable characters
'superscript_characters': ['supcs', 'Zv'], // List of superscriptable characters
'tab': ['ht', 'ta'], // tab to next 8-space hard ware tab stop
'these_cause_cr': ['docr', 'Zw'], // Printing any of these characters causes CR
'to_status_line': ['tsl', 'ts'], // move to status line, col umn #1
'tone': ['tone', 'TO'], // select touch tone dialing
'underline_char': ['uc', 'uc'], // underline char and move past it
'up_half_line': ['hu', 'hu'], // half a line up
'user0': ['u0', 'u0'], // User string #0
'user1': ['u1', 'u1'], // User string #1
'user2': ['u2', 'u2'], // User string #2
'user3': ['u3', 'u3'], // User string #3
'user4': ['u4', 'u4'], // User string #4
'user5': ['u5', 'u5'], // User string #5
'user6': ['u6', 'u6'], // User string #6
'user7': ['u7', 'u7'], // User string #7
'user8': ['u8', 'u8'], // User string #8
'user9': ['u9', 'u9'], // User string #9
'wait_tone': ['wait', 'WA'], // wait for dial-tone
'xoff_character': ['xoffc', 'XF'], // XOFF character
'xon_character': ['xonc', 'XN'], // XON character
'zero_motion': ['zerom', 'Zx'], // No motion for subsequent character
// The following string capabilities are present in the SVr4.0 term structure, but were originally not documented in the man page.
// Variable Cap- TCap Description
// String name Code
'alt_scancode_esc': ['scesa', 'S8'], // Alternate escape for scancode emu lation
'bit_image_carriage_return': ['bicr', 'Yv'], // Move to beginning of same row
'bit_image_newline': ['binel', 'Zz'], // Move to next row of the bit image
'bit_image_repeat': ['birep', 'Xy'], // Repeat bit image cell #1 #2 times
'char_set_names': ['csnm', 'Zy'], // Produce #1'th item from list of char acter set names
'code_set_init': ['csin', 'ci'], // Init sequence for multiple codesets
'color_names': ['colornm', 'Yw'], // Give name for color #1
'define_bit_image_region': ['defbi', 'Yx'], // Define rectan gualar bit image region
'device_type': ['devt', 'dv'], // Indicate lan guage/codeset sup port
'display_pc_char': ['dispc', 'S1'], // Display PC charac ter #1
'end_bit_image_region': ['endbi', 'Yy'], // End a bit-image region
'enter_pc_charset_mode': ['smpch', 'S2'], // Enter PC character display mode
'enter_scancode_mode': ['smsc', 'S4'], // Enter PC scancode mode
'exit_pc_charset_mode': ['rmpch', 'S3'], // Exit PC character display mode
'exit_scancode_mode': ['rmsc', 'S5'], // Exit PC scancode mode
'get_mouse': ['getm', 'Gm'], // Curses should get button events, parameter #1 not documented.
'key_mouse': ['kmous', 'Km'], // Mouse event has occurred
'mouse_info': ['minfo', 'Mi'], // Mouse status information
'pc_term_options': ['pctrm', 'S6'], // PC terminal options
'pkey_plab': ['pfxl', 'xl'], // Program function key #1 to type string #2 and show string #3
'req_mouse_pos': ['reqmp', 'RQ'], // Request mouse position
'scancode_escape': ['scesc', 'S7'], // Escape for scan code emulation
'set0_des_seq': ['s0ds', 's0'], // Shift to codeset 0 (EUC set 0, ASCII)
'set1_des_seq': ['s1ds', 's1'], // Shift to codeset 1
'set2_des_seq': ['s2ds', 's2'], // Shift to codeset 2
'set3_des_seq': ['s3ds', 's3'], // Shift to codeset 3
'set_a_background': ['setab', 'AB'], // Set background color to #1, using ANSI escape
'set_a_foreground': ['setaf', 'AF'], // Set foreground color to #1, using ANSI escape
'set_color_band': ['setcolor', 'Yz'], // Change to ribbon color #1
'set_lr_margin': ['smglr', 'ML'], // Set both left and right margins to #1, #2. (ML is not in BSD term cap).
'set_page_length': ['slines', 'YZ'], // Set page length to #1 lines
'set_tb_margin': ['smgtb', 'MT'], // Sets both top and bottom margins to #1, #2
// The XSI Curses standard added these. They are some post-4.1 versions of System V curses, e.g., Solaris 2.5 and IRIX 6.x. The ncurses termcap
// names for them are invented; according to the XSI Curses standard, they have no termcap names. If your compiled terminfo entries use these,
// they may not be binary-compatible with System V terminfo entries after SVr4.1; beware!
// Variable Cap- TCap Description
// String name Code
'enter_horizontal_hl_mode': ['ehhlm', 'Xh'], // Enter horizontal highlight mode
'enter_left_hl_mode': ['elhlm', 'Xl'], // Enter left highlight mode
'enter_low_hl_mode': ['elohlm', 'Xo'], // Enter low highlight mode
'enter_right_hl_mode': ['erhlm', 'Xr'], // Enter right high light mode
'enter_top_hl_mode': ['ethlm', 'Xt'], // Enter top highlight mode
'enter_vertical_hl_mode': ['evhlm', 'Xv'], // Enter vertical high light mode
'set_a_attributes': ['sgr1', 'sA'], // Define second set of video attributes #1-#6
'set_pglen_inch': ['slength', 'sL'] // YI Set page length to #1 hundredth of an inch
};

32
lib/blessed.js Normal file
View File

@ -0,0 +1,32 @@
/**
* blessed - a high-level terminal interface library for node.js
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Blessed
*/
function blessed() {
return blessed.program.apply(null, arguments);
}
blessed.program = blessed.Program = require('./program');
blessed.tput = blessed.Tput = require('./tput');
blessed.widget = require('./widget');
blessed.colors = require('./colors');
blessed.unicode = require('./unicode');
blessed.helpers = require('./helpers');
blessed.helpers.sprintf = blessed.tput.sprintf;
blessed.helpers.tryRead = blessed.tput.tryRead;
blessed.helpers.merge(blessed, blessed.helpers);
blessed.helpers.merge(blessed, blessed.widget);
/**
* Expose
*/
module.exports = blessed;

530
lib/colors.js Normal file
View File

@ -0,0 +1,530 @@
/**
* colors.js - color-related functions for blessed.
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
exports.match = function(r1, g1, b1) {
if (typeof r1 === 'string') {
var hex = r1;
if (hex[0] !== '#') {
return -1;
}
hex = exports.hexToRGB(hex);
r1 = hex[0], g1 = hex[1], b1 = hex[2];
} else if (Array.isArray(r1)) {
b1 = r1[2], g1 = r1[1], r1 = r1[0];
}
var hash = (r1 << 16) | (g1 << 8) | b1;
if (exports._cache[hash] != null) {
return exports._cache[hash];
}
var ldiff = Infinity
, li = -1
, i = 0
, c
, r2
, g2
, b2
, diff;
for (; i < exports.vcolors.length; i++) {
c = exports.vcolors[i];
r2 = c[0];
g2 = c[1];
b2 = c[2];
diff = colorDistance(r1, g1, b1, r2, g2, b2);
if (diff === 0) {
li = i;
break;
}
if (diff < ldiff) {
ldiff = diff;
li = i;
}
}
return exports._cache[hash] = li;
};
exports.RGBToHex = function(r, g, b) {
if (Array.isArray(r)) {
b = r[2], g = r[1], r = r[0];
}
function hex(n) {
n = n.toString(16);
if (n.length < 2) n = '0' + n;
return n;
}
return '#' + hex(r) + hex(g) + hex(b);
};
exports.hexToRGB = function(hex) {
if (hex.length === 4) {
hex = hex[0]
+ hex[1] + hex[1]
+ hex[2] + hex[2]
+ hex[3] + hex[3];
}
var col = parseInt(hex.substring(1), 16)
, r = (col >> 16) & 0xff
, g = (col >> 8) & 0xff
, b = col & 0xff;
return [r, g, b];
};
// As it happens, comparing how similar two colors are is really hard. Here is
// one of the simplest solutions, which doesn't require conversion to another
// color space, posted on stackoverflow[1]. Maybe someone better at math can
// propose a superior solution.
// [1] http://stackoverflow.com/questions/1633828
function colorDistance(r1, g1, b1, r2, g2, b2) {
return Math.pow(30 * (r1 - r2), 2)
+ Math.pow(59 * (g1 - g2), 2)
+ Math.pow(11 * (b1 - b2), 2);
}
// This might work well enough for a terminal's colors: treat RGB as XYZ in a
// 3-dimensional space and go midway between the two points.
exports.mixColors = function(c1, c2, alpha) {
// if (c1 === 0x1ff) return c1;
// if (c2 === 0x1ff) return c1;
if (c1 === 0x1ff) c1 = 0;
if (c2 === 0x1ff) c2 = 0;
if (alpha == null) alpha = 0.5;
c1 = exports.vcolors[c1];
var r1 = c1[0];
var g1 = c1[1];
var b1 = c1[2];
c2 = exports.vcolors[c2];
var r2 = c2[0];
var g2 = c2[1];
var b2 = c2[2];
r1 += (r2 - r1) * alpha | 0;
g1 += (g2 - g1) * alpha | 0;
b1 += (b2 - b1) * alpha | 0;
return exports.match([r1, g1, b1]);
};
exports.blend = function blend(attr, attr2, alpha) {
var name, i, c, nc;
var bg = attr & 0x1ff;
if (attr2 != null) {
var bg2 = attr2 & 0x1ff;
if (bg === 0x1ff) bg = 0;
if (bg2 === 0x1ff) bg2 = 0;
bg = exports.mixColors(bg, bg2, alpha);
} else {
if (blend._cache[bg] != null) {
bg = blend._cache[bg];
// } else if (bg < 8) {
// bg += 8;
} else if (bg >= 8 && bg <= 15) {
bg -= 8;
} else {
name = exports.ncolors[bg];
if (name) {
for (i = 0; i < exports.ncolors.length; i++) {
if (name === exports.ncolors[i] && i !== bg) {
c = exports.vcolors[bg];
nc = exports.vcolors[i];
if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
blend._cache[bg] = i;
bg = i;
break;
}
}
}
}
}
}
attr &= ~0x1ff;
attr |= bg;
var fg = (attr >> 9) & 0x1ff;
if (attr2 != null) {
var fg2 = (attr2 >> 9) & 0x1ff;
// 0, 7, 188, 231, 251
if (fg === 0x1ff) {
// XXX workaround
fg = 248;
} else {
if (fg === 0x1ff) fg = 7;
if (fg2 === 0x1ff) fg2 = 7;
fg = exports.mixColors(fg, fg2, alpha);
}
} else {
if (blend._cache[fg] != null) {
fg = blend._cache[fg];
// } else if (fg < 8) {
// fg += 8;
} else if (fg >= 8 && fg <= 15) {
fg -= 8;
} else {
name = exports.ncolors[fg];
if (name) {
for (i = 0; i < exports.ncolors.length; i++) {
if (name === exports.ncolors[i] && i !== fg) {
c = exports.vcolors[fg];
nc = exports.vcolors[i];
if (nc[0] + nc[1] + nc[2] < c[0] + c[1] + c[2]) {
blend._cache[fg] = i;
fg = i;
break;
}
}
}
}
}
}
attr &= ~(0x1ff << 9);
attr |= fg << 9;
return attr;
};
exports.blend._cache = {};
exports._cache = {};
exports.reduce = function(color, total) {
if (color >= 16 && total <= 16) {
color = exports.ccolors[color];
} else if (color >= 8 && total <= 8) {
color -= 8;
} else if (color >= 2 && total <= 2) {
color %= 2;
}
return color;
};
// XTerm Colors
// These were actually tough to track down. The xterm source only uses color
// keywords. The X11 source needed to be examined to find the actual values.
// They then had to be mapped to rgb values and then converted to hex values.
exports.xterm = [
'#000000', // black
'#cd0000', // red3
'#00cd00', // green3
'#cdcd00', // yellow3
'#0000ee', // blue2
'#cd00cd', // magenta3
'#00cdcd', // cyan3
'#e5e5e5', // gray90
'#7f7f7f', // gray50
'#ff0000', // red
'#00ff00', // green
'#ffff00', // yellow
'#5c5cff', // rgb:5c/5c/ff
'#ff00ff', // magenta
'#00ffff', // cyan
'#ffffff' // white
];
// Seed all 256 colors. Assume xterm defaults.
// Ported from the xterm color generation script.
exports.colors = (function() {
var cols = exports.colors = []
, _cols = exports.vcolors = []
, r
, g
, b
, i
, l;
function hex(n) {
n = n.toString(16);
if (n.length < 2) n = '0' + n;
return n;
}
function push(i, r, g, b) {
cols[i] = '#' + hex(r) + hex(g) + hex(b);
_cols[i] = [r, g, b];
}
// 0 - 15
exports.xterm.forEach(function(c, i) {
c = parseInt(c.substring(1), 16);
push(i, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
});
// 16 - 231
for (r = 0; r < 6; r++) {
for (g = 0; g < 6; g++) {
for (b = 0; b < 6; b++) {
i = 16 + (r * 36) + (g * 6) + b;
push(i,
r ? (r * 40 + 55) : 0,
g ? (g * 40 + 55) : 0,
b ? (b * 40 + 55) : 0);
}
}
}
// 232 - 255 are grey.
for (g = 0; g < 24; g++) {
l = (g * 10) + 8;
i = 232 + g;
push(i, l, l, l);
}
return cols;
})();
// Map higher colors to the first 8 colors.
// This allows translation of high colors to low colors on 8-color terminals.
exports.ccolors = (function() {
var _cols = exports.vcolors.slice()
, cols = exports.colors.slice()
, out;
exports.vcolors = exports.vcolors.slice(0, 8);
exports.colors = exports.colors.slice(0, 8);
out = cols.map(exports.match);
exports.colors = cols;
exports.vcolors = _cols;
exports.ccolors = out;
return out;
})();
var colorNames = exports.colorNames = {
// special
default: -1,
normal: -1,
bg: -1,
fg: -1,
// normal
black: 0,
red: 1,
green: 2,
yellow: 3,
blue: 4,
magenta: 5,
cyan: 6,
white: 7,
// light
lightblack: 8,
lightred: 9,
lightgreen: 10,
lightyellow: 11,
lightblue: 12,
lightmagenta: 13,
lightcyan: 14,
lightwhite: 15,
// bright
brightblack: 8,
brightred: 9,
brightgreen: 10,
brightyellow: 11,
brightblue: 12,
brightmagenta: 13,
brightcyan: 14,
brightwhite: 15,
// alternate spellings
grey: 8,
gray: 8,
lightgrey: 7,
lightgray: 7,
brightgrey: 7,
brightgray: 7
};
exports.convert = function(color) {
if (typeof color === 'number') {
;
} else if (typeof color === 'string') {
color = color.replace(/[\- ]/g, '');
if (colorNames[color] != null) {
color = colorNames[color];
} else {
color = exports.match(color);
}
} else if (Array.isArray(color)) {
color = exports.match(color);
} else {
color = -1;
}
return color !== -1 ? color : 0x1ff;
};
// Map higher colors to the first 8 colors.
// This allows translation of high colors to low colors on 8-color terminals.
// Why the hell did I do this by hand?
exports.ccolors = {
blue: [
4,
12,
[17, 21],
[24, 27],
[31, 33],
[38, 39],
45,
[54, 57],
[60, 63],
[67, 69],
[74, 75],
81,
[91, 93],
[97, 99],
[103, 105],
[110, 111],
117,
[128, 129],
[134, 135],
[140, 141],
[146, 147],
153,
165,
171,
177,
183,
189
],
green: [
2,
10,
22,
[28, 29],
[34, 36],
[40, 43],
[46, 50],
[64, 65],
[70, 72],
[76, 79],
[82, 86],
[106, 108],
[112, 115],
[118, 122],
[148, 151],
[154, 158],
[190, 194]
],
cyan: [
6,
14,
23,
30,
37,
44,
51,
66,
73,
80,
87,
109,
116,
123,
152,
159,
195
],
red: [
1,
9,
52,
[88, 89],
[94, 95],
[124, 126],
[130, 132],
[136, 138],
[160, 163],
[166, 169],
[172, 175],
[178, 181],
[196, 200],
[202, 206],
[208, 212],
[214, 218],
[220, 224]
],
magenta: [
5,
13,
53,
90,
96,
127,
133,
139,
164,
170,
176,
182,
201,
207,
213,
219,
225
],
yellow: [
3,
11,
58,
[100, 101],
[142, 144],
[184, 187],
[226, 230]
],
black: [
0,
8,
16,
59,
102,
[232, 243]
],
white: [
7,
15,
145,
188,
231,
[244, 255]
]
};
exports.ncolors = [];
Object.keys(exports.ccolors).forEach(function(name) {
exports.ccolors[name].forEach(function(offset) {
if (typeof offset === 'number') {
exports.ncolors[offset] = name;
exports.ccolors[offset] = exports.colorNames[name];
return;
}
for (var i = offset[0], l = offset[1]; i <= l; i++) {
exports.ncolors[i] = name;
exports.ccolors[i] = exports.colorNames[name];
}
});
delete exports.ccolors[name];
});

189
lib/events.js Normal file
View File

@ -0,0 +1,189 @@
/**
* events.js - event emitter for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
var slice = Array.prototype.slice;
/**
* EventEmitter
*/
function EventEmitter() {
if (!this._events) this._events = {};
}
EventEmitter.prototype.setMaxListeners = function(n) {
this._maxListeners = n;
};
EventEmitter.prototype.addListener = function(type, listener) {
if (!this._events[type]) {
this._events[type] = listener;
} else if (typeof this._events[type] === 'function') {
this._events[type] = [this._events[type], listener];
} else {
this._events[type].push(listener);
}
this._emit('newListener', [type, listener]);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.removeListener = function(type, listener) {
var handler = this._events[type];
if (!handler) return;
if (typeof handler === 'function' || handler.length === 1) {
delete this._events[type];
this._emit('removeListener', [type, listener]);
return;
}
for (var i = 0; i < handler.length; i++) {
if (handler[i] === listener || handler[i].listener === listener) {
handler.splice(i, 1);
this._emit('removeListener', [type, listener]);
return;
}
}
};
EventEmitter.prototype.off = EventEmitter.prototype.removeListener;
EventEmitter.prototype.removeAllListeners = function(type) {
if (type) {
delete this._events[type];
} else {
this._events = {};
}
};
EventEmitter.prototype.once = function(type, listener) {
function on() {
this.removeListener(type, on);
return listener.apply(this, arguments);
}
on.listener = listener;
return this.on(type, on);
};
EventEmitter.prototype.listeners = function(type) {
return typeof this._events[type] === 'function'
? [this._events[type]]
: this._events[type] || [];
};
EventEmitter.prototype._emit = function(type, args) {
var handler = this._events[type]
, ret;
// if (type !== 'event') {
// this._emit('event', [type.replace(/^element /, '')].concat(args));
// }
if (!handler) {
if (type === 'error') {
throw new args[0];
}
return;
}
if (typeof handler === 'function') {
return handler.apply(this, args);
}
for (var i = 0; i < handler.length; i++) {
if (handler[i].apply(this, args) === false) {
ret = false;
}
}
return ret !== false;
};
EventEmitter.prototype.emit = function(type) {
var args = slice.call(arguments, 1)
, params = slice.call(arguments)
, el = this;
this._emit('event', params);
if (this.type === 'screen') {
return this._emit(type, args);
}
if (this._emit(type, args) === false) {
return false;
}
type = 'element ' + type;
args.unshift(this);
// `element` prefix
// params = [type].concat(args);
// no `element` prefix
// params.splice(1, 0, this);
do {
// el._emit('event', params);
if (!el._events[type]) continue;
if (el._emit(type, args) === false) {
return false;
}
} while (el = el.parent);
return true;
};
// For hooking into the main EventEmitter if we want to.
// Might be better to do things this way being that it
// will always be compatible with node, not to mention
// it gives us domain support as well.
// Node.prototype._emit = Node.prototype.emit;
// Node.prototype.emit = function(type) {
// var args, el;
//
// if (this.type === 'screen') {
// return this._emit.apply(this, arguments);
// }
//
// this._emit.apply(this, arguments);
// if (this._bubbleStopped) return false;
//
// args = slice.call(arguments, 1);
// el = this;
//
// args.unshift('element ' + type, this);
// this._bubbleStopped = false;
// //args.push(stopBubble);
//
// do {
// if (!el._events || !el._events[type]) continue;
// el._emit.apply(el, args);
// if (this._bubbleStopped) return false;
// } while (el = el.parent);
//
// return true;
// };
//
// Node.prototype._addListener = Node.prototype.addListener;
// Node.prototype.on =
// Node.prototype.addListener = function(type, listener) {
// function on() {
// if (listener.apply(this, arguments) === false) {
// this._bubbleStopped = true;
// }
// }
// on.listener = listener;
// return this._addListener(type, on);
// };
/**
* Expose
*/
exports = EventEmitter;
exports.EventEmitter = EventEmitter;
module.exports = exports;

221
lib/gpmclient.js Normal file
View File

@ -0,0 +1,221 @@
/**
* gpmclient.js - support the gpm mouse protocol
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
var net = require('net');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var GPM_USE_MAGIC = false;
var GPM_MOVE = 1
, GPM_DRAG = 2
, GPM_DOWN = 4
, GPM_UP = 8;
var GPM_DOUBLE = 32
, GPM_MFLAG = 128;
var GPM_REQ_NOPASTE = 3
, GPM_HARD = 256;
var GPM_MAGIC = 0x47706D4C;
var GPM_SOCKET = '/dev/gpmctl';
// typedef struct Gpm_Connect {
// unsigned short eventMask, defaultMask;
// unsigned short minMod, maxMod;
// int pid;
// int vc;
// } Gpm_Connect;
function send_config(socket, Gpm_Connect, callback) {
var buffer;
if (GPM_USE_MAGIC) {
buffer = new Buffer(20);
buffer.writeUInt32LE(GPM_MAGIC, 0);
buffer.writeUInt16LE(Gpm_Connect.eventMask, 4);
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 6);
buffer.writeUInt16LE(Gpm_Connect.minMod, 8);
buffer.writeUInt16LE(Gpm_Connect.maxMod, 10);
buffer.writeInt16LE(process.pid, 12);
buffer.writeInt16LE(Gpm_Connect.vc, 16);
} else {
buffer = new Buffer(16);
buffer.writeUInt16LE(Gpm_Connect.eventMask, 0);
buffer.writeUInt16LE(Gpm_Connect.defaultMask, 2);
buffer.writeUInt16LE(Gpm_Connect.minMod, 4);
buffer.writeUInt16LE(Gpm_Connect.maxMod, 6);
buffer.writeInt16LE(Gpm_Connect.pid, 8);
buffer.writeInt16LE(Gpm_Connect.vc, 12);
}
socket.write(buffer, function() {
if (callback) callback();
});
}
// typedef struct Gpm_Event {
// unsigned char buttons, modifiers; // try to be a multiple of 4
// unsigned short vc;
// short dx, dy, x, y; // displacement x,y for this event, and absolute x,y
// enum Gpm_Etype type;
// // clicks e.g. double click are determined by time-based processing
// int clicks;
// enum Gpm_Margin margin;
// // wdx/y: displacement of wheels in this event. Absolute values are not
// // required, because wheel movement is typically used for scrolling
// // or selecting fields, not for cursor positioning. The application
// // can determine when the end of file or form is reached, and not
// // go any further.
// // A single mouse will use wdy, "vertical scroll" wheel.
// short wdx, wdy;
// } Gpm_Event;
function parseEvent(raw) {
var evnt = {};
evnt.buttons = raw[0];
evnt.modifiers = raw[1];
evnt.vc = raw.readUInt16LE(2);
evnt.dx = raw.readInt16LE(4);
evnt.dy = raw.readInt16LE(6);
evnt.x = raw.readInt16LE(8);
evnt.y = raw.readInt16LE(10);
evnt.type = raw.readInt16LE(12);
evnt.clicks = raw.readInt32LE(16);
evnt.margin = raw.readInt32LE(20);
evnt.wdx = raw.readInt16LE(24);
evnt.wdy = raw.readInt16LE(26);
return evnt;
}
function GpmClient(options) {
if (!(this instanceof GpmClient)) {
return new GpmClient(options);
}
EventEmitter.call(this);
var pid = process.pid;
// check tty for /dev/tty[n]
var path;
try {
path = fs.readlinkSync('/proc/' + pid + '/fd/0');
} catch (e) {
;
}
var tty = /tty[0-9]+$/.exec(path);
if (tty === null) {
// TODO: should also check for /dev/input/..
}
var vc;
if (tty) {
tty = tty[0];
vc = +/[0-9]+$/.exec(tty)[0];
}
var self = this;
if (tty) {
fs.stat(GPM_SOCKET, function(err, stat) {
if (err || !stat.isSocket()) {
return;
}
var conf = {
eventMask: 0xffff,
defaultMask: GPM_MOVE | GPM_HARD,
minMod: 0,
maxMod: 0xffff,
pid: pid,
vc: vc
};
var gpm = net.createConnection(GPM_SOCKET);
this.gpm = gpm;
gpm.on('connect', function() {
send_config(gpm, conf, function() {
conf.pid = 0;
conf.vc = GPM_REQ_NOPASTE;
//send_config(gpm, conf);
});
});
gpm.on('data', function(packet) {
var evnt = parseEvent(packet);
switch (evnt.type & 15) {
case GPM_MOVE:
if (evnt.dx || evnt.dy) {
self.emit('move', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
}
if (evnt.wdx || evnt.wdy) {
self.emit('mousewheel',
evnt.buttons, evnt.modifiers,
evnt.x, evnt.y, evnt.wdx, evnt.wdy);
}
break;
case GPM_DRAG:
if (evnt.dx || evnt.dy) {
self.emit('drag', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
}
if (evnt.wdx || evnt.wdy) {
self.emit('mousewheel',
evnt.buttons, evnt.modifiers,
evnt.x, evnt.y, evnt.wdx, evnt.wdy);
}
break;
case GPM_DOWN:
self.emit('btndown', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
if (evnt.type & GPM_DOUBLE) {
self.emit('dblclick', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
}
break;
case GPM_UP:
self.emit('btnup', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
if (!(evnt.type & GPM_MFLAG)) {
self.emit('click', evnt.buttons, evnt.modifiers, evnt.x, evnt.y);
}
break;
}
});
gpm.on('error', function() {
self.stop();
});
});
}
}
GpmClient.prototype.__proto__ = EventEmitter.prototype;
GpmClient.prototype.stop = function() {
if (this.gpm) {
this.gpm.end();
}
delete this.gpm;
};
GpmClient.prototype.ButtonName = function(btn) {
if (btn & 4) return 'left';
if (btn & 2) return 'middle';
if (btn & 1) return 'right';
return '';
};
GpmClient.prototype.hasShiftKey = function(mod) {
return (mod & 1) ? true : false;
};
GpmClient.prototype.hasCtrlKey = function(mod) {
return (mod & 4) ? true : false;
};
GpmClient.prototype.hasMetaKey = function(mod) {
return (mod & 8) ? true : false;
};
module.exports = GpmClient;

165
lib/helpers.js Normal file
View File

@ -0,0 +1,165 @@
/**
* helpers.js - helpers for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var fs = require('fs');
var unicode = require('./unicode');
/**
* Helpers
*/
var helpers = exports;
helpers.merge = function(a, b) {
Object.keys(b).forEach(function(key) {
a[key] = b[key];
});
return a;
};
helpers.asort = function(obj) {
return obj.sort(function(a, b) {
a = a.name.toLowerCase();
b = b.name.toLowerCase();
if (a[0] === '.' && b[0] === '.') {
a = a[1];
b = b[1];
} else {
a = a[0];
b = b[0];
}
return a > b ? 1 : (a < b ? -1 : 0);
});
};
helpers.hsort = function(obj) {
return obj.sort(function(a, b) {
return b.index - a.index;
});
};
helpers.findFile = function(start, target) {
return (function read(dir) {
var files, file, stat, out;
if (dir === '/dev' || dir === '/sys'
|| dir === '/proc' || dir === '/net') {
return null;
}
try {
files = fs.readdirSync(dir);
} catch (e) {
files = [];
}
for (var i = 0; i < files.length; i++) {
file = files[i];
if (file === target) {
return (dir === '/' ? '' : dir) + '/' + file;
}
try {
stat = fs.lstatSync((dir === '/' ? '' : dir) + '/' + file);
} catch (e) {
stat = null;
}
if (stat && stat.isDirectory() && !stat.isSymbolicLink()) {
out = read((dir === '/' ? '' : dir) + '/' + file);
if (out) return out;
}
}
return null;
})(start);
};
// Escape text for tag-enabled elements.
helpers.escape = function(text) {
return text.replace(/[{}]/g, function(ch) {
return ch === '{' ? '{open}' : '{close}';
});
};
helpers.parseTags = function(text, screen) {
return helpers.Element.prototype._parseTags.call(
{ parseTags: true, screen: screen || helpers.Screen.global }, text);
};
helpers.generateTags = function(style, text) {
var open = ''
, close = '';
Object.keys(style || {}).forEach(function(key) {
var val = style[key];
if (typeof val === 'string') {
val = val.replace(/^light(?!-)/, 'light-');
val = val.replace(/^bright(?!-)/, 'bright-');
open = '{' + val + '-' + key + '}' + open;
close += '{/' + val + '-' + key + '}';
} else {
if (val === true) {
open = '{' + key + '}' + open;
close += '{/' + key + '}';
}
}
});
if (text != null) {
return open + text + close;
}
return {
open: open,
close: close
};
};
helpers.attrToBinary = function(style, element) {
return helpers.Element.prototype.sattr.call(element || {}, style);
};
helpers.stripTags = function(text) {
if (!text) return '';
return text
.replace(/{(\/?)([\w\-,;!#]*)}/g, '')
.replace(/\x1b\[[\d;]*m/g, '');
};
helpers.cleanTags = function(text) {
return helpers.stripTags(text).trim();
};
helpers.dropUnicode = function(text) {
if (!text) return '';
return text
.replace(unicode.chars.all, '??')
.replace(unicode.chars.combining, '')
.replace(unicode.chars.surrogate, '?');
};
helpers.__defineGetter__('Screen', function() {
if (!helpers._screen) {
helpers._screen = require('./widgets/screen');
}
return helpers._screen;
});
helpers.__defineGetter__('Element', function() {
if (!helpers._element) {
helpers._element = require('./widgets/element');
}
return helpers._element;
});

339
lib/keys.js Normal file
View File

@ -0,0 +1,339 @@
/**
* keys.js - emit key presses
* Copyright (c) 2010-2015, Joyent, Inc. and other contributors (MIT License)
* https://github.com/chjj/blessed
*/
// Originally taken from the node.js tree:
//
// Copyright Joyent, Inc. and other Node contributors. All rights reserved.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
var EventEmitter = require('events').EventEmitter;
// NOTE: node <=v0.8.x has no EventEmitter.listenerCount
function listenerCount(stream, event) {
return EventEmitter.listenerCount
? EventEmitter.listenerCount(stream, event)
: stream.listeners(event).length;
}
/**
* accepts a readable Stream instance and makes it emit "keypress" events
*/
function emitKeypressEvents(stream) {
if (stream._keypressDecoder) return;
var StringDecoder = require('string_decoder').StringDecoder; // lazy load
stream._keypressDecoder = new StringDecoder('utf8');
function onData(b) {
if (listenerCount(stream, 'keypress') > 0) {
var r = stream._keypressDecoder.write(b);
if (r) emitKeys(stream, r);
} else {
// Nobody's watching anyway
stream.removeListener('data', onData);
stream.on('newListener', onNewListener);
}
}
function onNewListener(event) {
if (event === 'keypress') {
stream.on('data', onData);
stream.removeListener('newListener', onNewListener);
}
}
if (listenerCount(stream, 'keypress') > 0) {
stream.on('data', onData);
} else {
stream.on('newListener', onNewListener);
}
}
exports.emitKeypressEvents = emitKeypressEvents;
/*
Some patterns seen in terminal key escape codes, derived from combos seen
at http://www.midnight-commander.org/browser/lib/tty/key.c
ESC letter
ESC [ letter
ESC [ modifier letter
ESC [ 1 ; modifier letter
ESC [ num char
ESC [ num ; modifier char
ESC O letter
ESC O modifier letter
ESC O 1 ; modifier letter
ESC N letter
ESC [ [ num ; modifier char
ESC [ [ 1 ; modifier letter
ESC ESC [ num char
ESC ESC O letter
- char is usually ~ but $ and ^ also happen with rxvt
- modifier is 1 +
(shift * 1) +
(left_alt * 2) +
(ctrl * 4) +
(right_alt * 8)
- two leading ESCs apparently mean the same as one leading ESC
*/
// Regexes used for ansi escape code splitting
var metaKeyCodeReAnywhere = /(?:\x1b)([a-zA-Z0-9])/;
var metaKeyCodeRe = new RegExp('^' + metaKeyCodeReAnywhere.source + '$');
var functionKeyCodeReAnywhere = new RegExp('(?:\x1b+)(O|N|\\[|\\[\\[)(?:' + [
'(\\d+)(?:;(\\d+))?([~^$])',
'(?:M([@ #!a`])(.)(.))', // mouse
'(?:1;)?(\\d+)?([a-zA-Z])'
].join('|') + ')');
var functionKeyCodeRe = new RegExp('^' + functionKeyCodeReAnywhere.source);
var escapeCodeReAnywhere = new RegExp([
functionKeyCodeReAnywhere.source, metaKeyCodeReAnywhere.source, /\x1b./.source
].join('|'));
function emitKeys(stream, s) {
if (Buffer.isBuffer(s)) {
if (s[0] > 127 && s[1] === undefined) {
s[0] -= 128;
s = '\x1b' + s.toString(stream.encoding || 'utf-8');
} else {
s = s.toString(stream.encoding || 'utf-8');
}
}
if (isMouse(s)) return;
var buffer = [];
var match;
while (match = escapeCodeReAnywhere.exec(s)) {
buffer = buffer.concat(s.slice(0, match.index).split(''));
buffer.push(match[0]);
s = s.slice(match.index + match[0].length);
}
buffer = buffer.concat(s.split(''));
buffer.forEach(function(s) {
var ch,
key = {
sequence: s,
name: undefined,
ctrl: false,
meta: false,
shift: false
},
parts;
if (s === '\r') {
// carriage return
key.name = 'return';
} else if (s === '\n') {
// enter, should have been called linefeed
key.name = 'enter';
// linefeed
// key.name = 'linefeed';
} else if (s === '\t') {
// tab
key.name = 'tab';
} else if (s === '\b' || s === '\x7f' ||
s === '\x1b\x7f' || s === '\x1b\b') {
// backspace or ctrl+h
key.name = 'backspace';
key.meta = (s.charAt(0) === '\x1b');
} else if (s === '\x1b' || s === '\x1b\x1b') {
// escape key
key.name = 'escape';
key.meta = (s.length === 2);
} else if (s === ' ' || s === '\x1b ') {
key.name = 'space';
key.meta = (s.length === 2);
} else if (s.length === 1 && s <= '\x1a') {
// ctrl+letter
key.name = String.fromCharCode(s.charCodeAt(0) + 'a'.charCodeAt(0) - 1);
key.ctrl = true;
} else if (s.length === 1 && s >= 'a' && s <= 'z') {
// lowercase letter
key.name = s;
} else if (s.length === 1 && s >= 'A' && s <= 'Z') {
// shift+letter
key.name = s.toLowerCase();
key.shift = true;
} else if (parts = metaKeyCodeRe.exec(s)) {
// meta+character key
key.name = parts[1].toLowerCase();
key.meta = true;
key.shift = /^[A-Z]$/.test(parts[1]);
} else if (parts = functionKeyCodeRe.exec(s)) {
// ansi escape sequence
// reassemble the key code leaving out leading \x1b's,
// the modifier key bitflag and any meaningless "1;" sequence
var code = (parts[1] || '') + (parts[2] || '') +
(parts[4] || '') + (parts[9] || ''),
modifier = (parts[3] || parts[8] || 1) - 1;
// Parse the key modifier
key.ctrl = !!(modifier & 4);
key.meta = !!(modifier & 10);
key.shift = !!(modifier & 1);
key.code = code;
// Parse the key itself
switch (code) {
/* xterm/gnome ESC O letter */
case 'OP': key.name = 'f1'; break;
case 'OQ': key.name = 'f2'; break;
case 'OR': key.name = 'f3'; break;
case 'OS': key.name = 'f4'; break;
/* xterm/rxvt ESC [ number ~ */
case '[11~': key.name = 'f1'; break;
case '[12~': key.name = 'f2'; break;
case '[13~': key.name = 'f3'; break;
case '[14~': key.name = 'f4'; break;
/* from Cygwin and used in libuv */
case '[[A': key.name = 'f1'; break;
case '[[B': key.name = 'f2'; break;
case '[[C': key.name = 'f3'; break;
case '[[D': key.name = 'f4'; break;
case '[[E': key.name = 'f5'; break;
/* common */
case '[15~': key.name = 'f5'; break;
case '[17~': key.name = 'f6'; break;
case '[18~': key.name = 'f7'; break;
case '[19~': key.name = 'f8'; break;
case '[20~': key.name = 'f9'; break;
case '[21~': key.name = 'f10'; break;
case '[23~': key.name = 'f11'; break;
case '[24~': key.name = 'f12'; break;
/* xterm ESC [ letter */
case '[A': key.name = 'up'; break;
case '[B': key.name = 'down'; break;
case '[C': key.name = 'right'; break;
case '[D': key.name = 'left'; break;
case '[E': key.name = 'clear'; break;
case '[F': key.name = 'end'; break;
case '[H': key.name = 'home'; break;
/* xterm/gnome ESC O letter */
case 'OA': key.name = 'up'; break;
case 'OB': key.name = 'down'; break;
case 'OC': key.name = 'right'; break;
case 'OD': key.name = 'left'; break;
case 'OE': key.name = 'clear'; break;
case 'OF': key.name = 'end'; break;
case 'OH': key.name = 'home'; break;
/* xterm/rxvt ESC [ number ~ */
case '[1~': key.name = 'home'; break;
case '[2~': key.name = 'insert'; break;
case '[3~': key.name = 'delete'; break;
case '[4~': key.name = 'end'; break;
case '[5~': key.name = 'pageup'; break;
case '[6~': key.name = 'pagedown'; break;
/* putty */
case '[[5~': key.name = 'pageup'; break;
case '[[6~': key.name = 'pagedown'; break;
/* rxvt */
case '[7~': key.name = 'home'; break;
case '[8~': key.name = 'end'; break;
/* rxvt keys with modifiers */
case '[a': key.name = 'up'; key.shift = true; break;
case '[b': key.name = 'down'; key.shift = true; break;
case '[c': key.name = 'right'; key.shift = true; break;
case '[d': key.name = 'left'; key.shift = true; break;
case '[e': key.name = 'clear'; key.shift = true; break;
case '[2$': key.name = 'insert'; key.shift = true; break;
case '[3$': key.name = 'delete'; key.shift = true; break;
case '[5$': key.name = 'pageup'; key.shift = true; break;
case '[6$': key.name = 'pagedown'; key.shift = true; break;
case '[7$': key.name = 'home'; key.shift = true; break;
case '[8$': key.name = 'end'; key.shift = true; break;
case 'Oa': key.name = 'up'; key.ctrl = true; break;
case 'Ob': key.name = 'down'; key.ctrl = true; break;
case 'Oc': key.name = 'right'; key.ctrl = true; break;
case 'Od': key.name = 'left'; key.ctrl = true; break;
case 'Oe': key.name = 'clear'; key.ctrl = true; break;
case '[2^': key.name = 'insert'; key.ctrl = true; break;
case '[3^': key.name = 'delete'; key.ctrl = true; break;
case '[5^': key.name = 'pageup'; key.ctrl = true; break;
case '[6^': key.name = 'pagedown'; key.ctrl = true; break;
case '[7^': key.name = 'home'; key.ctrl = true; break;
case '[8^': key.name = 'end'; key.ctrl = true; break;
/* misc. */
case '[Z': key.name = 'tab'; key.shift = true; break;
default: key.name = 'undefined'; break;
}
}
// Don't emit a key if no name was found
if (key.name === undefined) {
key = undefined;
}
if (s.length === 1) {
ch = s;
}
if (key || ch) {
stream.emit('keypress', ch, key);
// if (key && key.name === 'return') {
// var nkey = {};
// Object.keys(key).forEach(function(k) {
// nkey[k] = key[k];
// });
// nkey.name = 'enter';
// stream.emit('keypress', ch, nkey);
// }
}
});
}
function isMouse(s) {
return /\x1b\[M/.test(s)
|| /\x1b\[M([\x00\u0020-\uffff]{3})/.test(s)
|| /\x1b\[(\d+;\d+;\d+)M/.test(s)
|| /\x1b\[<(\d+;\d+;\d+)([mM])/.test(s)
|| /\x1b\[<(\d+;\d+;\d+;\d+)&w/.test(s)
|| /\x1b\[24([0135])~\[(\d+),(\d+)\]\r/.test(s)
|| /\x1b\[(O|I)/.test(s);
}

File diff suppressed because it is too large Load Diff

3022
lib/tput.js Normal file

File diff suppressed because it is too large Load Diff

790
lib/unicode.js Normal file
View File

@ -0,0 +1,790 @@
/**
* unicode.js - east asian width and surrogate pairs
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
* Borrowed from vangie/east-asian-width, komagata/eastasianwidth,
* and mathiasbynens/String.prototype.codePointAt. Licenses below.
*/
// east-asian-width
//
// Copyright (c) 2015 Vangie Du
// https://github.com/vangie/east-asian-width
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// eastasianwidth
//
// Copyright (c) 2013, Masaki Komagata
// https://github.com/komagata/eastasianwidth
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// String.prototype.codePointAt
//
// Copyright Mathias Bynens <https://mathiasbynens.be/>
// https://github.com/mathiasbynens/String.prototype.codePointAt
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// String.fromCodePoint
//
// Copyright Mathias Bynens <https://mathiasbynens.be/>
// https://github.com/mathiasbynens/String.fromCodePoint
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var stringFromCharCode = String.fromCharCode;
var floor = Math.floor;
/**
* Wide, Surrogates, and Combining
*/
exports.charWidth = function(str, i) {
var point = typeof str !== 'number'
? exports.codePointAt(str, i || 0)
: str;
// nul
if (point === 0) return 0;
// tab
if (point === 0x09) {
if (!exports.blessed) {
exports.blessed = require('../');
}
return exports.blessed.screen.global
? exports.blessed.screen.global.tabc.length
: 8;
}
// 8-bit control characters (2-width according to unicode??)
if (point < 32 || (point >= 0x7f && point < 0xa0)) {
return 0;
}
// search table of non-spacing characters
// is ucs combining or C0/C1 control character
if (exports.combining[point]) {
return 0;
}
// check for double-wide
// if (point >= 0x1100
// && (point <= 0x115f // Hangul Jamo init. consonants
// || point === 0x2329 || point === 0x232a
// || (point >= 0x2e80 && point <= 0xa4cf
// && point !== 0x303f) // CJK ... Yi
// || (point >= 0xac00 && point <= 0xd7a3) // Hangul Syllables
// || (point >= 0xf900 && point <= 0xfaff) // CJK Compatibility Ideographs
// || (point >= 0xfe10 && point <= 0xfe19) // Vertical forms
// || (point >= 0xfe30 && point <= 0xfe6f) // CJK Compatibility Forms
// || (point >= 0xff00 && point <= 0xff60) // Fullwidth Forms
// || (point >= 0xffe0 && point <= 0xffe6)
// || (point >= 0x20000 && point <= 0x2fffd)
// || (point >= 0x30000 && point <= 0x3fffd))) {
// return 2;
// }
// check for double-wide
if ((0x3000 === point)
|| (0xFF01 <= point && point <= 0xFF60)
|| (0xFFE0 <= point && point <= 0xFFE6)) {
return 2;
}
if ((0x1100 <= point && point <= 0x115F)
|| (0x11A3 <= point && point <= 0x11A7)
|| (0x11FA <= point && point <= 0x11FF)
|| (0x2329 <= point && point <= 0x232A)
|| (0x2E80 <= point && point <= 0x2E99)
|| (0x2E9B <= point && point <= 0x2EF3)
|| (0x2F00 <= point && point <= 0x2FD5)
|| (0x2FF0 <= point && point <= 0x2FFB)
|| (0x3001 <= point && point <= 0x303E)
|| (0x3041 <= point && point <= 0x3096)
|| (0x3099 <= point && point <= 0x30FF)
|| (0x3105 <= point && point <= 0x312D)
|| (0x3131 <= point && point <= 0x318E)
|| (0x3190 <= point && point <= 0x31BA)
|| (0x31C0 <= point && point <= 0x31E3)
|| (0x31F0 <= point && point <= 0x321E)
|| (0x3220 <= point && point <= 0x3247)
|| (0x3250 <= point && point <= 0x32FE)
|| (0x3300 <= point && point <= 0x4DBF)
|| (0x4E00 <= point && point <= 0xA48C)
|| (0xA490 <= point && point <= 0xA4C6)
|| (0xA960 <= point && point <= 0xA97C)
|| (0xAC00 <= point && point <= 0xD7A3)
|| (0xD7B0 <= point && point <= 0xD7C6)
|| (0xD7CB <= point && point <= 0xD7FB)
|| (0xF900 <= point && point <= 0xFAFF)
|| (0xFE10 <= point && point <= 0xFE19)
|| (0xFE30 <= point && point <= 0xFE52)
|| (0xFE54 <= point && point <= 0xFE66)
|| (0xFE68 <= point && point <= 0xFE6B)
|| (0x1B000 <= point && point <= 0x1B001)
|| (0x1F200 <= point && point <= 0x1F202)
|| (0x1F210 <= point && point <= 0x1F23A)
|| (0x1F240 <= point && point <= 0x1F248)
|| (0x1F250 <= point && point <= 0x1F251)
|| (0x20000 <= point && point <= 0x2F73F)
|| (0x2B740 <= point && point <= 0x2FFFD)
|| (0x30000 <= point && point <= 0x3FFFD)) {
return 2;
}
// CJK Ambiguous
// http://www.unicode.org/reports/tr11/
// http://www.unicode.org/reports/tr11/#Ambiguous
if (process.env.NCURSES_CJK_WIDTH) {
if ((0x00A1 === point)
|| (0x00A4 === point)
|| (0x00A7 <= point && point <= 0x00A8)
|| (0x00AA === point)
|| (0x00AD <= point && point <= 0x00AE)
|| (0x00B0 <= point && point <= 0x00B4)
|| (0x00B6 <= point && point <= 0x00BA)
|| (0x00BC <= point && point <= 0x00BF)
|| (0x00C6 === point)
|| (0x00D0 === point)
|| (0x00D7 <= point && point <= 0x00D8)
|| (0x00DE <= point && point <= 0x00E1)
|| (0x00E6 === point)
|| (0x00E8 <= point && point <= 0x00EA)
|| (0x00EC <= point && point <= 0x00ED)
|| (0x00F0 === point)
|| (0x00F2 <= point && point <= 0x00F3)
|| (0x00F7 <= point && point <= 0x00FA)
|| (0x00FC === point)
|| (0x00FE === point)
|| (0x0101 === point)
|| (0x0111 === point)
|| (0x0113 === point)
|| (0x011B === point)
|| (0x0126 <= point && point <= 0x0127)
|| (0x012B === point)
|| (0x0131 <= point && point <= 0x0133)
|| (0x0138 === point)
|| (0x013F <= point && point <= 0x0142)
|| (0x0144 === point)
|| (0x0148 <= point && point <= 0x014B)
|| (0x014D === point)
|| (0x0152 <= point && point <= 0x0153)
|| (0x0166 <= point && point <= 0x0167)
|| (0x016B === point)
|| (0x01CE === point)
|| (0x01D0 === point)
|| (0x01D2 === point)
|| (0x01D4 === point)
|| (0x01D6 === point)
|| (0x01D8 === point)
|| (0x01DA === point)
|| (0x01DC === point)
|| (0x0251 === point)
|| (0x0261 === point)
|| (0x02C4 === point)
|| (0x02C7 === point)
|| (0x02C9 <= point && point <= 0x02CB)
|| (0x02CD === point)
|| (0x02D0 === point)
|| (0x02D8 <= point && point <= 0x02DB)
|| (0x02DD === point)
|| (0x02DF === point)
|| (0x0300 <= point && point <= 0x036F)
|| (0x0391 <= point && point <= 0x03A1)
|| (0x03A3 <= point && point <= 0x03A9)
|| (0x03B1 <= point && point <= 0x03C1)
|| (0x03C3 <= point && point <= 0x03C9)
|| (0x0401 === point)
|| (0x0410 <= point && point <= 0x044F)
|| (0x0451 === point)
|| (0x2010 === point)
|| (0x2013 <= point && point <= 0x2016)
|| (0x2018 <= point && point <= 0x2019)
|| (0x201C <= point && point <= 0x201D)
|| (0x2020 <= point && point <= 0x2022)
|| (0x2024 <= point && point <= 0x2027)
|| (0x2030 === point)
|| (0x2032 <= point && point <= 0x2033)
|| (0x2035 === point)
|| (0x203B === point)
|| (0x203E === point)
|| (0x2074 === point)
|| (0x207F === point)
|| (0x2081 <= point && point <= 0x2084)
|| (0x20AC === point)
|| (0x2103 === point)
|| (0x2105 === point)
|| (0x2109 === point)
|| (0x2113 === point)
|| (0x2116 === point)
|| (0x2121 <= point && point <= 0x2122)
|| (0x2126 === point)
|| (0x212B === point)
|| (0x2153 <= point && point <= 0x2154)
|| (0x215B <= point && point <= 0x215E)
|| (0x2160 <= point && point <= 0x216B)
|| (0x2170 <= point && point <= 0x2179)
|| (0x2189 === point)
|| (0x2190 <= point && point <= 0x2199)
|| (0x21B8 <= point && point <= 0x21B9)
|| (0x21D2 === point)
|| (0x21D4 === point)
|| (0x21E7 === point)
|| (0x2200 === point)
|| (0x2202 <= point && point <= 0x2203)
|| (0x2207 <= point && point <= 0x2208)
|| (0x220B === point)
|| (0x220F === point)
|| (0x2211 === point)
|| (0x2215 === point)
|| (0x221A === point)
|| (0x221D <= point && point <= 0x2220)
|| (0x2223 === point)
|| (0x2225 === point)
|| (0x2227 <= point && point <= 0x222C)
|| (0x222E === point)
|| (0x2234 <= point && point <= 0x2237)
|| (0x223C <= point && point <= 0x223D)
|| (0x2248 === point)
|| (0x224C === point)
|| (0x2252 === point)
|| (0x2260 <= point && point <= 0x2261)
|| (0x2264 <= point && point <= 0x2267)
|| (0x226A <= point && point <= 0x226B)
|| (0x226E <= point && point <= 0x226F)
|| (0x2282 <= point && point <= 0x2283)
|| (0x2286 <= point && point <= 0x2287)
|| (0x2295 === point)
|| (0x2299 === point)
|| (0x22A5 === point)
|| (0x22BF === point)
|| (0x2312 === point)
|| (0x2460 <= point && point <= 0x24E9)
|| (0x24EB <= point && point <= 0x254B)
|| (0x2550 <= point && point <= 0x2573)
|| (0x2580 <= point && point <= 0x258F)
|| (0x2592 <= point && point <= 0x2595)
|| (0x25A0 <= point && point <= 0x25A1)
|| (0x25A3 <= point && point <= 0x25A9)
|| (0x25B2 <= point && point <= 0x25B3)
|| (0x25B6 <= point && point <= 0x25B7)
|| (0x25BC <= point && point <= 0x25BD)
|| (0x25C0 <= point && point <= 0x25C1)
|| (0x25C6 <= point && point <= 0x25C8)
|| (0x25CB === point)
|| (0x25CE <= point && point <= 0x25D1)
|| (0x25E2 <= point && point <= 0x25E5)
|| (0x25EF === point)
|| (0x2605 <= point && point <= 0x2606)
|| (0x2609 === point)
|| (0x260E <= point && point <= 0x260F)
|| (0x2614 <= point && point <= 0x2615)
|| (0x261C === point)
|| (0x261E === point)
|| (0x2640 === point)
|| (0x2642 === point)
|| (0x2660 <= point && point <= 0x2661)
|| (0x2663 <= point && point <= 0x2665)
|| (0x2667 <= point && point <= 0x266A)
|| (0x266C <= point && point <= 0x266D)
|| (0x266F === point)
|| (0x269E <= point && point <= 0x269F)
|| (0x26BE <= point && point <= 0x26BF)
|| (0x26C4 <= point && point <= 0x26CD)
|| (0x26CF <= point && point <= 0x26E1)
|| (0x26E3 === point)
|| (0x26E8 <= point && point <= 0x26FF)
|| (0x273D === point)
|| (0x2757 === point)
|| (0x2776 <= point && point <= 0x277F)
|| (0x2B55 <= point && point <= 0x2B59)
|| (0x3248 <= point && point <= 0x324F)
|| (0xE000 <= point && point <= 0xF8FF)
|| (0xFE00 <= point && point <= 0xFE0F)
|| (0xFFFD === point)
|| (0x1F100 <= point && point <= 0x1F10A)
|| (0x1F110 <= point && point <= 0x1F12D)
|| (0x1F130 <= point && point <= 0x1F169)
|| (0x1F170 <= point && point <= 0x1F19A)
|| (0xE0100 <= point && point <= 0xE01EF)
|| (0xF0000 <= point && point <= 0xFFFFD)
|| (0x100000 <= point && point <= 0x10FFFD)) {
return +process.env.NCURSES_CJK_WIDTH || 1;
}
}
return 1;
};
exports.strWidth = function(str) {
var width = 0;
for (var i = 0; i < str.length; i++) {
width += exports.charWidth(str, i);
if (exports.isSurrogate(str, i)) i++;
}
return width;
};
exports.isSurrogate = function(str, i) {
var point = typeof str !== 'number'
? exports.codePointAt(str, i || 0)
: str;
return point > 0x00ffff;
};
exports.combiningTable = [
[0x0300, 0x036F], [0x0483, 0x0486], [0x0488, 0x0489],
[0x0591, 0x05BD], [0x05BF, 0x05BF], [0x05C1, 0x05C2],
[0x05C4, 0x05C5], [0x05C7, 0x05C7], [0x0600, 0x0603],
[0x0610, 0x0615], [0x064B, 0x065E], [0x0670, 0x0670],
[0x06D6, 0x06E4], [0x06E7, 0x06E8], [0x06EA, 0x06ED],
[0x070F, 0x070F], [0x0711, 0x0711], [0x0730, 0x074A],
[0x07A6, 0x07B0], [0x07EB, 0x07F3], [0x0901, 0x0902],
[0x093C, 0x093C], [0x0941, 0x0948], [0x094D, 0x094D],
[0x0951, 0x0954], [0x0962, 0x0963], [0x0981, 0x0981],
[0x09BC, 0x09BC], [0x09C1, 0x09C4], [0x09CD, 0x09CD],
[0x09E2, 0x09E3], [0x0A01, 0x0A02], [0x0A3C, 0x0A3C],
[0x0A41, 0x0A42], [0x0A47, 0x0A48], [0x0A4B, 0x0A4D],
[0x0A70, 0x0A71], [0x0A81, 0x0A82], [0x0ABC, 0x0ABC],
[0x0AC1, 0x0AC5], [0x0AC7, 0x0AC8], [0x0ACD, 0x0ACD],
[0x0AE2, 0x0AE3], [0x0B01, 0x0B01], [0x0B3C, 0x0B3C],
[0x0B3F, 0x0B3F], [0x0B41, 0x0B43], [0x0B4D, 0x0B4D],
[0x0B56, 0x0B56], [0x0B82, 0x0B82], [0x0BC0, 0x0BC0],
[0x0BCD, 0x0BCD], [0x0C3E, 0x0C40], [0x0C46, 0x0C48],
[0x0C4A, 0x0C4D], [0x0C55, 0x0C56], [0x0CBC, 0x0CBC],
[0x0CBF, 0x0CBF], [0x0CC6, 0x0CC6], [0x0CCC, 0x0CCD],
[0x0CE2, 0x0CE3], [0x0D41, 0x0D43], [0x0D4D, 0x0D4D],
[0x0DCA, 0x0DCA], [0x0DD2, 0x0DD4], [0x0DD6, 0x0DD6],
[0x0E31, 0x0E31], [0x0E34, 0x0E3A], [0x0E47, 0x0E4E],
[0x0EB1, 0x0EB1], [0x0EB4, 0x0EB9], [0x0EBB, 0x0EBC],
[0x0EC8, 0x0ECD], [0x0F18, 0x0F19], [0x0F35, 0x0F35],
[0x0F37, 0x0F37], [0x0F39, 0x0F39], [0x0F71, 0x0F7E],
[0x0F80, 0x0F84], [0x0F86, 0x0F87], [0x0F90, 0x0F97],
[0x0F99, 0x0FBC], [0x0FC6, 0x0FC6], [0x102D, 0x1030],
[0x1032, 0x1032], [0x1036, 0x1037], [0x1039, 0x1039],
[0x1058, 0x1059], [0x1160, 0x11FF], [0x135F, 0x135F],
[0x1712, 0x1714], [0x1732, 0x1734], [0x1752, 0x1753],
[0x1772, 0x1773], [0x17B4, 0x17B5], [0x17B7, 0x17BD],
[0x17C6, 0x17C6], [0x17C9, 0x17D3], [0x17DD, 0x17DD],
[0x180B, 0x180D], [0x18A9, 0x18A9], [0x1920, 0x1922],
[0x1927, 0x1928], [0x1932, 0x1932], [0x1939, 0x193B],
[0x1A17, 0x1A18], [0x1B00, 0x1B03], [0x1B34, 0x1B34],
[0x1B36, 0x1B3A], [0x1B3C, 0x1B3C], [0x1B42, 0x1B42],
[0x1B6B, 0x1B73], [0x1DC0, 0x1DCA], [0x1DFE, 0x1DFF],
[0x200B, 0x200F], [0x202A, 0x202E], [0x2060, 0x2063],
[0x206A, 0x206F], [0x20D0, 0x20EF], [0x302A, 0x302F],
[0x3099, 0x309A], [0xA806, 0xA806], [0xA80B, 0xA80B],
[0xA825, 0xA826], [0xFB1E, 0xFB1E], [0xFE00, 0xFE0F],
[0xFE20, 0xFE23], [0xFEFF, 0xFEFF], [0xFFF9, 0xFFFB],
[0x10A01, 0x10A03], [0x10A05, 0x10A06], [0x10A0C, 0x10A0F],
[0x10A38, 0x10A3A], [0x10A3F, 0x10A3F], [0x1D167, 0x1D169],
[0x1D173, 0x1D182], [0x1D185, 0x1D18B], [0x1D1AA, 0x1D1AD],
[0x1D242, 0x1D244], [0xE0001, 0xE0001], [0xE0020, 0xE007F],
[0xE0100, 0xE01EF]
];
exports.combining = exports.combiningTable.reduce(function(out, row) {
for (var i = row[0]; i <= row[1]; i++) {
out[i] = true;
}
return out;
}, {});
exports.isCombining = function(str, i) {
var point = typeof str !== 'number'
? exports.codePointAt(str, i || 0)
: str;
return exports.combining[point] === true;
};
/**
* Code Point Helpers
*/
exports.codePointAt = function(str, position) {
if (str == null) {
throw TypeError();
}
var string = String(str);
if (string.codePointAt) {
return string.codePointAt(position);
}
var size = string.length;
// `ToInteger`
var index = position ? Number(position) : 0;
if (index !== index) { // better `isNaN`
index = 0;
}
// Account for out-of-bounds indices:
if (index < 0 || index >= size) {
return undefined;
}
// Get the first code unit
var first = string.charCodeAt(index);
var second;
if ( // check if its the start of a surrogate pair
first >= 0xD800 && first <= 0xDBFF && // high surrogate
size > index + 1 // there is a next code unit
) {
second = string.charCodeAt(index + 1);
if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
return (first - 0xD800) * 0x400 + second - 0xDC00 + 0x10000;
}
}
return first;
};
// exports.codePointAt = function(str, position) {
// position = +position || 0;
// var x = str.charCodeAt(position);
// var y = str.length > 1 ? str.charCodeAt(position + 1) : 0;
// var point = x;
// if ((0xD800 <= x && x <= 0xDBFF) && (0xDC00 <= y && y <= 0xDFFF)) {
// x &= 0x3FF;
// y &= 0x3FF;
// point = (x << 10) | y;
// point += 0x10000;
// }
// return point;
// };
exports.fromCodePoint = function() {
if (String.fromCodePoint) {
return String.fromCodePoint.apply(String, arguments);
}
var MAX_SIZE = 0x4000;
var codeUnits = [];
var highSurrogate;
var lowSurrogate;
var index = -1;
var length = arguments.length;
if (!length) {
return '';
}
var result = '';
while (++index < length) {
var codePoint = Number(arguments[index]);
if (
!isFinite(codePoint) || // `NaN`, `+Infinity`, or `-Infinity`
codePoint < 0 || // not a valid Unicode code point
codePoint > 0x10FFFF || // not a valid Unicode code point
floor(codePoint) !== codePoint // not an integer
) {
throw RangeError('Invalid code point: ' + codePoint);
}
if (codePoint <= 0xFFFF) { // BMP code point
codeUnits.push(codePoint);
} else { // Astral code point; split in surrogate halves
// http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae
codePoint -= 0x10000;
highSurrogate = (codePoint >> 10) + 0xD800;
lowSurrogate = (codePoint % 0x400) + 0xDC00;
codeUnits.push(highSurrogate, lowSurrogate);
}
if (index + 1 === length || codeUnits.length > MAX_SIZE) {
result += stringFromCharCode.apply(null, codeUnits);
codeUnits.length = 0;
}
}
return result;
};
/**
* Regexes
*/
exports.chars = {};
// Double width characters that are _not_ surrogate pairs.
// NOTE: 0x20000 - 0x2fffd and 0x30000 - 0x3fffd are not necessary for this
// regex anyway. This regex is used to put a blank char after wide chars to
// be eaten, however, if this is a surrogate pair, parseContent already adds
// the extra one char because its length equals 2 instead of 1.
exports.chars.wide = new RegExp('(['
+ '\\u1100-\\u115f' // Hangul Jamo init. consonants
+ '\\u2329\\u232a'
+ '\\u2e80-\\u303e\\u3040-\\ua4cf' // CJK ... Yi
+ '\\uac00-\\ud7a3' // Hangul Syllables
+ '\\uf900-\\ufaff' // CJK Compatibility Ideographs
+ '\\ufe10-\\ufe19' // Vertical forms
+ '\\ufe30-\\ufe6f' // CJK Compatibility Forms
+ '\\uff00-\\uff60' // Fullwidth Forms
+ '\\uffe0-\\uffe6'
+ '])', 'g');
// All surrogate pair wide chars.
exports.chars.swide = new RegExp('('
// 0x20000 - 0x2fffd:
+ '[\\ud840-\\ud87f][\\udc00-\\udffd]'
+ '|'
// 0x30000 - 0x3fffd:
+ '[\\ud880-\\ud8bf][\\udc00-\\udffd]'
+ ')', 'g');
// All wide chars including surrogate pairs.
exports.chars.all = new RegExp('('
+ exports.chars.swide.source.slice(1, -1)
+ '|'
+ exports.chars.wide.source.slice(1, -1)
+ ')', 'g');
// Regex to detect a surrogate pair.
exports.chars.surrogate = /[\ud800-\udbff][\udc00-\udfff]/g;
// Regex to find combining characters.
exports.chars.combining = exports.combiningTable.reduce(function(out, row) {
var low, high, range;
if (row[0] > 0x00ffff) {
low = exports.fromCodePoint(row[0]);
low = [
hexify(low.charCodeAt(0)),
hexify(low.charCodeAt(1))
];
high = exports.fromCodePoint(row[1]);
high = [
hexify(high.charCodeAt(0)),
hexify(high.charCodeAt(1))
];
range = '[\\u' + low[0] + '-' + '\\u' + high[0] + ']'
+ '[\\u' + low[1] + '-' + '\\u' + high[1] + ']';
if (!~out.indexOf('|')) out += ']';
out += '|' + range;
} else {
low = hexify(row[0]);
high = hexify(row[1]);
low = '\\u' + low;
high = '\\u' + high;
out += low + '-' + high;
}
return out;
}, '[');
exports.chars.combining = new RegExp(exports.chars.combining, 'g');
function hexify(n) {
n = n.toString(16);
while (n.length < 4) n = '0' + n;
return n;
}
/*
exports.chars.combining = new RegExp(
'['
+ '\\u0300-\\u036f'
+ '\\u0483-\\u0486'
+ '\\u0488-\\u0489'
+ '\\u0591-\\u05bd'
+ '\\u05bf-\\u05bf'
+ '\\u05c1-\\u05c2'
+ '\\u05c4-\\u05c5'
+ '\\u05c7-\\u05c7'
+ '\\u0600-\\u0603'
+ '\\u0610-\\u0615'
+ '\\u064b-\\u065e'
+ '\\u0670-\\u0670'
+ '\\u06d6-\\u06e4'
+ '\\u06e7-\\u06e8'
+ '\\u06ea-\\u06ed'
+ '\\u070f-\\u070f'
+ '\\u0711-\\u0711'
+ '\\u0730-\\u074a'
+ '\\u07a6-\\u07b0'
+ '\\u07eb-\\u07f3'
+ '\\u0901-\\u0902'
+ '\\u093c-\\u093c'
+ '\\u0941-\\u0948'
+ '\\u094d-\\u094d'
+ '\\u0951-\\u0954'
+ '\\u0962-\\u0963'
+ '\\u0981-\\u0981'
+ '\\u09bc-\\u09bc'
+ '\\u09c1-\\u09c4'
+ '\\u09cd-\\u09cd'
+ '\\u09e2-\\u09e3'
+ '\\u0a01-\\u0a02'
+ '\\u0a3c-\\u0a3c'
+ '\\u0a41-\\u0a42'
+ '\\u0a47-\\u0a48'
+ '\\u0a4b-\\u0a4d'
+ '\\u0a70-\\u0a71'
+ '\\u0a81-\\u0a82'
+ '\\u0abc-\\u0abc'
+ '\\u0ac1-\\u0ac5'
+ '\\u0ac7-\\u0ac8'
+ '\\u0acd-\\u0acd'
+ '\\u0ae2-\\u0ae3'
+ '\\u0b01-\\u0b01'
+ '\\u0b3c-\\u0b3c'
+ '\\u0b3f-\\u0b3f'
+ '\\u0b41-\\u0b43'
+ '\\u0b4d-\\u0b4d'
+ '\\u0b56-\\u0b56'
+ '\\u0b82-\\u0b82'
+ '\\u0bc0-\\u0bc0'
+ '\\u0bcd-\\u0bcd'
+ '\\u0c3e-\\u0c40'
+ '\\u0c46-\\u0c48'
+ '\\u0c4a-\\u0c4d'
+ '\\u0c55-\\u0c56'
+ '\\u0cbc-\\u0cbc'
+ '\\u0cbf-\\u0cbf'
+ '\\u0cc6-\\u0cc6'
+ '\\u0ccc-\\u0ccd'
+ '\\u0ce2-\\u0ce3'
+ '\\u0d41-\\u0d43'
+ '\\u0d4d-\\u0d4d'
+ '\\u0dca-\\u0dca'
+ '\\u0dd2-\\u0dd4'
+ '\\u0dd6-\\u0dd6'
+ '\\u0e31-\\u0e31'
+ '\\u0e34-\\u0e3a'
+ '\\u0e47-\\u0e4e'
+ '\\u0eb1-\\u0eb1'
+ '\\u0eb4-\\u0eb9'
+ '\\u0ebb-\\u0ebc'
+ '\\u0ec8-\\u0ecd'
+ '\\u0f18-\\u0f19'
+ '\\u0f35-\\u0f35'
+ '\\u0f37-\\u0f37'
+ '\\u0f39-\\u0f39'
+ '\\u0f71-\\u0f7e'
+ '\\u0f80-\\u0f84'
+ '\\u0f86-\\u0f87'
+ '\\u0f90-\\u0f97'
+ '\\u0f99-\\u0fbc'
+ '\\u0fc6-\\u0fc6'
+ '\\u102d-\\u1030'
+ '\\u1032-\\u1032'
+ '\\u1036-\\u1037'
+ '\\u1039-\\u1039'
+ '\\u1058-\\u1059'
+ '\\u1160-\\u11ff'
+ '\\u135f-\\u135f'
+ '\\u1712-\\u1714'
+ '\\u1732-\\u1734'
+ '\\u1752-\\u1753'
+ '\\u1772-\\u1773'
+ '\\u17b4-\\u17b5'
+ '\\u17b7-\\u17bd'
+ '\\u17c6-\\u17c6'
+ '\\u17c9-\\u17d3'
+ '\\u17dd-\\u17dd'
+ '\\u180b-\\u180d'
+ '\\u18a9-\\u18a9'
+ '\\u1920-\\u1922'
+ '\\u1927-\\u1928'
+ '\\u1932-\\u1932'
+ '\\u1939-\\u193b'
+ '\\u1a17-\\u1a18'
+ '\\u1b00-\\u1b03'
+ '\\u1b34-\\u1b34'
+ '\\u1b36-\\u1b3a'
+ '\\u1b3c-\\u1b3c'
+ '\\u1b42-\\u1b42'
+ '\\u1b6b-\\u1b73'
+ '\\u1dc0-\\u1dca'
+ '\\u1dfe-\\u1dff'
+ '\\u200b-\\u200f'
+ '\\u202a-\\u202e'
+ '\\u2060-\\u2063'
+ '\\u206a-\\u206f'
+ '\\u20d0-\\u20ef'
+ '\\u302a-\\u302f'
+ '\\u3099-\\u309a'
+ '\\ua806-\\ua806'
+ '\\ua80b-\\ua80b'
+ '\\ua825-\\ua826'
+ '\\ufb1e-\\ufb1e'
+ '\\ufe00-\\ufe0f'
+ '\\ufe20-\\ufe23'
+ '\\ufeff-\\ufeff'
+ '\\ufff9-\\ufffb'
+ ']'
+ '|[\\ud802-\\ud802][\\ude01-\\ude03]'
+ '|[\\ud802-\\ud802][\\ude05-\\ude06]'
+ '|[\\ud802-\\ud802][\\ude0c-\\ude0f]'
+ '|[\\ud802-\\ud802][\\ude38-\\ude3a]'
+ '|[\\ud802-\\ud802][\\ude3f-\\ude3f]'
+ '|[\\ud834-\\ud834][\\udd67-\\udd69]'
+ '|[\\ud834-\\ud834][\\udd73-\\udd82]'
+ '|[\\ud834-\\ud834][\\udd85-\\udd8b]'
+ '|[\\ud834-\\ud834][\\uddaa-\\uddad]'
+ '|[\\ud834-\\ud834][\\ude42-\\ude44]'
+ '|[\\udb40-\\udb40][\\udc01-\\udc01]'
+ '|[\\udb40-\\udb40][\\udc20-\\udc7f]'
+ '|[\\udb40-\\udb40][\\udd00-\\uddef]'
, 'g');
*/

60
lib/widget.js Normal file
View File

@ -0,0 +1,60 @@
/**
* widget.js - high-level interface for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
var widget = exports;
widget.classes = [
'Node',
'Screen',
'Element',
'Box',
'Text',
'Line',
'ScrollableBox',
'ScrollableText',
'BigText',
'List',
'Form',
'Input',
'Textarea',
'Textbox',
'Button',
'ProgressBar',
'FileManager',
'Checkbox',
'RadioSet',
'RadioButton',
'Prompt',
'Question',
'Message',
'Loading',
'Listbar',
'Log',
'Table',
'ListTable',
'Terminal',
'Image',
'ANSIImage',
'OverlayImage',
'Video',
'Layout'
];
widget.classes.forEach(function(name) {
var file = name.toLowerCase();
widget[name] = widget[file] = require('./widgets/' + file);
});
widget.aliases = {
'ListBar': 'Listbar',
'PNG': 'ANSIImage'
};
Object.keys(widget.aliases).forEach(function(key) {
var name = widget.aliases[key];
widget[key] = widget[name];
widget[key.toLowerCase()] = widget[name];
});

167
lib/widgets/ansiimage.js Normal file
View File

@ -0,0 +1,167 @@
/**
* ansiimage.js - render PNGS/GIFS as ANSI
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var cp = require('child_process');
var colors = require('../colors');
var Node = require('./node');
var Box = require('./box');
var tng = require('../../vendor/tng');
/**
* ANSIImage
*/
function ANSIImage(options) {
var self = this;
if (!(this instanceof Node)) {
return new ANSIImage(options);
}
options = options || {};
options.shrink = true;
Box.call(this, options);
this.scale = this.options.scale || 1.0;
this.options.animate = this.options.animate !== false;
this._noFill = true;
if (this.options.file) {
this.setImage(this.options.file);
}
this.screen.on('prerender', function() {
var lpos = self.lpos;
if (!lpos) return;
// prevent image from blending with itself if there are alpha channels
self.screen.clearRegion(lpos.xi, lpos.xl, lpos.yi, lpos.yl);
});
this.on('destroy', function() {
self.stop();
});
}
ANSIImage.prototype.__proto__ = Box.prototype;
ANSIImage.prototype.type = 'ansiimage';
ANSIImage.curl = function(url) {
try {
return cp.execFileSync('curl',
['-s', '-A', '', url],
{ stdio: ['ignore', 'pipe', 'ignore'] });
} catch (e) {
;
}
try {
return cp.execFileSync('wget',
['-U', '', '-O', '-', url],
{ stdio: ['ignore', 'pipe', 'ignore'] });
} catch (e) {
;
}
throw new Error('curl or wget failed.');
};
ANSIImage.prototype.setImage = function(file) {
this.file = typeof file === 'string' ? file : null;
if (/^https?:/.test(file)) {
file = ANSIImage.curl(file);
}
var width = this.position.width;
var height = this.position.height;
if (width != null) {
width = this.width;
}
if (height != null) {
height = this.height;
}
try {
this.setContent('');
this.img = tng(file, {
colors: colors,
width: width,
height: height,
scale: this.scale,
ascii: this.options.ascii,
speed: this.options.speed,
filename: this.file
});
if (width == null || height == null) {
this.width = this.img.cellmap[0].length;
this.height = this.img.cellmap.length;
}
if (this.img.frames && this.options.animate) {
this.play();
} else {
this.cellmap = this.img.cellmap;
}
} catch (e) {
this.setContent('Image Error: ' + e.message);
this.img = null;
this.cellmap = null;
}
};
ANSIImage.prototype.play = function() {
var self = this;
if (!this.img) return;
return this.img.play(function(bmp, cellmap) {
self.cellmap = cellmap;
self.screen.render();
});
};
ANSIImage.prototype.pause = function() {
if (!this.img) return;
return this.img.pause();
};
ANSIImage.prototype.stop = function() {
if (!this.img) return;
return this.img.stop();
};
ANSIImage.prototype.clearImage = function() {
this.stop();
this.setContent('');
this.img = null;
this.cellmap = null;
};
ANSIImage.prototype.render = function() {
var coords = this._render();
if (!coords) return;
if (this.img && this.cellmap) {
this.img.renderElement(this.cellmap, this);
}
return coords;
};
/**
* Expose
*/
module.exports = ANSIImage;

159
lib/widgets/bigtext.js Normal file
View File

@ -0,0 +1,159 @@
/**
* bigtext.js - bigtext element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var fs = require('fs');
var Node = require('./node');
var Box = require('./box');
/**
* BigText
*/
function BigText(options) {
if (!(this instanceof Node)) {
return new BigText(options);
}
options = options || {};
options.font = options.font
|| __dirname + '/../../usr/fonts/ter-u14n.json';
options.fontBold = options.font
|| __dirname + '/../../usr/fonts/ter-u14b.json';
this.fch = options.fch;
this.ratio = {};
this.font = this.loadFont(options.font);
this.fontBold = this.loadFont(options.font);
Box.call(this, options);
if (this.style.bold) {
this.font = this.fontBold;
}
}
BigText.prototype.__proto__ = Box.prototype;
BigText.prototype.type = 'bigtext';
BigText.prototype.loadFont = function(filename) {
var self = this
, data
, font;
data = JSON.parse(fs.readFileSync(filename, 'utf8'));
this.ratio.width = data.width;
this.ratio.height = data.height;
function convertLetter(ch, lines) {
var line, i;
while (lines.length > self.ratio.height) {
lines.shift();
lines.pop();
}
lines = lines.map(function(line) {
var chs = line.split('');
chs = chs.map(function(ch) {
return ch === ' ' ? 0 : 1;
});
while (chs.length < self.ratio.width) {
chs.push(0);
}
return chs;
});
while (lines.length < self.ratio.height) {
line = [];
for (i = 0; i < self.ratio.width; i++) {
line.push(0);
}
lines.push(line);
}
return lines;
}
font = Object.keys(data.glyphs).reduce(function(out, ch) {
var lines = data.glyphs[ch].map;
out[ch] = convertLetter(ch, lines);
return out;
}, {});
delete font[' '];
return font;
};
BigText.prototype.setContent = function(content) {
this.content = '';
this.text = content || '';
};
BigText.prototype.render = function() {
if (this.position.width == null || this._shrinkWidth) {
// if (this.width - this.iwidth < this.ratio.width * this.text.length + 1) {
this.position.width = this.ratio.width * this.text.length + 1;
this._shrinkWidth = true;
// }
}
if (this.position.height == null || this._shrinkHeight) {
// if (this.height - this.iheight < this.ratio.height + 0) {
this.position.height = this.ratio.height + 0;
this._shrinkHeight = true;
// }
}
var coords = this._render();
if (!coords) return;
var lines = this.screen.lines
, left = coords.xi + this.ileft
, top = coords.yi + this.itop
, right = coords.xl - this.iright
, bottom = coords.yl - this.ibottom;
var dattr = this.sattr(this.style)
, bg = dattr & 0x1ff
, fg = (dattr >> 9) & 0x1ff
, flags = (dattr >> 18) & 0x1ff
, attr = (flags << 18) | (bg << 9) | fg;
for (var x = left, i = 0; x < right; x += this.ratio.width, i++) {
var ch = this.text[i];
if (!ch) break;
var map = this.font[ch];
if (!map) continue;
for (var y = top; y < Math.min(bottom, top + this.ratio.height); y++) {
if (!lines[y]) continue;
var mline = map[y - top];
if (!mline) continue;
for (var mx = 0; mx < this.ratio.width; mx++) {
var mcell = mline[mx];
if (mcell == null) break;
if (this.fch && this.fch !== ' ') {
lines[y][x + mx][0] = dattr;
lines[y][x + mx][1] = mcell === 1 ? this.fch : this.ch;
} else {
lines[y][x + mx][0] = mcell === 1 ? attr : dattr;
lines[y][x + mx][1] = mcell === 1 ? ' ' : this.ch;
}
}
lines[y].dirty = true;
}
}
return coords;
};
/**
* Expose
*/
module.exports = BigText;

34
lib/widgets/box.js Normal file
View File

@ -0,0 +1,34 @@
/**
* box.js - box element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Element = require('./element');
/**
* Box
*/
function Box(options) {
if (!(this instanceof Node)) {
return new Box(options);
}
options = options || {};
Element.call(this, options);
}
Box.prototype.__proto__ = Element.prototype;
Box.prototype.type = 'box';
/**
* Expose
*/
module.exports = Box;

62
lib/widgets/button.js Normal file
View File

@ -0,0 +1,62 @@
/**
* button.js - button element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Input = require('./input');
/**
* Button
*/
function Button(options) {
var self = this;
if (!(this instanceof Node)) {
return new Button(options);
}
options = options || {};
if (options.autoFocus == null) {
options.autoFocus = false;
}
Input.call(this, options);
this.on('keypress', function(ch, key) {
if (key.name === 'enter' || key.name === 'space') {
return self.press();
}
});
if (this.options.mouse) {
this.on('click', function() {
return self.press();
});
}
}
Button.prototype.__proto__ = Input.prototype;
Button.prototype.type = 'button';
Button.prototype.press = function() {
this.focus();
this.value = true;
var result = this.emit('press');
delete this.value;
return result;
};
/**
* Expose
*/
module.exports = Button;

91
lib/widgets/checkbox.js Normal file
View File

@ -0,0 +1,91 @@
/**
* checkbox.js - checkbox element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Input = require('./input');
/**
* Checkbox
*/
function Checkbox(options) {
var self = this;
if (!(this instanceof Node)) {
return new Checkbox(options);
}
options = options || {};
Input.call(this, options);
this.text = options.content || options.text || '';
this.checked = this.value = options.checked || false;
this.on('keypress', function(ch, key) {
if (key.name === 'enter' || key.name === 'space') {
self.toggle();
self.screen.render();
}
});
if (options.mouse) {
this.on('click', function() {
self.toggle();
self.screen.render();
});
}
this.on('focus', function() {
var lpos = self.lpos;
if (!lpos) return;
self.screen.program.lsaveCursor('checkbox');
self.screen.program.cup(lpos.yi, lpos.xi + 1);
self.screen.program.showCursor();
});
this.on('blur', function() {
self.screen.program.lrestoreCursor('checkbox', true);
});
}
Checkbox.prototype.__proto__ = Input.prototype;
Checkbox.prototype.type = 'checkbox';
Checkbox.prototype.render = function() {
this.clearPos(true);
this.setContent('[' + (this.checked ? 'x' : ' ') + '] ' + this.text, true);
return this._render();
};
Checkbox.prototype.check = function() {
if (this.checked) return;
this.checked = this.value = true;
this.emit('check');
};
Checkbox.prototype.uncheck = function() {
if (!this.checked) return;
this.checked = this.value = false;
this.emit('uncheck');
};
Checkbox.prototype.toggle = function() {
return this.checked
? this.uncheck()
: this.check();
};
/**
* Expose
*/
module.exports = Checkbox;

2570
lib/widgets/element.js Normal file

File diff suppressed because it is too large Load Diff

212
lib/widgets/filemanager.js Normal file
View File

@ -0,0 +1,212 @@
/**
* filemanager.js - file manager element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var path = require('path')
, fs = require('fs');
var helpers = require('../helpers');
var Node = require('./node');
var List = require('./list');
/**
* FileManager
*/
function FileManager(options) {
var self = this;
if (!(this instanceof Node)) {
return new FileManager(options);
}
options = options || {};
options.parseTags = true;
// options.label = ' {blue-fg}%path{/blue-fg} ';
List.call(this, options);
this.cwd = options.cwd || process.cwd();
this.file = this.cwd;
this.value = this.cwd;
if (options.label && ~options.label.indexOf('%path')) {
this._label.setContent(options.label.replace('%path', this.cwd));
}
this.on('select', function(item) {
var value = item.content.replace(/\{[^{}]+\}/g, '').replace(/@$/, '')
, file = path.resolve(self.cwd, value);
return fs.stat(file, function(err, stat) {
if (err) {
return self.emit('error', err, file);
}
self.file = file;
self.value = file;
if (stat.isDirectory()) {
self.emit('cd', file, self.cwd);
self.cwd = file;
if (options.label && ~options.label.indexOf('%path')) {
self._label.setContent(options.label.replace('%path', file));
}
self.refresh();
} else {
self.emit('file', file);
}
});
});
}
FileManager.prototype.__proto__ = List.prototype;
FileManager.prototype.type = 'file-manager';
FileManager.prototype.refresh = function(cwd, callback) {
if (!callback) {
callback = cwd;
cwd = null;
}
var self = this;
if (cwd) this.cwd = cwd;
else cwd = this.cwd;
return fs.readdir(cwd, function(err, list) {
if (err && err.code === 'ENOENT') {
self.cwd = cwd !== process.env.HOME
? process.env.HOME
: '/';
return self.refresh(callback);
}
if (err) {
if (callback) return callback(err);
return self.emit('error', err, cwd);
}
var dirs = []
, files = [];
list.unshift('..');
list.forEach(function(name) {
var f = path.resolve(cwd, name)
, stat;
try {
stat = fs.lstatSync(f);
} catch (e) {
;
}
if ((stat && stat.isDirectory()) || name === '..') {
dirs.push({
name: name,
text: '{light-blue-fg}' + name + '{/light-blue-fg}/',
dir: true
});
} else if (stat && stat.isSymbolicLink()) {
files.push({
name: name,
text: '{light-cyan-fg}' + name + '{/light-cyan-fg}@',
dir: false
});
} else {
files.push({
name: name,
text: name,
dir: false
});
}
});
dirs = helpers.asort(dirs);
files = helpers.asort(files);
list = dirs.concat(files).map(function(data) {
return data.text;
});
self.setItems(list);
self.select(0);
self.screen.render();
self.emit('refresh');
if (callback) callback();
});
};
FileManager.prototype.pick = function(cwd, callback) {
if (!callback) {
callback = cwd;
cwd = null;
}
var self = this
, focused = this.screen.focused === this
, hidden = this.hidden
, onfile
, oncancel;
function resume() {
self.removeListener('file', onfile);
self.removeListener('cancel', oncancel);
if (hidden) {
self.hide();
}
if (!focused) {
self.screen.restoreFocus();
}
self.screen.render();
}
this.on('file', onfile = function(file) {
resume();
return callback(null, file);
});
this.on('cancel', oncancel = function() {
resume();
return callback();
});
this.refresh(cwd, function(err) {
if (err) return callback(err);
if (hidden) {
self.show();
}
if (!focused) {
self.screen.saveFocus();
self.focus();
}
self.screen.render();
});
};
FileManager.prototype.reset = function(cwd, callback) {
if (!callback) {
callback = cwd;
cwd = null;
}
this.cwd = cwd || this.options.cwd;
this.refresh(callback);
};
/**
* Expose
*/
module.exports = FileManager;

267
lib/widgets/form.js Normal file
View File

@ -0,0 +1,267 @@
/**
* form.js - form element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Form
*/
function Form(options) {
var self = this;
if (!(this instanceof Node)) {
return new Form(options);
}
options = options || {};
options.ignoreKeys = true;
Box.call(this, options);
if (options.keys) {
this.screen._listenKeys(this);
this.on('element keypress', function(el, ch, key) {
if ((key.name === 'tab' && !key.shift)
|| (el.type === 'textbox' && options.autoNext && key.name === 'enter')
|| key.name === 'down'
|| (options.vi && key.name === 'j')) {
if (el.type === 'textbox' || el.type === 'textarea') {
if (key.name === 'j') return;
if (key.name === 'tab') {
// Workaround, since we can't stop the tab from being added.
el.emit('keypress', null, { name: 'backspace' });
}
el.emit('keypress', '\x1b', { name: 'escape' });
}
self.focusNext();
return;
}
if ((key.name === 'tab' && key.shift)
|| key.name === 'up'
|| (options.vi && key.name === 'k')) {
if (el.type === 'textbox' || el.type === 'textarea') {
if (key.name === 'k') return;
el.emit('keypress', '\x1b', { name: 'escape' });
}
self.focusPrevious();
return;
}
if (key.name === 'escape') {
self.focus();
return;
}
});
}
}
Form.prototype.__proto__ = Box.prototype;
Form.prototype.type = 'form';
Form.prototype._refresh = function() {
// XXX Possibly remove this if statement and refresh on every focus.
// Also potentially only include *visible* focusable elements.
// This would remove the need to check for _selected.visible in previous()
// and next().
if (!this._children) {
var out = [];
this.children.forEach(function fn(el) {
if (el.keyable) out.push(el);
el.children.forEach(fn);
});
this._children = out;
}
};
Form.prototype._visible = function() {
return !!this._children.filter(function(el) {
return el.visible;
}).length;
};
Form.prototype.next = function() {
this._refresh();
if (!this._visible()) return;
if (!this._selected) {
this._selected = this._children[0];
if (!this._selected.visible) return this.next();
if (this.screen.focused !== this._selected) return this._selected;
}
var i = this._children.indexOf(this._selected);
if (!~i || !this._children[i + 1]) {
this._selected = this._children[0];
if (!this._selected.visible) return this.next();
return this._selected;
}
this._selected = this._children[i + 1];
if (!this._selected.visible) return this.next();
return this._selected;
};
Form.prototype.previous = function() {
this._refresh();
if (!this._visible()) return;
if (!this._selected) {
this._selected = this._children[this._children.length - 1];
if (!this._selected.visible) return this.previous();
if (this.screen.focused !== this._selected) return this._selected;
}
var i = this._children.indexOf(this._selected);
if (!~i || !this._children[i - 1]) {
this._selected = this._children[this._children.length - 1];
if (!this._selected.visible) return this.previous();
return this._selected;
}
this._selected = this._children[i - 1];
if (!this._selected.visible) return this.previous();
return this._selected;
};
Form.prototype.focusNext = function() {
var next = this.next();
if (next) next.focus();
};
Form.prototype.focusPrevious = function() {
var previous = this.previous();
if (previous) previous.focus();
};
Form.prototype.resetSelected = function() {
this._selected = null;
};
Form.prototype.focusFirst = function() {
this.resetSelected();
this.focusNext();
};
Form.prototype.focusLast = function() {
this.resetSelected();
this.focusPrevious();
};
Form.prototype.submit = function() {
var out = {};
this.children.forEach(function fn(el) {
if (el.value != null) {
var name = el.name || el.type;
if (Array.isArray(out[name])) {
out[name].push(el.value);
} else if (out[name]) {
out[name] = [out[name], el.value];
} else {
out[name] = el.value;
}
}
el.children.forEach(fn);
});
this.emit('submit', out);
return this.submission = out;
};
Form.prototype.cancel = function() {
this.emit('cancel');
};
Form.prototype.reset = function() {
this.children.forEach(function fn(el) {
switch (el.type) {
case 'screen':
break;
case 'box':
break;
case 'text':
break;
case 'line':
break;
case 'scrollable-box':
break;
case 'list':
el.select(0);
return;
case 'form':
break;
case 'input':
break;
case 'textbox':
el.clearInput();
return;
case 'textarea':
el.clearInput();
return;
case 'button':
delete el.value;
break;
case 'progress-bar':
el.setProgress(0);
break;
case 'file-manager':
el.refresh(el.options.cwd);
return;
case 'checkbox':
el.uncheck();
return;
case 'radio-set':
break;
case 'radio-button':
el.uncheck();
return;
case 'prompt':
break;
case 'question':
break;
case 'message':
break;
case 'info':
break;
case 'loading':
break;
case 'list-bar':
//el.select(0);
break;
case 'dir-manager':
el.refresh(el.options.cwd);
return;
case 'terminal':
el.write('');
return;
case 'image':
//el.clearImage();
return;
}
el.children.forEach(fn);
});
this.emit('reset');
};
/**
* Expose
*/
module.exports = Form;

61
lib/widgets/image.js Normal file
View File

@ -0,0 +1,61 @@
/**
* image.js - image element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Image
*/
function Image(options) {
if (!(this instanceof Node)) {
return new Image(options);
}
options = options || {};
options.type = options.itype || options.type || 'ansi';
Box.call(this, options);
if (options.type === 'ansi' && this.type !== 'ansiimage') {
var ANSIImage = require('./ansiimage');
Object.getOwnPropertyNames(ANSIImage.prototype).forEach(function(key) {
if (key === 'type') return;
Object.defineProperty(this, key,
Object.getOwnPropertyDescriptor(ANSIImage.prototype, key));
}, this);
ANSIImage.call(this, options);
return this;
}
if (options.type === 'overlay' && this.type !== 'overlayimage') {
var OverlayImage = require('./overlayimage');
Object.getOwnPropertyNames(OverlayImage.prototype).forEach(function(key) {
if (key === 'type') return;
Object.defineProperty(this, key,
Object.getOwnPropertyDescriptor(OverlayImage.prototype, key));
}, this);
OverlayImage.call(this, options);
return this;
}
throw new Error('`type` must either be `ansi` or `overlay`.');
}
Image.prototype.__proto__ = Box.prototype;
Image.prototype.type = 'image';
/**
* Expose
*/
module.exports = Image;

34
lib/widgets/input.js Normal file
View File

@ -0,0 +1,34 @@
/**
* input.js - abstract input element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Input
*/
function Input(options) {
if (!(this instanceof Node)) {
return new Input(options);
}
options = options || {};
Box.call(this, options);
}
Input.prototype.__proto__ = Box.prototype;
Input.prototype.type = 'input';
/**
* Expose
*/
module.exports = Input;

233
lib/widgets/layout.js Normal file
View File

@ -0,0 +1,233 @@
/**
* layout.js - layout element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Element = require('./element');
/**
* Layout
*/
function Layout(options) {
if (!(this instanceof Node)) {
return new Layout(options);
}
options = options || {};
if ((options.width == null
&& (options.left == null && options.right == null))
|| (options.height == null
&& (options.top == null && options.bottom == null))) {
throw new Error('`Layout` must have a width and height!');
}
options.layout = options.layout || 'inline';
Element.call(this, options);
if (options.renderer) {
this.renderer = options.renderer;
}
}
Layout.prototype.__proto__ = Element.prototype;
Layout.prototype.type = 'layout';
Layout.prototype.isRendered = function(el) {
if (!el.lpos) return false;
return (el.lpos.xl - el.lpos.xi) > 0
&& (el.lpos.yl - el.lpos.yi) > 0;
};
Layout.prototype.getLast = function(i) {
while (this.children[--i]) {
var el = this.children[i];
if (this.isRendered(el)) return el;
}
};
Layout.prototype.getLastCoords = function(i) {
var last = this.getLast(i);
if (last) return last.lpos;
};
Layout.prototype._renderCoords = function() {
var coords = this._getCoords(true);
var children = this.children;
this.children = [];
this._render();
this.children = children;
return coords;
};
Layout.prototype.renderer = function(coords) {
var self = this;
// The coordinates of the layout element
var width = coords.xl - coords.xi
, height = coords.yl - coords.yi
, xi = coords.xi
, yi = coords.yi;
// The current row offset in cells (which row are we on?)
var rowOffset = 0;
// The index of the first child in the row
var rowIndex = 0;
var lastRowIndex = 0;
// Figure out the highest width child
if (this.options.layout === 'grid') {
var highWidth = this.children.reduce(function(out, el) {
out = Math.max(out, el.width);
return out;
}, 0);
}
return function iterator(el, i) {
// Make our children shrinkable. If they don't have a height, for
// example, calculate it for them.
el.shrink = true;
// Find the previous rendered child's coordinates
var last = self.getLast(i);
// If there is no previously rendered element, we are on the first child.
if (!last) {
el.position.left = 0;
el.position.top = 0;
} else {
// Otherwise, figure out where to place this child. We'll start by
// setting it's `left`/`x` coordinate to right after the previous
// rendered element. This child will end up directly to the right of it.
el.position.left = last.lpos.xl - xi;
// Make sure the position matches the highest width element
if (self.options.layout === 'grid') {
// Compensate with width:
// el.position.width = el.width + (highWidth - el.width);
// Compensate with position:
el.position.left += highWidth - (last.lpos.xl - last.lpos.xi);
}
// If our child does not overlap the right side of the Layout, set it's
// `top`/`y` to the current `rowOffset` (the coordinate for the current
// row).
if (el.position.left + el.width <= width) {
el.position.top = rowOffset;
} else {
// Otherwise we need to start a new row and calculate a new
// `rowOffset` and `rowIndex` (the index of the child on the current
// row).
rowOffset += self.children.slice(rowIndex, i).reduce(function(out, el) {
if (!self.isRendered(el)) return out;
out = Math.max(out, el.lpos.yl - el.lpos.yi);
return out;
}, 0);
lastRowIndex = rowIndex;
rowIndex = i;
el.position.left = 0;
el.position.top = rowOffset;
}
}
// Make sure the elements on lower rows graviatate up as much as possible
if (self.options.layout === 'inline') {
var above = null;
var abovea = Infinity;
for (var j = lastRowIndex; j < rowIndex; j++) {
var l = self.children[j];
if (!self.isRendered(l)) continue;
var abs = Math.abs(el.position.left - (l.lpos.xi - xi));
// if (abs < abovea && (l.lpos.xl - l.lpos.xi) <= el.width) {
if (abs < abovea) {
above = l;
abovea = abs;
}
}
if (above) {
el.position.top = above.lpos.yl - yi;
}
}
// If our child overflows the Layout, do not render it!
// Disable this feature for now.
if (el.position.top + el.height > height) {
// Returning false tells blessed to ignore this child.
// return false;
}
};
};
Layout.prototype.render = function() {
this._emit('prerender');
var coords = this._renderCoords();
if (!coords) {
delete this.lpos;
return;
}
if (coords.xl - coords.xi <= 0) {
coords.xl = Math.max(coords.xl, coords.xi);
return;
}
if (coords.yl - coords.yi <= 0) {
coords.yl = Math.max(coords.yl, coords.yi);
return;
}
this.lpos = coords;
if (this.border) coords.xi++, coords.xl--, coords.yi++, coords.yl--;
if (this.tpadding) {
coords.xi += this.padding.left, coords.xl -= this.padding.right;
coords.yi += this.padding.top, coords.yl -= this.padding.bottom;
}
var iterator = this.renderer(coords);
if (this.border) coords.xi--, coords.xl++, coords.yi--, coords.yl++;
if (this.tpadding) {
coords.xi -= this.padding.left, coords.xl += this.padding.right;
coords.yi -= this.padding.top, coords.yl += this.padding.bottom;
}
this.children.forEach(function(el, i) {
if (el.screen._ci !== -1) {
el.index = el.screen._ci++;
}
var rendered = iterator(el, i);
if (rendered === false) {
delete el.lpos;
return;
}
// if (el.screen._rendering) {
// el._rendering = true;
// }
el.render();
// if (el.screen._rendering) {
// el._rendering = false;
// }
});
this._emit('render', [coords]);
return coords;
};
/**
* Expose
*/
module.exports = Layout;

56
lib/widgets/line.js Normal file
View File

@ -0,0 +1,56 @@
/**
* line.js - line element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Line
*/
function Line(options) {
if (!(this instanceof Node)) {
return new Line(options);
}
options = options || {};
var orientation = options.orientation || 'vertical';
delete options.orientation;
if (orientation === 'vertical') {
options.width = 1;
} else {
options.height = 1;
}
Box.call(this, options);
this.ch = !options.type || options.type === 'line'
? orientation === 'horizontal' ? '─' : '│'
: options.ch || ' ';
this.border = {
type: 'bg',
__proto__: this
};
this.style.border = this.style;
}
Line.prototype.__proto__ = Box.prototype;
Line.prototype.type = 'line';
/**
* Expose
*/
module.exports = Line;

599
lib/widgets/list.js Normal file
View File

@ -0,0 +1,599 @@
/**
* list.js - list element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var helpers = require('../helpers');
var Node = require('./node');
var Box = require('./box');
/**
* List
*/
function List(options) {
var self = this;
if (!(this instanceof Node)) {
return new List(options);
}
options = options || {};
options.ignoreKeys = true;
// Possibly put this here: this.items = [];
options.scrollable = true;
Box.call(this, options);
this.value = '';
this.items = [];
this.ritems = [];
this.selected = 0;
this._isList = true;
if (!this.style.selected) {
this.style.selected = {};
this.style.selected.bg = options.selectedBg;
this.style.selected.fg = options.selectedFg;
this.style.selected.bold = options.selectedBold;
this.style.selected.underline = options.selectedUnderline;
this.style.selected.blink = options.selectedBlink;
this.style.selected.inverse = options.selectedInverse;
this.style.selected.invisible = options.selectedInvisible;
}
if (!this.style.item) {
this.style.item = {};
this.style.item.bg = options.itemBg;
this.style.item.fg = options.itemFg;
this.style.item.bold = options.itemBold;
this.style.item.underline = options.itemUnderline;
this.style.item.blink = options.itemBlink;
this.style.item.inverse = options.itemInverse;
this.style.item.invisible = options.itemInvisible;
}
// Legacy: for apps written before the addition of item attributes.
['bg', 'fg', 'bold', 'underline',
'blink', 'inverse', 'invisible'].forEach(function(name) {
if (self.style[name] != null && self.style.item[name] == null) {
self.style.item[name] = self.style[name];
}
});
if (this.options.itemHoverBg) {
this.options.itemHoverEffects = { bg: this.options.itemHoverBg };
}
if (this.options.itemHoverEffects) {
this.style.item.hover = this.options.itemHoverEffects;
}
if (this.options.itemFocusEffects) {
this.style.item.focus = this.options.itemFocusEffects;
}
this.interactive = options.interactive !== false;
this.mouse = options.mouse || false;
if (options.items) {
this.ritems = options.items;
options.items.forEach(this.add.bind(this));
}
this.select(0);
if (options.mouse) {
this.screen._listenMouse(this);
this.on('element wheeldown', function() {
self.select(self.selected + 2);
self.screen.render();
});
this.on('element wheelup', function() {
self.select(self.selected - 2);
self.screen.render();
});
}
if (options.keys) {
this.on('keypress', function(ch, key) {
if (key.name === 'up' || (options.vi && key.name === 'k')) {
self.up();
self.screen.render();
return;
}
if (key.name === 'down' || (options.vi && key.name === 'j')) {
self.down();
self.screen.render();
return;
}
if (key.name === 'enter'
|| (options.vi && key.name === 'l' && !key.shift)) {
self.enterSelected();
return;
}
if (key.name === 'escape' || (options.vi && key.name === 'q')) {
self.cancelSelected();
return;
}
if (options.vi && key.name === 'u' && key.ctrl) {
self.move(-((self.height - self.iheight) / 2) | 0);
self.screen.render();
return;
}
if (options.vi && key.name === 'd' && key.ctrl) {
self.move((self.height - self.iheight) / 2 | 0);
self.screen.render();
return;
}
if (options.vi && key.name === 'b' && key.ctrl) {
self.move(-(self.height - self.iheight));
self.screen.render();
return;
}
if (options.vi && key.name === 'f' && key.ctrl) {
self.move(self.height - self.iheight);
self.screen.render();
return;
}
if (options.vi && key.name === 'h' && key.shift) {
self.move(self.childBase - self.selected);
self.screen.render();
return;
}
if (options.vi && key.name === 'm' && key.shift) {
// TODO: Maybe use Math.min(this.items.length,
// ... for calculating visible items elsewhere.
var visible = Math.min(
self.height - self.iheight,
self.items.length) / 2 | 0;
self.move(self.childBase + visible - self.selected);
self.screen.render();
return;
}
if (options.vi && key.name === 'l' && key.shift) {
// XXX This goes one too far on lists with an odd number of items.
self.down(self.childBase
+ Math.min(self.height - self.iheight, self.items.length)
- self.selected);
self.screen.render();
return;
}
if (options.vi && key.name === 'g' && !key.shift) {
self.select(0);
self.screen.render();
return;
}
if (options.vi && key.name === 'g' && key.shift) {
self.select(self.items.length - 1);
self.screen.render();
return;
}
if (options.vi && (key.ch === '/' || key.ch === '?')) {
if (typeof self.options.search !== 'function') {
return;
}
return self.options.search(function(err, value) {
if (typeof err === 'string' || typeof err === 'function'
|| typeof err === 'number' || (err && err.test)) {
value = err;
err = null;
}
if (err || !value) return self.screen.render();
self.select(self.fuzzyFind(value, key.ch === '?'));
self.screen.render();
});
}
});
}
this.on('resize', function() {
var visible = self.height - self.iheight;
// if (self.selected < visible - 1) {
if (visible >= self.selected + 1) {
self.childBase = 0;
self.childOffset = self.selected;
} else {
// Is this supposed to be: self.childBase = visible - self.selected + 1; ?
self.childBase = self.selected - visible + 1;
self.childOffset = visible - 1;
}
});
this.on('adopt', function(el) {
if (!~self.items.indexOf(el)) {
el.fixed = true;
}
});
// Ensure children are removed from the
// item list if they are items.
this.on('remove', function(el) {
self.removeItem(el);
});
}
List.prototype.__proto__ = Box.prototype;
List.prototype.type = 'list';
List.prototype.createItem = function(content) {
var self = this;
// Note: Could potentially use Button here.
var options = {
screen: this.screen,
content: content,
align: this.align || 'left',
top: 0,
left: 0,
right: (this.scrollbar ? 1 : 0),
tags: this.parseTags,
height: 1,
hoverEffects: this.mouse ? this.style.item.hover : null,
focusEffects: this.mouse ? this.style.item.focus : null,
autoFocus: false
};
if (!this.screen.autoPadding) {
options.top = 1;
options.left = this.ileft;
options.right = this.iright + (this.scrollbar ? 1 : 0);
}
// if (this.shrink) {
// XXX NOTE: Maybe just do this on all shrinkage once autoPadding is default?
if (this.shrink && this.options.normalShrink) {
delete options.right;
options.width = 'shrink';
}
['bg', 'fg', 'bold', 'underline',
'blink', 'inverse', 'invisible'].forEach(function(name) {
options[name] = function() {
var attr = self.items[self.selected] === item && self.interactive
? self.style.selected[name]
: self.style.item[name];
if (typeof attr === 'function') attr = attr(item);
return attr;
};
});
if (this.style.transparent) {
options.transparent = true;
}
var item = new Box(options);
if (this.mouse) {
item.on('click', function() {
self.focus();
if (self.items[self.selected] === item) {
self.emit('action', item, self.selected);
self.emit('select', item, self.selected);
return;
}
self.select(item);
self.screen.render();
});
}
this.emit('create item');
return item;
};
List.prototype.add =
List.prototype.addItem =
List.prototype.appendItem = function(content) {
content = typeof content === 'string' ? content : content.getContent();
var item = this.createItem(content);
item.position.top = this.items.length;
if (!this.screen.autoPadding) {
item.position.top = this.itop + this.items.length;
}
this.ritems.push(content);
this.items.push(item);
this.append(item);
if (this.items.length === 1) {
this.select(0);
}
this.emit('add item');
return item;
};
List.prototype.removeItem = function(child) {
var i = this.getItemIndex(child);
if (~i && this.items[i]) {
child = this.items.splice(i, 1)[0];
this.ritems.splice(i, 1);
this.remove(child);
for (var j = i; j < this.items.length; j++) {
this.items[j].position.top--;
}
if (i === this.selected) {
this.select(i - 1);
}
}
this.emit('remove item');
return child;
};
List.prototype.insertItem = function(child, content) {
content = typeof content === 'string' ? content : content.getContent();
var i = this.getItemIndex(child);
if (!~i) return;
if (i >= this.items.length) return this.appendItem(content);
var item = this.createItem(content);
for (var j = i; j < this.items.length; j++) {
this.items[j].position.top++;
}
item.position.top = i + (!this.screen.autoPadding ? 1 : 0);
this.ritems.splice(i, 0, content);
this.items.splice(i, 0, item);
this.append(item);
if (i === this.selected) {
this.select(i + 1);
}
this.emit('insert item');
};
List.prototype.getItem = function(child) {
return this.items[this.getItemIndex(child)];
};
List.prototype.setItem = function(child, content) {
content = typeof content === 'string' ? content : content.getContent();
var i = this.getItemIndex(child);
if (!~i) return;
this.items[i].setContent(content);
this.ritems[i] = content;
};
List.prototype.clearItems = function() {
return this.setItems([]);
};
List.prototype.setItems = function(items) {
var original = this.items.slice()
, selected = this.selected
, sel = this.ritems[this.selected]
, i = 0;
items = items.slice();
this.select(0);
for (; i < items.length; i++) {
if (this.items[i]) {
this.items[i].setContent(items[i]);
} else {
this.add(items[i]);
}
}
for (; i < original.length; i++) {
this.remove(original[i]);
}
this.ritems = items;
// Try to find our old item if it still exists.
sel = items.indexOf(sel);
if (~sel) {
this.select(sel);
} else if (items.length === original.length) {
this.select(selected);
} else {
this.select(Math.min(selected, items.length - 1));
}
this.emit('set items');
};
List.prototype.pushItem = function(content) {
this.appendItem(content);
return this.items.length;
};
List.prototype.popItem = function() {
return this.removeItem(this.items.length - 1);
};
List.prototype.unshiftItem = function(content) {
this.insertItem(0, content);
return this.items.length;
};
List.prototype.shiftItem = function() {
return this.removeItem(0);
};
List.prototype.spliceItem = function(child, n) {
var self = this;
var i = this.getItemIndex(child);
if (!~i) return;
var items = Array.prototype.slice.call(arguments, 2);
var removed = [];
while (n--) {
removed.push(this.removeItem(i));
}
items.forEach(function(item) {
self.insertItem(i++, item);
});
return removed;
};
List.prototype.find =
List.prototype.fuzzyFind = function(search, back) {
var start = this.selected + (back ? -1 : 1)
, i;
if (typeof search === 'number') search += '';
if (search && search[0] === '/' && search[search.length - 1] === '/') {
try {
search = new RegExp(search.slice(1, -1));
} catch (e) {
;
}
}
var test = typeof search === 'string'
? function(item) { return !!~item.indexOf(search); }
: (search.test ? search.test.bind(search) : search);
if (typeof test !== 'function') {
if (this.screen.options.debug) {
throw new Error('fuzzyFind(): `test` is not a function.');
}
return this.selected;
}
if (!back) {
for (i = start; i < this.ritems.length; i++) {
if (test(helpers.cleanTags(this.ritems[i]))) return i;
}
for (i = 0; i < start; i++) {
if (test(helpers.cleanTags(this.ritems[i]))) return i;
}
} else {
for (i = start; i >= 0; i--) {
if (test(helpers.cleanTags(this.ritems[i]))) return i;
}
for (i = this.ritems.length - 1; i > start; i--) {
if (test(helpers.cleanTags(this.ritems[i]))) return i;
}
}
return this.selected;
};
List.prototype.getItemIndex = function(child) {
if (typeof child === 'number') {
return child;
} else if (typeof child === 'string') {
var i = this.ritems.indexOf(child);
if (~i) return i;
for (i = 0; i < this.ritems.length; i++) {
if (helpers.cleanTags(this.ritems[i]) === child) {
return i;
}
}
return -1;
} else {
return this.items.indexOf(child);
}
};
List.prototype.select = function(index) {
if (!this.interactive) {
return;
}
if (!this.items.length) {
this.selected = 0;
this.value = '';
this.scrollTo(0);
return;
}
if (typeof index === 'object') {
index = this.items.indexOf(index);
}
if (index < 0) {
index = 0;
} else if (index >= this.items.length) {
index = this.items.length - 1;
}
if (this.selected === index && this._listInitialized) return;
this._listInitialized = true;
this.selected = index;
this.value = helpers.cleanTags(this.ritems[this.selected]);
if (!this.parent) return;
this.scrollTo(this.selected);
// XXX Move `action` and `select` events here.
this.emit('select item', this.items[this.selected], this.selected);
};
List.prototype.move = function(offset) {
this.select(this.selected + offset);
};
List.prototype.up = function(offset) {
this.move(-(offset || 1));
};
List.prototype.down = function(offset) {
this.move(offset || 1);
};
List.prototype.pick = function(label, callback) {
if (!callback) {
callback = label;
label = null;
}
if (!this.interactive) {
return callback();
}
var self = this;
var focused = this.screen.focused;
if (focused && focused._done) focused._done('stop');
this.screen.saveFocus();
// XXX Keep above:
// var parent = this.parent;
// this.detach();
// parent.append(this);
this.focus();
this.show();
this.select(0);
if (label) this.setLabel(label);
this.screen.render();
this.once('action', function(el, selected) {
if (label) self.removeLabel();
self.screen.restoreFocus();
self.hide();
self.screen.render();
if (!el) return callback();
return callback(null, helpers.cleanTags(self.ritems[selected]));
});
};
List.prototype.enterSelected = function(i) {
if (i != null) this.select(i);
this.emit('action', this.items[this.selected], this.selected);
this.emit('select', this.items[this.selected], this.selected);
};
List.prototype.cancelSelected = function(i) {
if (i != null) this.select(i);
this.emit('action');
this.emit('cancel');
};
/**
* Expose
*/
module.exports = List;

411
lib/widgets/listbar.js Normal file
View File

@ -0,0 +1,411 @@
/**
* listbar.js - listbar element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var helpers = require('../helpers');
var Node = require('./node');
var Box = require('./box');
/**
* Listbar / HorizontalList
*/
function Listbar(options) {
var self = this;
if (!(this instanceof Node)) {
return new Listbar(options);
}
options = options || {};
this.items = [];
this.ritems = [];
this.commands = [];
this.leftBase = 0;
this.leftOffset = 0;
this.mouse = options.mouse || false;
Box.call(this, options);
if (!this.style.selected) {
this.style.selected = {};
}
if (!this.style.item) {
this.style.item = {};
}
if (options.commands || options.items) {
this.setItems(options.commands || options.items);
}
if (options.keys) {
this.on('keypress', function(ch, key) {
if (key.name === 'left'
|| (options.vi && key.name === 'h')
|| (key.shift && key.name === 'tab')) {
self.moveLeft();
self.screen.render();
// Stop propagation if we're in a form.
if (key.name === 'tab') return false;
return;
}
if (key.name === 'right'
|| (options.vi && key.name === 'l')
|| key.name === 'tab') {
self.moveRight();
self.screen.render();
// Stop propagation if we're in a form.
if (key.name === 'tab') return false;
return;
}
if (key.name === 'enter'
|| (options.vi && key.name === 'k' && !key.shift)) {
self.emit('action', self.items[self.selected], self.selected);
self.emit('select', self.items[self.selected], self.selected);
var item = self.items[self.selected];
if (item._.cmd.callback) {
item._.cmd.callback();
}
self.screen.render();
return;
}
if (key.name === 'escape' || (options.vi && key.name === 'q')) {
self.emit('action');
self.emit('cancel');
return;
}
});
}
if (options.autoCommandKeys) {
this.onScreenEvent('keypress', function(ch) {
if (/^[0-9]$/.test(ch)) {
var i = +ch - 1;
if (!~i) i = 9;
return self.selectTab(i);
}
});
}
this.on('focus', function() {
self.select(self.selected);
});
}
Listbar.prototype.__proto__ = Box.prototype;
Listbar.prototype.type = 'listbar';
Listbar.prototype.__defineGetter__('selected', function() {
return this.leftBase + this.leftOffset;
});
Listbar.prototype.setItems = function(commands) {
var self = this;
if (!Array.isArray(commands)) {
commands = Object.keys(commands).reduce(function(obj, key, i) {
var cmd = commands[key]
, cb;
if (typeof cmd === 'function') {
cb = cmd;
cmd = { callback: cb };
}
if (cmd.text == null) cmd.text = key;
if (cmd.prefix == null) cmd.prefix = ++i + '';
if (cmd.text == null && cmd.callback) {
cmd.text = cmd.callback.name;
}
obj.push(cmd);
return obj;
}, []);
}
this.items.forEach(function(el) {
el.detach();
});
this.items = [];
this.ritems = [];
this.commands = [];
commands.forEach(function(cmd) {
self.add(cmd);
});
this.emit('set items');
};
Listbar.prototype.add =
Listbar.prototype.addItem =
Listbar.prototype.appendItem = function(item, callback) {
var self = this
, prev = this.items[this.items.length - 1]
, drawn
, cmd
, title
, len;
if (!this.parent) {
drawn = 0;
} else {
drawn = prev ? prev.aleft + prev.width : 0;
if (!this.screen.autoPadding) {
drawn += this.ileft;
}
}
if (typeof item === 'object') {
cmd = item;
if (cmd.prefix == null) cmd.prefix = (this.items.length + 1) + '';
}
if (typeof item === 'string') {
cmd = {
prefix: (this.items.length + 1) + '',
text: item,
callback: callback
};
}
if (typeof item === 'function') {
cmd = {
prefix: (this.items.length + 1) + '',
text: item.name,
callback: item
};
}
if (cmd.keys && cmd.keys[0]) {
cmd.prefix = cmd.keys[0];
}
var t = helpers.generateTags(this.style.prefix || { fg: 'lightblack' });
title = (cmd.prefix != null ? t.open + cmd.prefix + t.close + ':' : '') + cmd.text;
len = ((cmd.prefix != null ? cmd.prefix + ':' : '') + cmd.text).length;
var options = {
screen: this.screen,
top: 0,
left: drawn + 1,
height: 1,
content: title,
width: len + 2,
align: 'center',
autoFocus: false,
tags: true,
mouse: true,
style: helpers.merge({}, this.style.item),
noOverflow: true
};
if (!this.screen.autoPadding) {
options.top += this.itop;
options.left += this.ileft;
}
['bg', 'fg', 'bold', 'underline',
'blink', 'inverse', 'invisible'].forEach(function(name) {
options.style[name] = function() {
var attr = self.items[self.selected] === el
? self.style.selected[name]
: self.style.item[name];
if (typeof attr === 'function') attr = attr(el);
return attr;
};
});
var el = new Box(options);
this._[cmd.text] = el;
cmd.element = el;
el._.cmd = cmd;
this.ritems.push(cmd.text);
this.items.push(el);
this.commands.push(cmd);
this.append(el);
if (cmd.callback) {
if (cmd.keys) {
this.screen.key(cmd.keys, function() {
self.emit('action', el, self.selected);
self.emit('select', el, self.selected);
if (el._.cmd.callback) {
el._.cmd.callback();
}
self.select(el);
self.screen.render();
});
}
}
if (this.items.length === 1) {
this.select(0);
}
// XXX May be affected by new element.options.mouse option.
if (this.mouse) {
el.on('click', function() {
self.emit('action', el, self.selected);
self.emit('select', el, self.selected);
if (el._.cmd.callback) {
el._.cmd.callback();
}
self.select(el);
self.screen.render();
});
}
this.emit('add item');
};
Listbar.prototype.render = function() {
var self = this
, drawn = 0;
if (!this.screen.autoPadding) {
drawn += this.ileft;
}
this.items.forEach(function(el, i) {
if (i < self.leftBase) {
el.hide();
} else {
el.rleft = drawn + 1;
drawn += el.width + 2;
el.show();
}
});
return this._render();
};
Listbar.prototype.select = function(offset) {
if (typeof offset !== 'number') {
offset = this.items.indexOf(offset);
}
if (offset < 0) {
offset = 0;
} else if (offset >= this.items.length) {
offset = this.items.length - 1;
}
if (!this.parent) {
this.emit('select item', this.items[offset], offset);
return;
}
var lpos = this._getCoords();
if (!lpos) return;
var self = this
, width = (lpos.xl - lpos.xi) - this.iwidth
, drawn = 0
, visible = 0
, el;
el = this.items[offset];
if (!el) return;
this.items.forEach(function(el, i) {
if (i < self.leftBase) return;
var lpos = el._getCoords();
if (!lpos) return;
if (lpos.xl - lpos.xi <= 0) return;
drawn += (lpos.xl - lpos.xi) + 2;
if (drawn <= width) visible++;
});
var diff = offset - (this.leftBase + this.leftOffset);
if (offset > this.leftBase + this.leftOffset) {
if (offset > this.leftBase + visible - 1) {
this.leftOffset = 0;
this.leftBase = offset;
} else {
this.leftOffset += diff;
}
} else if (offset < this.leftBase + this.leftOffset) {
diff = -diff;
if (offset < this.leftBase) {
this.leftOffset = 0;
this.leftBase = offset;
} else {
this.leftOffset -= diff;
}
}
// XXX Move `action` and `select` events here.
this.emit('select item', el, offset);
};
Listbar.prototype.removeItem = function(child) {
var i = typeof child !== 'number'
? this.items.indexOf(child)
: child;
if (~i && this.items[i]) {
child = this.items.splice(i, 1)[0];
this.ritems.splice(i, 1);
this.commands.splice(i, 1);
this.remove(child);
if (i === this.selected) {
this.select(i - 1);
}
}
this.emit('remove item');
};
Listbar.prototype.move = function(offset) {
this.select(this.selected + offset);
};
Listbar.prototype.moveLeft = function(offset) {
this.move(-(offset || 1));
};
Listbar.prototype.moveRight = function(offset) {
this.move(offset || 1);
};
Listbar.prototype.selectTab = function(index) {
var item = this.items[index];
if (item) {
if (item._.cmd.callback) {
item._.cmd.callback();
}
this.select(index);
this.screen.render();
}
this.emit('select tab', item, index);
};
/**
* Expose
*/
module.exports = Listbar;

280
lib/widgets/listtable.js Normal file
View File

@ -0,0 +1,280 @@
/**
* listtable.js - list table element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
var List = require('./list');
var Table = require('./table');
/**
* ListTable
*/
function ListTable(options) {
var self = this;
if (!(this instanceof Node)) {
return new ListTable(options);
}
options = options || {};
// options.shrink = true;
options.normalShrink = true;
options.style = options.style || {};
options.style.border = options.style.border || {};
options.style.header = options.style.header || {};
options.style.cell = options.style.cell || {};
this.__align = options.align || 'center';
delete options.align;
options.style.selected = options.style.cell.selected;
options.style.item = options.style.cell;
var border = options.border;
if (border
&& border.top === false
&& border.bottom === false
&& border.left === false
&& border.right === false) {
delete options.border;
}
List.call(this, options);
options.border = border;
this._header = new Box({
parent: this,
left: this.screen.autoPadding ? 0 : this.ileft,
top: 0,
width: 'shrink',
height: 1,
style: options.style.header,
tags: options.parseTags || options.tags
});
this.on('scroll', function() {
self._header.setFront();
self._header.rtop = self.childBase;
if (!self.screen.autoPadding) {
self._header.rtop = self.childBase + (self.border ? 1 : 0);
}
});
this.pad = options.pad != null
? options.pad
: 2;
this.setData(options.rows || options.data);
this.on('attach', function() {
self.setData(self.rows);
});
this.on('resize', function() {
var selected = self.selected;
self.setData(self.rows);
self.select(selected);
self.screen.render();
});
}
ListTable.prototype.__proto__ = List.prototype;
ListTable.prototype.type = 'list-table';
ListTable.prototype._calculateMaxes = Table.prototype._calculateMaxes;
ListTable.prototype.setRows =
ListTable.prototype.setData = function(rows) {
var self = this
, align = this.__align
, selected = this.selected
, original = this.items.slice()
, sel = this.ritems[this.selected];
if (this.visible && this.lpos) {
this.clearPos();
}
this.clearItems();
this.rows = rows || [];
this._calculateMaxes();
if (!this._maxes) return;
this.addItem('');
this.rows.forEach(function(row, i) {
var isHeader = i === 0;
var text = '';
row.forEach(function(cell, i) {
var width = self._maxes[i];
var clen = self.strWidth(cell);
if (i !== 0) {
text += ' ';
}
while (clen < width) {
if (align === 'center') {
cell = ' ' + cell + ' ';
clen += 2;
} else if (align === 'left') {
cell = cell + ' ';
clen += 1;
} else if (align === 'right') {
cell = ' ' + cell;
clen += 1;
}
}
if (clen > width) {
if (align === 'center') {
cell = cell.substring(1);
clen--;
} else if (align === 'left') {
cell = cell.slice(0, -1);
clen--;
} else if (align === 'right') {
cell = cell.substring(1);
clen--;
}
}
text += cell;
});
if (isHeader) {
self._header.setContent(text);
} else {
self.addItem(text);
}
});
this._header.setFront();
// Try to find our old item if it still exists.
sel = this.ritems.indexOf(sel);
if (~sel) {
this.select(sel);
} else if (this.items.length === original.length) {
this.select(selected);
} else {
this.select(Math.min(selected, this.items.length - 1));
}
};
ListTable.prototype._select = ListTable.prototype.select;
ListTable.prototype.select = function(i) {
if (i === 0) {
i = 1;
}
if (i <= this.childBase) {
this.setScroll(this.childBase - 1);
}
return this._select(i);
};
ListTable.prototype.render = function() {
var self = this;
var coords = this._render();
if (!coords) return;
this._calculateMaxes();
if (!this._maxes) return coords;
var lines = this.screen.lines
, xi = coords.xi
, yi = coords.yi
, rx
, ry
, i;
var battr = this.sattr(this.style.border);
var height = coords.yl - coords.yi - this.ibottom;
var border = this.border;
if (!this.border && this.options.border) {
border = this.options.border;
}
if (!border || this.options.noCellBorders) return coords;
// Draw border with correct angles.
ry = 0;
for (i = 0; i < height + 1; i++) {
if (!lines[yi + ry]) break;
rx = 0;
self._maxes.slice(0, -1).forEach(function(max) {
rx += max;
if (!lines[yi + ry][xi + rx + 1]) return;
// center
if (ry === 0) {
// top
rx++;
lines[yi + ry][xi + rx][0] = battr;
lines[yi + ry][xi + rx][1] = '\u252c'; // '┬'
// XXX If we alter iheight and itop for no borders - nothing should be written here
if (!border.top) {
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
}
lines[yi + ry].dirty = true;
} else if (ry === height) {
// bottom
rx++;
lines[yi + ry][xi + rx][0] = battr;
lines[yi + ry][xi + rx][1] = '\u2534'; // '┴'
// XXX If we alter iheight and ibottom for no borders - nothing should be written here
if (!border.bottom) {
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
}
lines[yi + ry].dirty = true;
} else {
// middle
rx++;
}
});
ry += 1;
}
// Draw internal borders.
for (ry = 1; ry < height; ry++) {
if (!lines[yi + ry]) break;
rx = 0;
self._maxes.slice(0, -1).forEach(function(max) {
rx += max;
if (!lines[yi + ry][xi + rx + 1]) return;
if (self.options.fillCellBorders !== false) {
var lbg = lines[yi + ry][xi + rx][0] & 0x1ff;
rx++;
lines[yi + ry][xi + rx][0] = (battr & ~0x1ff) | lbg;
} else {
rx++;
lines[yi + ry][xi + rx][0] = battr;
}
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
lines[yi + ry].dirty = true;
});
}
return coords;
};
/**
* Expose
*/
module.exports = ListTable;

88
lib/widgets/loading.js Normal file
View File

@ -0,0 +1,88 @@
/**
* loading.js - loading element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
var Text = require('./text');
/**
* Loading
*/
function Loading(options) {
if (!(this instanceof Node)) {
return new Loading(options);
}
options = options || {};
Box.call(this, options);
this._.icon = new Text({
parent: this,
align: 'center',
top: 2,
left: 1,
right: 1,
height: 1,
content: '|'
});
}
Loading.prototype.__proto__ = Box.prototype;
Loading.prototype.type = 'loading';
Loading.prototype.load = function(text) {
var self = this;
// XXX Keep above:
// var parent = this.parent;
// this.detach();
// parent.append(this);
this.show();
this.setContent(text);
if (this._.timer) {
this.stop();
}
this.screen.lockKeys = true;
this._.timer = setInterval(function() {
if (self._.icon.content === '|') {
self._.icon.setContent('/');
} else if (self._.icon.content === '/') {
self._.icon.setContent('-');
} else if (self._.icon.content === '-') {
self._.icon.setContent('\\');
} else if (self._.icon.content === '\\') {
self._.icon.setContent('|');
}
self.screen.render();
}, 200);
};
Loading.prototype.stop = function() {
this.screen.lockKeys = false;
this.hide();
if (this._.timer) {
clearInterval(this._.timer);
delete this._.timer;
}
this.screen.render();
};
/**
* Expose
*/
module.exports = Loading;

83
lib/widgets/log.js Normal file
View File

@ -0,0 +1,83 @@
/**
* log.js - log element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var util = require('util');
var nextTick = global.setImmediate || process.nextTick.bind(process);
var Node = require('./node');
var ScrollableText = require('./scrollabletext');
/**
* Log
*/
function Log(options) {
var self = this;
if (!(this instanceof Node)) {
return new Log(options);
}
options = options || {};
ScrollableText.call(this, options);
this.scrollback = options.scrollback != null
? options.scrollback
: Infinity;
this.scrollOnInput = options.scrollOnInput;
this.on('set content', function() {
if (!self._userScrolled || self.scrollOnInput) {
nextTick(function() {
self.setScrollPerc(100);
self._userScrolled = false;
self.screen.render();
});
}
});
}
Log.prototype.__proto__ = ScrollableText.prototype;
Log.prototype.type = 'log';
Log.prototype.log =
Log.prototype.add = function() {
var args = Array.prototype.slice.call(arguments);
if (typeof args[0] === 'object') {
args[0] = util.inspect(args[0], true, 20, true);
}
var text = util.format.apply(util, args);
this.emit('log', text);
var ret = this.pushLine(text);
if (this._clines.fake.length > this.scrollback) {
this.shiftLine(0, (this.scrollback / 3) | 0);
}
return ret;
};
Log.prototype._scroll = Log.prototype.scroll;
Log.prototype.scroll = function(offset, always) {
if (offset === 0) return this._scroll(offset, always);
this._userScrolled = true;
var ret = this._scroll(offset, always);
if (this.getScrollPerc() === 100) {
this._userScrolled = false;
}
return ret;
};
/**
* Expose
*/
module.exports = Log;

123
lib/widgets/message.js Normal file
View File

@ -0,0 +1,123 @@
/**
* message.js - message element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Message / Error
*/
function Message(options) {
if (!(this instanceof Node)) {
return new Message(options);
}
options = options || {};
options.tags = true;
Box.call(this, options);
}
Message.prototype.__proto__ = Box.prototype;
Message.prototype.type = 'message';
Message.prototype.log =
Message.prototype.display = function(text, time, callback) {
var self = this;
if (typeof time === 'function') {
callback = time;
time = null;
}
if (time == null) time = 3;
// Keep above:
// var parent = this.parent;
// this.detach();
// parent.append(this);
if (this.scrollable) {
this.screen.saveFocus();
this.focus();
this.scrollTo(0);
}
this.show();
this.setContent(text);
this.screen.render();
if (time === Infinity || time === -1 || time === 0) {
var end = function() {
if (end.done) return;
end.done = true;
if (self.scrollable) {
try {
self.screen.restoreFocus();
} catch (e) {
;
}
}
self.hide();
self.screen.render();
if (callback) callback();
};
setTimeout(function() {
self.onScreenEvent('keypress', function fn(ch, key) {
if (key.name === 'mouse') return;
if (self.scrollable) {
if ((key.name === 'up' || (self.options.vi && key.name === 'k'))
|| (key.name === 'down' || (self.options.vi && key.name === 'j'))
|| (self.options.vi && key.name === 'u' && key.ctrl)
|| (self.options.vi && key.name === 'd' && key.ctrl)
|| (self.options.vi && key.name === 'b' && key.ctrl)
|| (self.options.vi && key.name === 'f' && key.ctrl)
|| (self.options.vi && key.name === 'g' && !key.shift)
|| (self.options.vi && key.name === 'g' && key.shift)) {
return;
}
}
if (self.options.ignoreKeys && ~self.options.ignoreKeys.indexOf(key.name)) {
return;
}
self.removeScreenEvent('keypress', fn);
end();
});
// XXX May be affected by new element.options.mouse option.
if (!self.options.mouse) return;
self.onScreenEvent('mouse', function fn(data) {
if (data.action === 'mousemove') return;
self.removeScreenEvent('mouse', fn);
end();
});
}, 10);
return;
}
setTimeout(function() {
self.hide();
self.screen.render();
if (callback) callback();
}, time * 1000);
};
Message.prototype.error = function(text, time, callback) {
return this.display('{red-fg}Error: ' + text + '{/red-fg}', time, callback);
};
/**
* Expose
*/
module.exports = Message;

282
lib/widgets/node.js Normal file
View File

@ -0,0 +1,282 @@
/**
* node.js - base abstract node for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var EventEmitter = require('../events').EventEmitter;
/**
* Node
*/
function Node(options) {
var self = this;
var Screen = require('./screen');
if (!(this instanceof Node)) {
return new Node(options);
}
EventEmitter.call(this);
options = options || {};
this.options = options;
this.screen = this.screen || options.screen;
if (!this.screen) {
if (this.type === 'screen') {
this.screen = this;
} else if (Screen.total === 1) {
this.screen = Screen.global;
} else if (options.parent) {
this.screen = options.parent;
while (this.screen && this.screen.type !== 'screen') {
this.screen = this.screen.parent;
}
} else if (Screen.total) {
// This _should_ work in most cases as long as the element is appended
// synchronously after the screen's creation. Throw error if not.
this.screen = Screen.instances[Screen.instances.length - 1];
process.nextTick(function() {
if (!self.parent) {
throw new Error('Element (' + self.type + ')'
+ ' was not appended synchronously after the'
+ ' screen\'s creation. Please set a `parent`'
+ ' or `screen` option in the element\'s constructor'
+ ' if you are going to use multiple screens and'
+ ' append the element later.');
}
});
} else {
throw new Error('No active screen.');
}
}
this.parent = options.parent || null;
this.children = [];
this.$ = this._ = this.data = {};
this.uid = Node.uid++;
this.index = this.index != null ? this.index : -1;
if (this.type !== 'screen') {
this.detached = true;
}
if (this.parent) {
this.parent.append(this);
}
(options.children || []).forEach(this.append.bind(this));
}
Node.uid = 0;
Node.prototype.__proto__ = EventEmitter.prototype;
Node.prototype.type = 'node';
Node.prototype.insert = function(element, i) {
var self = this;
if (element.screen && element.screen !== this.screen) {
throw new Error('Cannot switch a node\'s screen.');
}
element.detach();
element.parent = this;
element.screen = this.screen;
if (i === 0) {
this.children.unshift(element);
} else if (i === this.children.length) {
this.children.push(element);
} else {
this.children.splice(i, 0, element);
}
element.emit('reparent', this);
this.emit('adopt', element);
(function emit(el) {
var n = el.detached !== self.detached;
el.detached = self.detached;
if (n) el.emit('attach');
el.children.forEach(emit);
})(element);
if (!this.screen.focused) {
this.screen.focused = element;
}
};
Node.prototype.prepend = function(element) {
this.insert(element, 0);
};
Node.prototype.append = function(element) {
this.insert(element, this.children.length);
};
Node.prototype.insertBefore = function(element, other) {
var i = this.children.indexOf(other);
if (~i) this.insert(element, i);
};
Node.prototype.insertAfter = function(element, other) {
var i = this.children.indexOf(other);
if (~i) this.insert(element, i + 1);
};
Node.prototype.remove = function(element) {
if (element.parent !== this) return;
var i = this.children.indexOf(element);
if (!~i) return;
element.clearPos();
element.parent = null;
this.children.splice(i, 1);
i = this.screen.clickable.indexOf(element);
if (~i) this.screen.clickable.splice(i, 1);
i = this.screen.keyable.indexOf(element);
if (~i) this.screen.keyable.splice(i, 1);
element.emit('reparent', null);
this.emit('remove', element);
(function emit(el) {
var n = el.detached !== true;
el.detached = true;
if (n) el.emit('detach');
el.children.forEach(emit);
})(element);
if (this.screen.focused === element) {
this.screen.rewindFocus();
}
};
Node.prototype.detach = function() {
if (this.parent) this.parent.remove(this);
};
Node.prototype.free = function() {
return;
};
Node.prototype.destroy = function() {
this.detach();
this.forDescendants(function(el) {
el.free();
el.destroyed = true;
el.emit('destroy');
}, this);
};
Node.prototype.forDescendants = function(iter, s) {
if (s) iter(this);
this.children.forEach(function emit(el) {
iter(el);
el.children.forEach(emit);
});
};
Node.prototype.forAncestors = function(iter, s) {
var el = this;
if (s) iter(this);
while (el = el.parent) {
iter(el);
}
};
Node.prototype.collectDescendants = function(s) {
var out = [];
this.forDescendants(function(el) {
out.push(el);
}, s);
return out;
};
Node.prototype.collectAncestors = function(s) {
var out = [];
this.forAncestors(function(el) {
out.push(el);
}, s);
return out;
};
Node.prototype.emitDescendants = function() {
var args = Array.prototype.slice(arguments)
, iter;
if (typeof args[args.length - 1] === 'function') {
iter = args.pop();
}
return this.forDescendants(function(el) {
if (iter) iter(el);
el.emit.apply(el, args);
}, true);
};
Node.prototype.emitAncestors = function() {
var args = Array.prototype.slice(arguments)
, iter;
if (typeof args[args.length - 1] === 'function') {
iter = args.pop();
}
return this.forAncestors(function(el) {
if (iter) iter(el);
el.emit.apply(el, args);
}, true);
};
Node.prototype.hasDescendant = function(target) {
return (function find(el) {
for (var i = 0; i < el.children.length; i++) {
if (el.children[i] === target) {
return true;
}
if (find(el.children[i]) === true) {
return true;
}
}
return false;
})(this);
};
Node.prototype.hasAncestor = function(target) {
var el = this;
while (el = el.parent) {
if (el === target) return true;
}
return false;
};
Node.prototype.get = function(name, value) {
if (this.data.hasOwnProperty(name)) {
return this.data[name];
}
return value;
};
Node.prototype.set = function(name, value) {
return this.data[name] = value;
};
/**
* Expose
*/
module.exports = Node;

717
lib/widgets/overlayimage.js Normal file
View File

@ -0,0 +1,717 @@
/**
* overlayimage.js - w3m image element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var fs = require('fs')
, cp = require('child_process');
var helpers = require('../helpers');
var Node = require('./node');
var Box = require('./box');
/**
* OverlayImage
* Good example of w3mimgdisplay commands:
* https://github.com/hut/ranger/blob/master/ranger/ext/img_display.py
*/
function OverlayImage(options) {
var self = this;
if (!(this instanceof Node)) {
return new OverlayImage(options);
}
options = options || {};
Box.call(this, options);
if (options.w3m) {
OverlayImage.w3mdisplay = options.w3m;
}
if (OverlayImage.hasW3MDisplay == null) {
if (fs.existsSync(OverlayImage.w3mdisplay)) {
OverlayImage.hasW3MDisplay = true;
} else if (options.search !== false) {
var file = helpers.findFile('/usr', 'w3mimgdisplay')
|| helpers.findFile('/lib', 'w3mimgdisplay')
|| helpers.findFile('/bin', 'w3mimgdisplay');
if (file) {
OverlayImage.hasW3MDisplay = true;
OverlayImage.w3mdisplay = file;
} else {
OverlayImage.hasW3MDisplay = false;
}
}
}
this.on('hide', function() {
self._lastFile = self.file;
self.clearImage();
});
this.on('show', function() {
if (!self._lastFile) return;
self.setImage(self._lastFile);
});
this.on('detach', function() {
self._lastFile = self.file;
self.clearImage();
});
this.on('attach', function() {
if (!self._lastFile) return;
self.setImage(self._lastFile);
});
this.onScreenEvent('resize', function() {
self._needsRatio = true;
});
// Get images to overlap properly. Maybe not worth it:
// this.onScreenEvent('render', function() {
// self.screen.program.flush();
// if (!self._noImage) return;
// function display(el, next) {
// if (el.type === 'w3mimage' && el.file) {
// el.setImage(el.file, next);
// } else {
// next();
// }
// }
// function done(el) {
// el.children.forEach(recurse);
// }
// function recurse(el) {
// display(el, function() {
// var pending = el.children.length;
// el.children.forEach(function(el) {
// display(el, function() {
// if (!--pending) done(el);
// });
// });
// });
// }
// recurse(self.screen);
// });
this.onScreenEvent('render', function() {
self.screen.program.flush();
if (!self._noImage) {
self.setImage(self.file);
}
});
if (this.options.file || this.options.img) {
this.setImage(this.options.file || this.options.img);
}
}
OverlayImage.prototype.__proto__ = Box.prototype;
OverlayImage.prototype.type = 'overlayimage';
OverlayImage.w3mdisplay = '/usr/lib/w3m/w3mimgdisplay';
OverlayImage.prototype.spawn = function(file, args, opt, callback) {
var spawn = require('child_process').spawn
, ps;
opt = opt || {};
ps = spawn(file, args, opt);
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function(code) {
if (!callback) return;
if (code !== 0) return callback(new Error('Exit Code: ' + code));
return callback(null, code === 0);
});
return ps;
};
OverlayImage.prototype.setImage = function(img, callback) {
var self = this;
if (this._settingImage) {
this._queue = this._queue || [];
this._queue.push([img, callback]);
return;
}
this._settingImage = true;
var reset = function() {
self._settingImage = false;
self._queue = self._queue || [];
var item = self._queue.shift();
if (item) {
self.setImage(item[0], item[1]);
}
};
if (OverlayImage.hasW3MDisplay === false) {
reset();
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!img) {
reset();
if (!callback) return;
return callback(new Error('No image.'));
}
this.file = img;
return this.getPixelRatio(function(err, ratio) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
return self.renderImage(img, ratio, function(err, success) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
if (self.shrink || self.options.autofit) {
delete self.shrink;
delete self.options.shrink;
self.options.autofit = true;
return self.imageSize(function(err, size) {
if (err) {
reset();
if (!callback) return;
return callback(err);
}
if (self._lastSize
&& ratio.tw === self._lastSize.tw
&& ratio.th === self._lastSize.th
&& size.width === self._lastSize.width
&& size.height === self._lastSize.height
&& self.aleft === self._lastSize.aleft
&& self.atop === self._lastSize.atop) {
reset();
if (!callback) return;
return callback(null, success);
}
self._lastSize = {
tw: ratio.tw,
th: ratio.th,
width: size.width,
height: size.height,
aleft: self.aleft,
atop: self.atop
};
self.position.width = size.width / ratio.tw | 0;
self.position.height = size.height / ratio.th | 0;
self._noImage = true;
self.screen.render();
self._noImage = false;
reset();
return self.renderImage(img, ratio, callback);
});
}
reset();
if (!callback) return;
return callback(null, success);
});
});
};
OverlayImage.prototype.renderImage = function(img, ratio, callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.renderImageSync(img, ratio));
} catch (e) {
return callback(e);
}
}
if (OverlayImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!ratio) {
if (!callback) return;
return callback(new Error('No ratio.'));
}
// clearImage unsets these:
var _file = self.file;
var _lastSize = self._lastSize;
return self.clearImage(function(err) {
if (err) return callback(err);
self.file = _file;
self._lastSize = _lastSize;
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = self.spawn(OverlayImage.w3mdisplay, [], opt, function(err, success) {
if (!callback) return;
return err
? callback(err)
: callback(null, success);
});
var width = self.width * ratio.tw | 0
, height = self.height * ratio.th | 0
, aleft = self.aleft * ratio.tw | 0
, atop = self.atop * ratio.th | 0;
var input = '0;1;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height + ';;;;;'
+ img
+ '\n4;\n3;\n';
self._props = {
aleft: aleft,
atop: atop,
width: width,
height: height
};
ps.stdin.write(input);
ps.stdin.end();
});
};
OverlayImage.prototype.clearImage = function(callback) {
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.clearImageSync());
} catch (e) {
return callback(e);
}
}
if (OverlayImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!this._props) {
if (!callback) return;
return callback(null);
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(OverlayImage.w3mdisplay, [], opt, function(err, success) {
if (!callback) return;
return err
? callback(err)
: callback(null, success);
});
var width = this._props.width + 2
, height = this._props.height + 2
, aleft = this._props.aleft
, atop = this._props.atop;
if (this._drag) {
aleft -= 10;
atop -= 10;
width += 10;
height += 10;
}
var input = '6;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height
+ '\n4;\n3;\n';
delete this.file;
delete this._props;
delete this._lastSize;
ps.stdin.write(input);
ps.stdin.end();
};
OverlayImage.prototype.imageSize = function(callback) {
var img = this.file;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.imageSizeSync());
} catch (e) {
return callback(e);
}
}
if (OverlayImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
if (!img) {
if (!callback) return;
return callback(new Error('No image.'));
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(OverlayImage.w3mdisplay, [], opt);
var buf = '';
ps.stdout.setEncoding('utf8');
ps.stdout.on('data', function(data) {
buf += data;
});
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function() {
if (!callback) return;
var size = buf.trim().split(/\s+/);
return callback(null, {
raw: buf.trim(),
width: +size[0],
height: +size[1]
});
});
var input = '5;' + img + '\n';
ps.stdin.write(input);
ps.stdin.end();
};
OverlayImage.prototype.termSize = function(callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.termSizeSync());
} catch (e) {
return callback(e);
}
}
if (OverlayImage.hasW3MDisplay === false) {
if (!callback) return;
return callback(new Error('W3M Image Display not available.'));
}
var opt = {
stdio: 'pipe',
env: process.env,
cwd: process.env.HOME
};
var ps = this.spawn(OverlayImage.w3mdisplay, ['-test'], opt);
var buf = '';
ps.stdout.setEncoding('utf8');
ps.stdout.on('data', function(data) {
buf += data;
});
ps.on('error', function(err) {
if (!callback) return;
return callback(err);
});
ps.on('exit', function() {
if (!callback) return;
if (!buf.trim()) {
// Bug: w3mimgdisplay will sometimes
// output nothing. Try again:
return self.termSize(callback);
}
var size = buf.trim().split(/\s+/);
return callback(null, {
raw: buf.trim(),
width: +size[0],
height: +size[1]
});
});
ps.stdin.end();
};
OverlayImage.prototype.getPixelRatio = function(callback) {
var self = this;
if (cp.execSync) {
callback = callback || function(err, result) { return result; };
try {
return callback(null, this.getPixelRatioSync());
} catch (e) {
return callback(e);
}
}
// XXX We could cache this, but sometimes it's better
// to recalculate to be pixel perfect.
if (this._ratio && !this._needsRatio) {
return callback(null, this._ratio);
}
return this.termSize(function(err, dimensions) {
if (err) return callback(err);
self._ratio = {
tw: dimensions.width / self.screen.width,
th: dimensions.height / self.screen.height
};
self._needsRatio = false;
return callback(null, self._ratio);
});
};
OverlayImage.prototype.renderImageSync = function(img, ratio) {
if (OverlayImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!ratio) {
throw new Error('No ratio.');
}
// clearImage unsets these:
var _file = this.file;
var _lastSize = this._lastSize;
this.clearImageSync();
this.file = _file;
this._lastSize = _lastSize;
var width = this.width * ratio.tw | 0
, height = this.height * ratio.th | 0
, aleft = this.aleft * ratio.tw | 0
, atop = this.atop * ratio.th | 0;
var input = '0;1;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height + ';;;;;'
+ img
+ '\n4;\n3;\n';
this._props = {
aleft: aleft,
atop: atop,
width: width,
height: height
};
try {
cp.execFileSync(OverlayImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
return true;
};
OverlayImage.prototype.clearImageSync = function() {
if (OverlayImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!this._props) {
return false;
}
var width = this._props.width + 2
, height = this._props.height + 2
, aleft = this._props.aleft
, atop = this._props.atop;
if (this._drag) {
aleft -= 10;
atop -= 10;
width += 10;
height += 10;
}
var input = '6;'
+ aleft + ';'
+ atop + ';'
+ width + ';'
+ height
+ '\n4;\n3;\n';
delete this.file;
delete this._props;
delete this._lastSize;
try {
cp.execFileSync(OverlayImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
return true;
};
OverlayImage.prototype.imageSizeSync = function() {
var img = this.file;
if (OverlayImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
if (!img) {
throw new Error('No image.');
}
var buf = '';
var input = '5;' + img + '\n';
try {
buf = cp.execFileSync(OverlayImage.w3mdisplay, [], {
env: process.env,
encoding: 'utf8',
input: input,
timeout: 1000
});
} catch (e) {
;
}
var size = buf.trim().split(/\s+/);
return {
raw: buf.trim(),
width: +size[0],
height: +size[1]
};
};
OverlayImage.prototype.termSizeSync = function(_, recurse) {
if (OverlayImage.hasW3MDisplay === false) {
throw new Error('W3M Image Display not available.');
}
var buf = '';
try {
buf = cp.execFileSync(OverlayImage.w3mdisplay, ['-test'], {
env: process.env,
encoding: 'utf8',
timeout: 1000
});
} catch (e) {
;
}
if (!buf.trim()) {
// Bug: w3mimgdisplay will sometimes
// output nothing. Try again:
recurse = recurse || 0;
if (++recurse === 5) {
throw new Error('Term size not determined.');
}
return this.termSizeSync(_, recurse);
}
var size = buf.trim().split(/\s+/);
return {
raw: buf.trim(),
width: +size[0],
height: +size[1]
};
};
OverlayImage.prototype.getPixelRatioSync = function() {
// XXX We could cache this, but sometimes it's better
// to recalculate to be pixel perfect.
if (this._ratio && !this._needsRatio) {
return this._ratio;
}
this._needsRatio = false;
var dimensions = this.termSizeSync();
this._ratio = {
tw: dimensions.width / this.screen.width,
th: dimensions.height / this.screen.height
};
return this._ratio;
};
OverlayImage.prototype.displayImage = function(callback) {
return this.screen.displayImage(this.file, callback);
};
/**
* Expose
*/
module.exports = OverlayImage;

157
lib/widgets/progressbar.js Normal file
View File

@ -0,0 +1,157 @@
/**
* progressbar.js - progress bar element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Input = require('./input');
/**
* ProgressBar
*/
function ProgressBar(options) {
var self = this;
if (!(this instanceof Node)) {
return new ProgressBar(options);
}
options = options || {};
Input.call(this, options);
this.filled = options.filled || 0;
if (typeof this.filled === 'string') {
this.filled = +this.filled.slice(0, -1);
}
this.value = this.filled;
this.pch = options.pch || ' ';
// XXX Workaround that predates the usage of `el.ch`.
if (options.ch) {
this.pch = options.ch;
this.ch = ' ';
}
if (options.bch) {
this.ch = options.bch;
}
if (!this.style.bar) {
this.style.bar = {};
this.style.bar.fg = options.barFg;
this.style.bar.bg = options.barBg;
}
this.orientation = options.orientation || 'horizontal';
if (options.keys) {
this.on('keypress', function(ch, key) {
var back, forward;
if (self.orientation === 'horizontal') {
back = ['left', 'h'];
forward = ['right', 'l'];
} else if (self.orientation === 'vertical') {
back = ['down', 'j'];
forward = ['up', 'k'];
}
if (key.name === back[0] || (options.vi && key.name === back[1])) {
self.progress(-5);
self.screen.render();
return;
}
if (key.name === forward[0] || (options.vi && key.name === forward[1])) {
self.progress(5);
self.screen.render();
return;
}
});
}
if (options.mouse) {
this.on('click', function(data) {
var x, y, m, p;
if (!self.lpos) return;
if (self.orientation === 'horizontal') {
x = data.x - self.lpos.xi;
m = (self.lpos.xl - self.lpos.xi) - self.iwidth;
p = x / m * 100 | 0;
} else if (self.orientation === 'vertical') {
y = data.y - self.lpos.yi;
m = (self.lpos.yl - self.lpos.yi) - self.iheight;
p = y / m * 100 | 0;
}
self.setProgress(p);
});
}
}
ProgressBar.prototype.__proto__ = Input.prototype;
ProgressBar.prototype.type = 'progress-bar';
ProgressBar.prototype.render = function() {
var ret = this._render();
if (!ret) return;
var xi = ret.xi
, xl = ret.xl
, yi = ret.yi
, yl = ret.yl
, dattr;
if (this.border) xi++, yi++, xl--, yl--;
if (this.orientation === 'horizontal') {
xl = xi + ((xl - xi) * (this.filled / 100)) | 0;
} else if (this.orientation === 'vertical') {
yi = yi + ((yl - yi) - (((yl - yi) * (this.filled / 100)) | 0));
}
dattr = this.sattr(this.style.bar);
this.screen.fillRegion(dattr, this.pch, xi, xl, yi, yl);
if (this.content) {
var line = this.screen.lines[yi];
for (var i = 0; i < this.content.length; i++) {
line[xi + i][1] = this.content[i];
}
line.dirty = true;
}
return ret;
};
ProgressBar.prototype.progress = function(filled) {
this.filled += filled;
if (this.filled < 0) this.filled = 0;
else if (this.filled > 100) this.filled = 100;
if (this.filled === 100) {
this.emit('complete');
}
this.value = this.filled;
};
ProgressBar.prototype.setProgress = function(filled) {
this.filled = 0;
this.progress(filled);
};
ProgressBar.prototype.reset = function() {
this.emit('reset');
this.filled = 0;
this.value = this.filled;
};
/**
* Expose
*/
module.exports = ProgressBar;

120
lib/widgets/prompt.js Normal file
View File

@ -0,0 +1,120 @@
/**
* prompt.js - prompt element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
var Button = require('./button');
var Textbox = require('./textbox');
/**
* Prompt
*/
function Prompt(options) {
if (!(this instanceof Node)) {
return new Prompt(options);
}
options = options || {};
options.hidden = true;
Box.call(this, options);
this._.input = new Textbox({
parent: this,
top: 3,
height: 1,
left: 2,
right: 2,
bg: 'black'
});
this._.okay = new Button({
parent: this,
top: 5,
height: 1,
left: 2,
width: 6,
content: 'Okay',
align: 'center',
bg: 'black',
hoverBg: 'blue',
autoFocus: false,
mouse: true
});
this._.cancel = new Button({
parent: this,
top: 5,
height: 1,
shrink: true,
left: 10,
width: 8,
content: 'Cancel',
align: 'center',
bg: 'black',
hoverBg: 'blue',
autoFocus: false,
mouse: true
});
}
Prompt.prototype.__proto__ = Box.prototype;
Prompt.prototype.type = 'prompt';
Prompt.prototype.input =
Prompt.prototype.setInput =
Prompt.prototype.readInput = function(text, value, callback) {
var self = this;
var okay, cancel;
if (!callback) {
callback = value;
value = '';
}
// Keep above:
// var parent = this.parent;
// this.detach();
// parent.append(this);
this.show();
this.setContent(' ' + text);
this._.input.value = value;
this.screen.saveFocus();
this._.okay.on('press', okay = function() {
self._.input.submit();
});
this._.cancel.on('press', cancel = function() {
self._.input.cancel();
});
this._.input.readInput(function(err, data) {
self.hide();
self.screen.restoreFocus();
self._.okay.removeListener('press', okay);
self._.cancel.removeListener('press', cancel);
return callback(err, data);
});
this.screen.render();
};
/**
* Expose
*/
module.exports = Prompt;

116
lib/widgets/question.js Normal file
View File

@ -0,0 +1,116 @@
/**
* question.js - question element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
var Button = require('./button');
/**
* Question
*/
function Question(options) {
if (!(this instanceof Node)) {
return new Question(options);
}
options = options || {};
options.hidden = true;
Box.call(this, options);
this._.okay = new Button({
screen: this.screen,
parent: this,
top: 2,
height: 1,
left: 2,
width: 6,
content: 'Okay',
align: 'center',
bg: 'black',
hoverBg: 'blue',
autoFocus: false,
mouse: true
});
this._.cancel = new Button({
screen: this.screen,
parent: this,
top: 2,
height: 1,
shrink: true,
left: 10,
width: 8,
content: 'Cancel',
align: 'center',
bg: 'black',
hoverBg: 'blue',
autoFocus: false,
mouse: true
});
}
Question.prototype.__proto__ = Box.prototype;
Question.prototype.type = 'question';
Question.prototype.ask = function(text, callback) {
var self = this;
var press, okay, cancel;
// Keep above:
// var parent = this.parent;
// this.detach();
// parent.append(this);
this.show();
this.setContent(' ' + text);
this.onScreenEvent('keypress', press = function(ch, key) {
if (key.name === 'mouse') return;
if (key.name !== 'enter'
&& key.name !== 'escape'
&& key.name !== 'q'
&& key.name !== 'y'
&& key.name !== 'n') {
return;
}
done(null, key.name === 'enter' || key.name === 'y');
});
this._.okay.on('press', okay = function() {
done(null, true);
});
this._.cancel.on('press', cancel = function() {
done(null, false);
});
this.screen.saveFocus();
this.focus();
function done(err, data) {
self.hide();
self.screen.restoreFocus();
self.removeScreenEvent('keypress', press);
self._.okay.removeListener('press', okay);
self._.cancel.removeListener('press', cancel);
return callback(err, data);
}
this.screen.render();
};
/**
* Expose
*/
module.exports = Question;

View File

@ -0,0 +1,61 @@
/**
* radiobutton.js - radio button element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Checkbox = require('./checkbox');
/**
* RadioButton
*/
function RadioButton(options) {
var self = this;
if (!(this instanceof Node)) {
return new RadioButton(options);
}
options = options || {};
Checkbox.call(this, options);
this.on('check', function() {
var el = self;
while (el = el.parent) {
if (el.type === 'radio-set'
|| el.type === 'form') break;
}
el = el || self.parent;
el.forDescendants(function(el) {
if (el.type !== 'radio-button' || el === self) {
return;
}
el.uncheck();
});
});
}
RadioButton.prototype.__proto__ = Checkbox.prototype;
RadioButton.prototype.type = 'radio-button';
RadioButton.prototype.render = function() {
this.clearPos(true);
this.setContent('(' + (this.checked ? '*' : ' ') + ') ' + this.text, true);
return this._render();
};
RadioButton.prototype.toggle = RadioButton.prototype.check;
/**
* Expose
*/
module.exports = RadioButton;

36
lib/widgets/radioset.js Normal file
View File

@ -0,0 +1,36 @@
/**
* radioset.js - radio set element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* RadioSet
*/
function RadioSet(options) {
if (!(this instanceof Node)) {
return new RadioSet(options);
}
options = options || {};
// Possibly inherit parent's style.
// options.style = this.parent.style;
Box.call(this, options);
}
RadioSet.prototype.__proto__ = Box.prototype;
RadioSet.prototype.type = 'radio-set';
/**
* Expose
*/
module.exports = RadioSet;

2298
lib/widgets/screen.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,389 @@
/**
* scrollablebox.js - scrollable box element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* ScrollableBox
*/
function ScrollableBox(options) {
var self = this;
if (!(this instanceof Node)) {
return new ScrollableBox(options);
}
options = options || {};
Box.call(this, options);
if (options.scrollable === false) {
return this;
}
this.scrollable = true;
this.childOffset = 0;
this.childBase = 0;
this.baseLimit = options.baseLimit || Infinity;
this.alwaysScroll = options.alwaysScroll;
this.scrollbar = options.scrollbar;
if (this.scrollbar) {
this.scrollbar.ch = this.scrollbar.ch || ' ';
this.style.scrollbar = this.style.scrollbar || this.scrollbar.style;
if (!this.style.scrollbar) {
this.style.scrollbar = {};
this.style.scrollbar.fg = this.scrollbar.fg;
this.style.scrollbar.bg = this.scrollbar.bg;
this.style.scrollbar.bold = this.scrollbar.bold;
this.style.scrollbar.underline = this.scrollbar.underline;
this.style.scrollbar.inverse = this.scrollbar.inverse;
this.style.scrollbar.invisible = this.scrollbar.invisible;
}
//this.scrollbar.style = this.style.scrollbar;
if (this.track || this.scrollbar.track) {
this.track = this.scrollbar.track || this.track;
this.style.track = this.style.scrollbar.track || this.style.track;
this.track.ch = this.track.ch || ' ';
this.style.track = this.style.track || this.track.style;
if (!this.style.track) {
this.style.track = {};
this.style.track.fg = this.track.fg;
this.style.track.bg = this.track.bg;
this.style.track.bold = this.track.bold;
this.style.track.underline = this.track.underline;
this.style.track.inverse = this.track.inverse;
this.style.track.invisible = this.track.invisible;
}
this.track.style = this.style.track;
}
// Allow controlling of the scrollbar via the mouse:
if (options.mouse) {
this.on('mousedown', function(data) {
if (self._scrollingBar) {
// Do not allow dragging on the scrollbar:
delete self.screen._dragging;
delete self._drag;
return;
}
var x = data.x - self.aleft;
var y = data.y - self.atop;
if (x === self.width - self.iright - 1) {
// Do not allow dragging on the scrollbar:
delete self.screen._dragging;
delete self._drag;
var perc = (y - self.itop) / (self.height - self.iheight);
self.setScrollPerc(perc * 100 | 0);
self.screen.render();
var smd, smu;
self._scrollingBar = true;
self.onScreenEvent('mousedown', smd = function(data) {
var y = data.y - self.atop;
var perc = y / self.height;
self.setScrollPerc(perc * 100 | 0);
self.screen.render();
});
// If mouseup occurs out of the window, no mouseup event fires, and
// scrollbar will drag again on mousedown until another mouseup
// occurs.
self.onScreenEvent('mouseup', smu = function() {
self._scrollingBar = false;
self.removeScreenEvent('mousedown', smd);
self.removeScreenEvent('mouseup', smu);
});
}
});
}
}
if (options.mouse) {
this.on('wheeldown', function() {
self.scroll(self.height / 2 | 0 || 1);
self.screen.render();
});
this.on('wheelup', function() {
self.scroll(-(self.height / 2 | 0) || -1);
self.screen.render();
});
}
if (options.keys && !options.ignoreKeys) {
this.on('keypress', function(ch, key) {
if (key.name === 'up' || (options.vi && key.name === 'k')) {
self.scroll(-1);
self.screen.render();
return;
}
if (key.name === 'down' || (options.vi && key.name === 'j')) {
self.scroll(1);
self.screen.render();
return;
}
if (options.vi && key.name === 'u' && key.ctrl) {
self.scroll(-(self.height / 2 | 0) || -1);
self.screen.render();
return;
}
if (options.vi && key.name === 'd' && key.ctrl) {
self.scroll(self.height / 2 | 0 || 1);
self.screen.render();
return;
}
if (options.vi && key.name === 'b' && key.ctrl) {
self.scroll(-self.height || -1);
self.screen.render();
return;
}
if (options.vi && key.name === 'f' && key.ctrl) {
self.scroll(self.height || 1);
self.screen.render();
return;
}
if (options.vi && key.name === 'g' && !key.shift) {
self.scrollTo(0);
self.screen.render();
return;
}
if (options.vi && key.name === 'g' && key.shift) {
self.scrollTo(self.getScrollHeight());
self.screen.render();
return;
}
});
}
this.on('parsed content', function() {
self._recalculateIndex();
});
self._recalculateIndex();
}
ScrollableBox.prototype.__proto__ = Box.prototype;
ScrollableBox.prototype.type = 'scrollable-box';
// XXX Potentially use this in place of scrollable checks elsewhere.
ScrollableBox.prototype.__defineGetter__('reallyScrollable', function() {
if (this.shrink) return this.scrollable;
return this.getScrollHeight() > this.height;
});
ScrollableBox.prototype._scrollBottom = function() {
if (!this.scrollable) return 0;
// We could just calculate the children, but we can
// optimize for lists by just returning the items.length.
if (this._isList) {
return this.items ? this.items.length : 0;
}
if (this.lpos && this.lpos._scrollBottom) {
return this.lpos._scrollBottom;
}
var bottom = this.children.reduce(function(current, el) {
// el.height alone does not calculate the shrunken height, we need to use
// getCoords. A shrunken box inside a scrollable element will not grow any
// larger than the scrollable element's context regardless of how much
// content is in the shrunken box, unless we do this (call getCoords
// without the scrollable calculation):
// See: $ node test/widget-shrink-fail-2.js
if (!el.detached) {
var lpos = el._getCoords(false, true);
if (lpos) {
return Math.max(current, el.rtop + (lpos.yl - lpos.yi));
}
}
return Math.max(current, el.rtop + el.height);
}, 0);
// XXX Use this? Makes .getScrollHeight() useless!
// if (bottom < this._clines.length) bottom = this._clines.length;
if (this.lpos) this.lpos._scrollBottom = bottom;
return bottom;
};
ScrollableBox.prototype.setScroll =
ScrollableBox.prototype.scrollTo = function(offset, always) {
// XXX
// At first, this appeared to account for the first new calculation of childBase:
this.scroll(0);
return this.scroll(offset - (this.childBase + this.childOffset), always);
};
ScrollableBox.prototype.getScroll = function() {
return this.childBase + this.childOffset;
};
ScrollableBox.prototype.scroll = function(offset, always) {
if (!this.scrollable) return;
if (this.detached) return;
// Handle scrolling.
var visible = this.height - this.iheight
, base = this.childBase
, d
, p
, t
, b
, max
, emax;
if (this.alwaysScroll || always) {
// Semi-workaround
this.childOffset = offset > 0
? visible - 1 + offset
: offset;
} else {
this.childOffset += offset;
}
if (this.childOffset > visible - 1) {
d = this.childOffset - (visible - 1);
this.childOffset -= d;
this.childBase += d;
} else if (this.childOffset < 0) {
d = this.childOffset;
this.childOffset += -d;
this.childBase += d;
}
if (this.childBase < 0) {
this.childBase = 0;
} else if (this.childBase > this.baseLimit) {
this.childBase = this.baseLimit;
}
// Find max "bottom" value for
// content and descendant elements.
// Scroll the content if necessary.
if (this.childBase === base) {
return this.emit('scroll');
}
// When scrolling text, we want to be able to handle SGR codes as well as line
// feeds. This allows us to take preformatted text output from other programs
// and put it in a scrollable text box.
this.parseContent();
// XXX
// max = this.getScrollHeight() - (this.height - this.iheight);
max = this._clines.length - (this.height - this.iheight);
if (max < 0) max = 0;
emax = this._scrollBottom() - (this.height - this.iheight);
if (emax < 0) emax = 0;
this.childBase = Math.min(this.childBase, Math.max(emax, max));
if (this.childBase < 0) {
this.childBase = 0;
} else if (this.childBase > this.baseLimit) {
this.childBase = this.baseLimit;
}
// Optimize scrolling with CSR + IL/DL.
p = this.lpos;
// Only really need _getCoords() if we want
// to allow nestable scrolling elements...
// or if we **really** want shrinkable
// scrolling elements.
// p = this._getCoords();
if (p && this.childBase !== base && this.screen.cleanSides(this)) {
t = p.yi + this.itop;
b = p.yl - this.ibottom - 1;
d = this.childBase - base;
if (d > 0 && d < visible) {
// scrolled down
this.screen.deleteLine(d, t, t, b);
} else if (d < 0 && -d < visible) {
// scrolled up
d = -d;
this.screen.insertLine(d, t, t, b);
}
}
return this.emit('scroll');
};
ScrollableBox.prototype._recalculateIndex = function() {
var max, emax;
if (this.detached || !this.scrollable) {
return 0;
}
// XXX
// max = this.getScrollHeight() - (this.height - this.iheight);
max = this._clines.length - (this.height - this.iheight);
if (max < 0) max = 0;
emax = this._scrollBottom() - (this.height - this.iheight);
if (emax < 0) emax = 0;
this.childBase = Math.min(this.childBase, Math.max(emax, max));
if (this.childBase < 0) {
this.childBase = 0;
} else if (this.childBase > this.baseLimit) {
this.childBase = this.baseLimit;
}
};
ScrollableBox.prototype.resetScroll = function() {
if (!this.scrollable) return;
this.childOffset = 0;
this.childBase = 0;
return this.emit('scroll');
};
ScrollableBox.prototype.getScrollHeight = function() {
return Math.max(this._clines.length, this._scrollBottom());
};
ScrollableBox.prototype.getScrollPerc = function(s) {
var pos = this.lpos || this._getCoords();
if (!pos) return s ? -1 : 0;
var height = (pos.yl - pos.yi) - this.iheight
, i = this.getScrollHeight()
, p;
if (height < i) {
if (this.alwaysScroll) {
p = this.childBase / (i - height);
} else {
p = (this.childBase + this.childOffset) / (i - 1);
}
return p * 100;
}
return s ? -1 : 0;
};
ScrollableBox.prototype.setScrollPerc = function(i) {
// XXX
// var m = this.getScrollHeight();
var m = Math.max(this._clines.length, this._scrollBottom());
return this.scrollTo((i / 100) * m | 0);
};
/**
* Expose
*/
module.exports = ScrollableBox;

View File

@ -0,0 +1,35 @@
/**
* scrollabletext.js - scrollable text element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var ScrollableBox = require('./scrollablebox');
/**
* ScrollableText
*/
function ScrollableText(options) {
if (!(this instanceof Node)) {
return new ScrollableText(options);
}
options = options || {};
options.alwaysScroll = true;
ScrollableBox.call(this, options);
}
ScrollableText.prototype.__proto__ = ScrollableBox.prototype;
ScrollableText.prototype.type = 'scrollable-text';
/**
* Expose
*/
module.exports = ScrollableText;

354
lib/widgets/table.js Normal file
View File

@ -0,0 +1,354 @@
/**
* table.js - table element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Box = require('./box');
/**
* Table
*/
function Table(options) {
var self = this;
if (!(this instanceof Node)) {
return new Table(options);
}
options = options || {};
options.shrink = true;
options.style = options.style || {};
options.style.border = options.style.border || {};
options.style.header = options.style.header || {};
options.style.cell = options.style.cell || {};
options.align = options.align || 'center';
// Regular tables do not get custom height (this would
// require extra padding). Maybe add in the future.
delete options.height;
Box.call(this, options);
this.pad = options.pad != null
? options.pad
: 2;
this.setData(options.rows || options.data);
this.on('attach', function() {
self.setContent('');
self.setData(self.rows);
});
this.on('resize', function() {
self.setContent('');
self.setData(self.rows);
self.screen.render();
});
}
Table.prototype.__proto__ = Box.prototype;
Table.prototype.type = 'table';
Table.prototype._calculateMaxes = function() {
var self = this;
var maxes = [];
if (this.detached) return;
this.rows = this.rows || [];
this.rows.forEach(function(row) {
row.forEach(function(cell, i) {
var clen = self.strWidth(cell);
if (!maxes[i] || maxes[i] < clen) {
maxes[i] = clen;
}
});
});
var total = maxes.reduce(function(total, max) {
return total + max;
}, 0);
total += maxes.length + 1;
// XXX There might be an issue with resizing where on the first resize event
// width appears to be less than total if it's a percentage or left/right
// combination.
if (this.width < total) {
delete this.position.width;
}
if (this.position.width != null) {
var missing = this.width - total;
var w = missing / maxes.length | 0;
var wr = missing % maxes.length;
maxes = maxes.map(function(max, i) {
if (i === maxes.length - 1) {
return max + w + wr;
}
return max + w;
});
} else {
maxes = maxes.map(function(max) {
return max + self.pad;
});
}
return this._maxes = maxes;
};
Table.prototype.setRows =
Table.prototype.setData = function(rows) {
var self = this
, text = ''
, align = this.align;
this.rows = rows || [];
this._calculateMaxes();
if (!this._maxes) return;
this.rows.forEach(function(row, i) {
var isFooter = i === self.rows.length - 1;
row.forEach(function(cell, i) {
var width = self._maxes[i];
var clen = self.strWidth(cell);
if (i !== 0) {
text += ' ';
}
while (clen < width) {
if (align === 'center') {
cell = ' ' + cell + ' ';
clen += 2;
} else if (align === 'left') {
cell = cell + ' ';
clen += 1;
} else if (align === 'right') {
cell = ' ' + cell;
clen += 1;
}
}
if (clen > width) {
if (align === 'center') {
cell = cell.substring(1);
clen--;
} else if (align === 'left') {
cell = cell.slice(0, -1);
clen--;
} else if (align === 'right') {
cell = cell.substring(1);
clen--;
}
}
text += cell;
});
if (!isFooter) {
text += '\n\n';
}
});
delete this.align;
this.setContent(text);
this.align = align;
};
Table.prototype.render = function() {
var self = this;
var coords = this._render();
if (!coords) return;
this._calculateMaxes();
if (!this._maxes) return coords;
var lines = this.screen.lines
, xi = coords.xi
, yi = coords.yi
, rx
, ry
, i;
var dattr = this.sattr(this.style)
, hattr = this.sattr(this.style.header)
, cattr = this.sattr(this.style.cell)
, battr = this.sattr(this.style.border);
var width = coords.xl - coords.xi - this.iright
, height = coords.yl - coords.yi - this.ibottom;
// Apply attributes to header cells and cells.
for (var y = this.itop; y < height; y++) {
if (!lines[yi + y]) break;
for (var x = this.ileft; x < width; x++) {
if (!lines[yi + y][xi + x]) break;
// Check to see if it's not the default attr. Allows for tags:
if (lines[yi + y][xi + x][0] !== dattr) continue;
if (y === this.itop) {
lines[yi + y][xi + x][0] = hattr;
} else {
lines[yi + y][xi + x][0] = cattr;
}
lines[yi + y].dirty = true;
}
}
if (!this.border || this.options.noCellBorders) return coords;
// Draw border with correct angles.
ry = 0;
for (i = 0; i < self.rows.length + 1; i++) {
if (!lines[yi + ry]) break;
rx = 0;
self._maxes.forEach(function(max, i) {
rx += max;
if (i === 0) {
if (!lines[yi + ry][xi + 0]) return;
// left side
if (ry === 0) {
// top
lines[yi + ry][xi + 0][0] = battr;
// lines[yi + ry][xi + 0][1] = '\u250c'; // '┌'
} else if (ry / 2 === self.rows.length) {
// bottom
lines[yi + ry][xi + 0][0] = battr;
// lines[yi + ry][xi + 0][1] = '\u2514'; // '└'
} else {
// middle
lines[yi + ry][xi + 0][0] = battr;
lines[yi + ry][xi + 0][1] = '\u251c'; // '├'
// XXX If we alter iwidth and ileft for no borders - nothing should be written here
if (!self.border.left) {
lines[yi + ry][xi + 0][1] = '\u2500'; // '─'
}
}
lines[yi + ry].dirty = true;
} else if (i === self._maxes.length - 1) {
if (!lines[yi + ry][xi + rx + 1]) return;
// right side
if (ry === 0) {
// top
rx++;
lines[yi + ry][xi + rx][0] = battr;
// lines[yi + ry][xi + rx][1] = '\u2510'; // '┐'
} else if (ry / 2 === self.rows.length) {
// bottom
rx++;
lines[yi + ry][xi + rx][0] = battr;
// lines[yi + ry][xi + rx][1] = '\u2518'; // '┘'
} else {
// middle
rx++;
lines[yi + ry][xi + rx][0] = battr;
lines[yi + ry][xi + rx][1] = '\u2524'; // '┤'
// XXX If we alter iwidth and iright for no borders - nothing should be written here
if (!self.border.right) {
lines[yi + ry][xi + rx][1] = '\u2500'; // '─'
}
}
lines[yi + ry].dirty = true;
return;
}
if (!lines[yi + ry][xi + rx + 1]) return;
// center
if (ry === 0) {
// top
rx++;
lines[yi + ry][xi + rx][0] = battr;
lines[yi + ry][xi + rx][1] = '\u252c'; // '┬'
// XXX If we alter iheight and itop for no borders - nothing should be written here
if (!self.border.top) {
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
}
} else if (ry / 2 === self.rows.length) {
// bottom
rx++;
lines[yi + ry][xi + rx][0] = battr;
lines[yi + ry][xi + rx][1] = '\u2534'; // '┴'
// XXX If we alter iheight and ibottom for no borders - nothing should be written here
if (!self.border.bottom) {
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
}
} else {
// middle
if (self.options.fillCellBorders) {
var lbg = (ry <= 2 ? hattr : cattr) & 0x1ff;
rx++;
lines[yi + ry][xi + rx][0] = (battr & ~0x1ff) | lbg;
} else {
rx++;
lines[yi + ry][xi + rx][0] = battr;
}
lines[yi + ry][xi + rx][1] = '\u253c'; // '┼'
// rx++;
}
lines[yi + ry].dirty = true;
});
ry += 2;
}
// Draw internal borders.
for (ry = 1; ry < self.rows.length * 2; ry++) {
if (!lines[yi + ry]) break;
rx = 0;
self._maxes.slice(0, -1).forEach(function(max) {
rx += max;
if (!lines[yi + ry][xi + rx + 1]) return;
if (ry % 2 !== 0) {
if (self.options.fillCellBorders) {
var lbg = (ry <= 2 ? hattr : cattr) & 0x1ff;
rx++;
lines[yi + ry][xi + rx][0] = (battr & ~0x1ff) | lbg;
} else {
rx++;
lines[yi + ry][xi + rx][0] = battr;
}
lines[yi + ry][xi + rx][1] = '\u2502'; // '│'
lines[yi + ry].dirty = true;
} else {
rx++;
}
});
rx = 1;
self._maxes.forEach(function(max) {
while (max--) {
if (ry % 2 === 0) {
if (!lines[yi + ry]) break;
if (!lines[yi + ry][xi + rx + 1]) break;
if (self.options.fillCellBorders) {
var lbg = (ry <= 2 ? hattr : cattr) & 0x1ff;
lines[yi + ry][xi + rx][0] = (battr & ~0x1ff) | lbg;
} else {
lines[yi + ry][xi + rx][0] = battr;
}
lines[yi + ry][xi + rx][1] = '\u2500'; // '─'
lines[yi + ry].dirty = true;
}
rx++;
}
rx++;
});
}
return coords;
};
/**
* Expose
*/
module.exports = Table;

412
lib/widgets/terminal.js Normal file
View File

@ -0,0 +1,412 @@
/**
* terminal.js - term.js terminal element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var nextTick = global.setImmediate || process.nextTick.bind(process);
var Node = require('./node');
var Box = require('./box');
/**
* Terminal
*/
function Terminal(options) {
if (!(this instanceof Node)) {
return new Terminal(options);
}
options = options || {};
options.scrollable = false;
Box.call(this, options);
// XXX Workaround for all motion
if (this.screen.program.tmux && this.screen.program.tmuxVersion >= 2) {
this.screen.program.enableMouse();
}
this.handler = options.handler;
this.shell = options.shell || process.env.SHELL || 'sh';
this.args = options.args || [];
this.cursor = this.options.cursor;
this.cursorBlink = this.options.cursorBlink;
this.screenKeys = this.options.screenKeys;
this.style = this.style || {};
this.style.bg = this.style.bg || 'default';
this.style.fg = this.style.fg || 'default';
this.termName = options.terminal
|| options.term
|| process.env.TERM
|| 'xterm';
this.bootstrap();
}
Terminal.prototype.__proto__ = Box.prototype;
Terminal.prototype.type = 'terminal';
Terminal.prototype.bootstrap = function() {
var self = this;
var element = {
// window
get document() { return element; },
navigator: { userAgent: 'node.js' },
// document
get defaultView() { return element; },
get documentElement() { return element; },
createElement: function() { return element; },
// element
get ownerDocument() { return element; },
addEventListener: function() {},
removeEventListener: function() {},
getElementsByTagName: function() { return [element]; },
getElementById: function() { return element; },
parentNode: null,
offsetParent: null,
appendChild: function() {},
removeChild: function() {},
setAttribute: function() {},
getAttribute: function() {},
style: {},
focus: function() {},
blur: function() {},
console: console
};
element.parentNode = element;
element.offsetParent = element;
this.term = require('term.js')({
termName: this.termName,
cols: this.width - this.iwidth,
rows: this.height - this.iheight,
context: element,
document: element,
body: element,
parent: element,
cursorBlink: this.cursorBlink,
screenKeys: this.screenKeys
});
this.term.refresh = function() {
self.screen.render();
};
this.term.keyDown = function() {};
this.term.keyPress = function() {};
this.term.open(element);
// Emits key sequences in html-land.
// Technically not necessary here.
// In reality if we wanted to be neat, we would overwrite the keyDown and
// keyPress methods with our own node.js-keys->terminal-keys methods, but
// since all the keys are already coming in as escape sequences, we can just
// send the input directly to the handler/socket (see below).
// this.term.on('data', function(data) {
// self.handler(data);
// });
// Incoming keys and mouse inputs.
// NOTE: Cannot pass mouse events - coordinates will be off!
this.screen.program.input.on('data', this._onData = function(data) {
if (self.screen.focused === self && !self._isMouse(data)) {
self.handler(data);
}
});
this.onScreenEvent('mouse', function(data) {
if (self.screen.focused !== self) return;
if (data.x < self.aleft + self.ileft) return;
if (data.y < self.atop + self.itop) return;
if (data.x > self.aleft - self.ileft + self.width) return;
if (data.y > self.atop - self.itop + self.height) return;
if (self.term.x10Mouse
|| self.term.vt200Mouse
|| self.term.normalMouse
|| self.term.mouseEvents
|| self.term.utfMouse
|| self.term.sgrMouse
|| self.term.urxvtMouse) {
;
} else {
return;
}
var b = data.raw[0]
, x = data.x - self.aleft
, y = data.y - self.atop
, s;
if (self.term.urxvtMouse) {
if (self.screen.program.sgrMouse) {
b += 32;
}
s = '\x1b[' + b + ';' + (x + 32) + ';' + (y + 32) + 'M';
} else if (self.term.sgrMouse) {
if (!self.screen.program.sgrMouse) {
b -= 32;
}
s = '\x1b[<' + b + ';' + x + ';' + y
+ (data.action === 'mousedown' ? 'M' : 'm');
} else {
if (self.screen.program.sgrMouse) {
b += 32;
}
s = '\x1b[M'
+ String.fromCharCode(b)
+ String.fromCharCode(x + 32)
+ String.fromCharCode(y + 32);
}
self.handler(s);
});
this.on('focus', function() {
self.term.focus();
});
this.on('blur', function() {
self.term.blur();
});
this.term.on('title', function(title) {
self.title = title;
self.emit('title', title);
});
this.term.on('passthrough', function(data) {
self.screen.program.flush();
self.screen.program._owrite(data);
});
this.on('resize', function() {
nextTick(function() {
self.term.resize(self.width - self.iwidth, self.height - self.iheight);
});
});
this.once('render', function() {
self.term.resize(self.width - self.iwidth, self.height - self.iheight);
});
this.on('destroy', function() {
self.kill();
self.screen.program.input.removeListener('data', self._onData);
});
if (this.handler) {
return;
}
this.pty = require('pty.js').fork(this.shell, this.args, {
name: this.termName,
cols: this.width - this.iwidth,
rows: this.height - this.iheight,
cwd: process.env.HOME,
env: this.options.env || process.env
});
this.on('resize', function() {
nextTick(function() {
try {
self.pty.resize(self.width - self.iwidth, self.height - self.iheight);
} catch (e) {
;
}
});
});
this.handler = function(data) {
self.pty.write(data);
self.screen.render();
};
this.pty.on('data', function(data) {
self.write(data);
self.screen.render();
});
this.pty.on('exit', function(code) {
self.emit('exit', code || null);
});
this.onScreenEvent('keypress', function() {
self.screen.render();
});
this.screen._listenKeys(this);
};
Terminal.prototype.write = function(data) {
return this.term.write(data);
};
Terminal.prototype.render = function() {
var ret = this._render();
if (!ret) return;
this.dattr = this.sattr(this.style);
var xi = ret.xi + this.ileft
, xl = ret.xl - this.iright
, yi = ret.yi + this.itop
, yl = ret.yl - this.ibottom
, cursor;
var scrollback = this.term.lines.length - (yl - yi);
for (var y = Math.max(yi, 0); y < yl; y++) {
var line = this.screen.lines[y];
if (!line || !this.term.lines[scrollback + y - yi]) break;
if (y === yi + this.term.y
&& this.term.cursorState
&& this.screen.focused === this
&& (this.term.ydisp === this.term.ybase || this.term.selectMode)
&& !this.term.cursorHidden) {
cursor = xi + this.term.x;
} else {
cursor = -1;
}
for (var x = Math.max(xi, 0); x < xl; x++) {
if (!line[x] || !this.term.lines[scrollback + y - yi][x - xi]) break;
line[x][0] = this.term.lines[scrollback + y - yi][x - xi][0];
if (x === cursor) {
if (this.cursor === 'line') {
line[x][0] = this.dattr;
line[x][1] = '\u2502';
continue;
} else if (this.cursor === 'underline') {
line[x][0] = this.dattr | (2 << 18);
} else if (this.cursor === 'block' || !this.cursor) {
line[x][0] = this.dattr | (8 << 18);
}
}
line[x][1] = this.term.lines[scrollback + y - yi][x - xi][1];
// default foreground = 257
if (((line[x][0] >> 9) & 0x1ff) === 257) {
line[x][0] &= ~(0x1ff << 9);
line[x][0] |= ((this.dattr >> 9) & 0x1ff) << 9;
}
// default background = 256
if ((line[x][0] & 0x1ff) === 256) {
line[x][0] &= ~0x1ff;
line[x][0] |= this.dattr & 0x1ff;
}
}
line.dirty = true;
}
return ret;
};
Terminal.prototype._isMouse = function(buf) {
var s = buf;
if (Buffer.isBuffer(s)) {
if (s[0] > 127 && s[1] === undefined) {
s[0] -= 128;
s = '\x1b' + s.toString('utf-8');
} else {
s = s.toString('utf-8');
}
}
return (buf[0] === 0x1b && buf[1] === 0x5b && buf[2] === 0x4d)
|| /^\x1b\[M([\x00\u0020-\uffff]{3})/.test(s)
|| /^\x1b\[(\d+;\d+;\d+)M/.test(s)
|| /^\x1b\[<(\d+;\d+;\d+)([mM])/.test(s)
|| /^\x1b\[<(\d+;\d+;\d+;\d+)&w/.test(s)
|| /^\x1b\[24([0135])~\[(\d+),(\d+)\]\r/.test(s)
|| /^\x1b\[(O|I)/.test(s);
};
Terminal.prototype.setScroll =
Terminal.prototype.scrollTo = function(offset) {
this.term.ydisp = offset;
return this.emit('scroll');
};
Terminal.prototype.getScroll = function() {
return this.term.ydisp;
};
Terminal.prototype.scroll = function(offset) {
this.term.scrollDisp(offset);
return this.emit('scroll');
};
Terminal.prototype.resetScroll = function() {
this.term.ydisp = 0;
this.term.ybase = 0;
return this.emit('scroll');
};
Terminal.prototype.getScrollHeight = function() {
return this.term.rows - 1;
};
Terminal.prototype.getScrollPerc = function() {
return (this.term.ydisp / this.term.ybase) * 100;
};
Terminal.prototype.setScrollPerc = function(i) {
return this.setScroll((i / 100) * this.term.ybase | 0);
};
Terminal.prototype.screenshot = function(xi, xl, yi, yl) {
xi = 0 + (xi || 0);
if (xl != null) {
xl = 0 + (xl || 0);
} else {
xl = this.term.lines[0].length;
}
yi = 0 + (yi || 0);
if (yl != null) {
yl = 0 + (yl || 0);
} else {
yl = this.term.lines.length;
}
return this.screen.screenshot(xi, xl, yi, yl, this.term);
};
Terminal.prototype.kill = function() {
if (this.pty) {
this.pty.destroy();
this.pty.kill();
}
this.term.refresh = function() {};
this.term.write('\x1b[H\x1b[J');
if (this.term._blink) {
clearInterval(this.term._blink);
}
this.term.destroy();
};
/**
* Expose
*/
module.exports = Terminal;

35
lib/widgets/text.js Normal file
View File

@ -0,0 +1,35 @@
/**
* text.js - text element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Element = require('./element');
/**
* Text
*/
function Text(options) {
if (!(this instanceof Node)) {
return new Text(options);
}
options = options || {};
options.shrink = true;
Element.call(this, options);
}
Text.prototype.__proto__ = Element.prototype;
Text.prototype.type = 'text';
/**
* Expose
*/
module.exports = Text;

342
lib/widgets/textarea.js Normal file
View File

@ -0,0 +1,342 @@
/**
* textarea.js - textarea element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var unicode = require('../unicode');
var nextTick = global.setImmediate || process.nextTick.bind(process);
var Node = require('./node');
var Input = require('./input');
/**
* Textarea
*/
function Textarea(options) {
var self = this;
if (!(this instanceof Node)) {
return new Textarea(options);
}
options = options || {};
options.scrollable = options.scrollable !== false;
Input.call(this, options);
this.screen._listenKeys(this);
this.value = options.value || '';
this.__updateCursor = this._updateCursor.bind(this);
this.on('resize', this.__updateCursor);
this.on('move', this.__updateCursor);
if (options.inputOnFocus) {
this.on('focus', this.readInput.bind(this, null));
}
if (!options.inputOnFocus && options.keys) {
this.on('keypress', function(ch, key) {
if (self._reading) return;
if (key.name === 'enter' || (options.vi && key.name === 'i')) {
return self.readInput();
}
if (key.name === 'e') {
return self.readEditor();
}
});
}
if (options.mouse) {
this.on('click', function(data) {
if (self._reading) return;
if (data.button !== 'right') return;
self.readEditor();
});
}
}
Textarea.prototype.__proto__ = Input.prototype;
Textarea.prototype.type = 'textarea';
Textarea.prototype._updateCursor = function(get) {
if (this.screen.focused !== this) {
return;
}
var lpos = get ? this.lpos : this._getCoords();
if (!lpos) return;
var last = this._clines[this._clines.length - 1]
, program = this.screen.program
, line
, cx
, cy;
// Stop a situation where the textarea begins scrolling
// and the last cline appears to always be empty from the
// _typeScroll `+ '\n'` thing.
// Maybe not necessary anymore?
if (last === '' && this.value[this.value.length - 1] !== '\n') {
last = this._clines[this._clines.length - 2] || '';
}
line = Math.min(
this._clines.length - 1 - (this.childBase || 0),
(lpos.yl - lpos.yi) - this.iheight - 1);
// When calling clearValue() on a full textarea with a border, the first
// argument in the above Math.min call ends up being -2. Make sure we stay
// positive.
line = Math.max(0, line);
cy = lpos.yi + this.itop + line;
cx = lpos.xi + this.ileft + this.strWidth(last);
// XXX Not sure, but this may still sometimes
// cause problems when leaving editor.
if (cy === program.y && cx === program.x) {
return;
}
if (cy === program.y) {
if (cx > program.x) {
program.cuf(cx - program.x);
} else if (cx < program.x) {
program.cub(program.x - cx);
}
} else if (cx === program.x) {
if (cy > program.y) {
program.cud(cy - program.y);
} else if (cy < program.y) {
program.cuu(program.y - cy);
}
} else {
program.cup(cy, cx);
}
};
Textarea.prototype.input =
Textarea.prototype.setInput =
Textarea.prototype.readInput = function(callback) {
var self = this
, focused = this.screen.focused === this;
if (this._reading) return;
this._reading = true;
this._callback = callback;
if (!focused) {
this.screen.saveFocus();
this.focus();
}
this.screen.grabKeys = true;
this._updateCursor();
this.screen.program.showCursor();
//this.screen.program.sgr('normal');
this._done = function fn(err, value) {
if (!self._reading) return;
if (fn.done) return;
fn.done = true;
self._reading = false;
delete self._callback;
delete self._done;
self.removeListener('keypress', self.__listener);
delete self.__listener;
self.removeListener('blur', self.__done);
delete self.__done;
self.screen.program.hideCursor();
self.screen.grabKeys = false;
if (!focused) {
self.screen.restoreFocus();
}
if (self.options.inputOnFocus) {
self.screen.rewindFocus();
}
// Ugly
if (err === 'stop') return;
if (err) {
self.emit('error', err);
} else if (value != null) {
self.emit('submit', value);
} else {
self.emit('cancel', value);
}
self.emit('action', value);
if (!callback) return;
return err
? callback(err)
: callback(null, value);
};
// Put this in a nextTick so the current
// key event doesn't trigger any keys input.
nextTick(function() {
self.__listener = self._listener.bind(self);
self.on('keypress', self.__listener);
});
this.__done = this._done.bind(this, null, null);
this.on('blur', this.__done);
};
Textarea.prototype._listener = function(ch, key) {
var done = this._done
, value = this.value;
if (key.name === 'return') return;
if (key.name === 'enter') {
ch = '\n';
}
// TODO: Handle directional keys.
if (key.name === 'left' || key.name === 'right'
|| key.name === 'up' || key.name === 'down') {
;
}
if (this.options.keys && key.ctrl && key.name === 'e') {
return this.readEditor();
}
// TODO: Optimize typing by writing directly
// to the screen and screen buffer here.
if (key.name === 'escape') {
done(null, null);
} else if (key.name === 'backspace') {
if (this.value.length) {
if (this.screen.fullUnicode) {
if (unicode.isSurrogate(this.value, this.value.length - 2)) {
// || unicode.isCombining(this.value, this.value.length - 1)) {
this.value = this.value.slice(0, -2);
} else {
this.value = this.value.slice(0, -1);
}
} else {
this.value = this.value.slice(0, -1);
}
}
} else if (ch) {
if (!/^[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]$/.test(ch)) {
this.value += ch;
}
}
if (this.value !== value) {
this.screen.render();
}
};
Textarea.prototype._typeScroll = function() {
// XXX Workaround
var height = this.height - this.iheight;
if (this._clines.length - this.childBase > height) {
this.scroll(this._clines.length);
}
};
Textarea.prototype.getValue = function() {
return this.value;
};
Textarea.prototype.setValue = function(value) {
if (value == null) {
value = this.value;
}
if (this._value !== value) {
this.value = value;
this._value = value;
this.setContent(this.value);
this._typeScroll();
this._updateCursor();
}
};
Textarea.prototype.clearInput =
Textarea.prototype.clearValue = function() {
return this.setValue('');
};
Textarea.prototype.submit = function() {
if (!this.__listener) return;
return this.__listener('\x1b', { name: 'escape' });
};
Textarea.prototype.cancel = function() {
if (!this.__listener) return;
return this.__listener('\x1b', { name: 'escape' });
};
Textarea.prototype.render = function() {
this.setValue();
return this._render();
};
Textarea.prototype.editor =
Textarea.prototype.setEditor =
Textarea.prototype.readEditor = function(callback) {
var self = this;
if (this._reading) {
var _cb = this._callback
, cb = callback;
this._done('stop');
callback = function(err, value) {
if (_cb) _cb(err, value);
if (cb) cb(err, value);
};
}
if (!callback) {
callback = function() {};
}
return this.screen.readEditor({ value: this.value }, function(err, value) {
if (err) {
if (err.message === 'Unsuccessful.') {
self.screen.render();
return self.readInput(callback);
}
self.screen.render();
self.readInput(callback);
return callback(err);
}
self.setValue(value);
self.screen.render();
return self.readInput(callback);
});
};
/**
* Expose
*/
module.exports = Textarea;

77
lib/widgets/textbox.js Normal file
View File

@ -0,0 +1,77 @@
/**
* textbox.js - textbox element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var Node = require('./node');
var Textarea = require('./textarea');
/**
* Textbox
*/
function Textbox(options) {
if (!(this instanceof Node)) {
return new Textbox(options);
}
options = options || {};
options.scrollable = false;
Textarea.call(this, options);
this.secret = options.secret;
this.censor = options.censor;
}
Textbox.prototype.__proto__ = Textarea.prototype;
Textbox.prototype.type = 'textbox';
Textbox.prototype.__olistener = Textbox.prototype._listener;
Textbox.prototype._listener = function(ch, key) {
if (key.name === 'enter') {
this._done(null, this.value);
return;
}
return this.__olistener(ch, key);
};
Textbox.prototype.setValue = function(value) {
var visible, val;
if (value == null) {
value = this.value;
}
if (this._value !== value) {
value = value.replace(/\n/g, '');
this.value = value;
this._value = value;
if (this.secret) {
this.setContent('');
} else if (this.censor) {
this.setContent(Array(this.value.length + 1).join('*'));
} else {
visible = -(this.width - this.iwidth - 1);
val = this.value.replace(/\t/g, this.screen.tabc);
this.setContent(val.slice(visible));
}
this._updateCursor();
}
};
Textbox.prototype.submit = function() {
if (!this.__listener) return;
return this.__listener('\r', { name: 'enter' });
};
/**
* Expose
*/
module.exports = Textbox;

126
lib/widgets/video.js Normal file
View File

@ -0,0 +1,126 @@
/**
* video.js - video element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var cp = require('child_process');
var Node = require('./node');
var Box = require('./box');
var Terminal = require('./terminal');
/**
* Video
*/
function Video(options) {
var self = this
, shell
, args;
if (!(this instanceof Node)) {
return new Video(options);
}
options = options || {};
Box.call(this, options);
if (this.exists('mplayer')) {
shell = 'mplayer';
args = ['-vo', 'caca', '-quiet', options.file];
} else if (this.exists('mpv')) {
shell = 'mpv';
args = ['--vo', 'caca', '--really-quiet', options.file];
} else {
this.parseTags = true;
this.setContent('{red-fg}{bold}Error:{/bold}'
+ ' mplayer or mpv not installed.{/red-fg}');
return this;
}
var opts = {
parent: this,
left: 0,
top: 0,
width: this.width - this.iwidth,
height: this.height - this.iheight,
shell: shell,
args: args.slice()
};
this.now = Date.now() / 1000 | 0;
this.start = opts.start || 0;
if (this.start) {
if (shell === 'mplayer') {
opts.args.unshift('-ss', this.start + '');
} else if (shell === 'mpv') {
opts.args.unshift('--start', this.start + '');
}
}
var DISPLAY = process.env.DISPLAY;
delete process.env.DISPLAY;
this.tty = new Terminal(opts);
process.env.DISPLAY = DISPLAY;
this.on('click', function() {
self.tty.pty.write('p');
});
// mplayer/mpv cannot resize itself in the terminal, so we have
// to restart it at the correct start time.
this.on('resize', function() {
self.tty.destroy();
var opts = {
parent: self,
left: 0,
top: 0,
width: self.width - self.iwidth,
height: self.height - self.iheight,
shell: shell,
args: args.slice()
};
var watched = (Date.now() / 1000 | 0) - self.now;
self.now = Date.now() / 1000 | 0;
self.start += watched;
if (shell === 'mplayer') {
opts.args.unshift('-ss', self.start + '');
} else if (shell === 'mpv') {
opts.args.unshift('--start', self.start + '');
}
var DISPLAY = process.env.DISPLAY;
delete process.env.DISPLAY;
self.tty = new Terminal(opts);
process.env.DISPLAY = DISPLAY;
self.screen.render();
});
}
Video.prototype.__proto__ = Box.prototype;
Video.prototype.type = 'video';
Video.prototype.exists = function(program) {
try {
return !!+cp.execSync('type '
+ program + ' > /dev/null 2> /dev/null'
+ ' && echo 1', { encoding: 'utf8' }).trim();
} catch (e) {
return false;
}
};
/**
* Expose
*/
module.exports = Video;

View File

@ -1,13 +1,21 @@
{
"name": "blessed",
"description": "A curses-like library for node.js.",
"description": "A high-level terminal interface library for node.js.",
"author": "Christopher Jeffrey",
"version": "0.0.2",
"main": "./lib/program.js",
"version": "0.1.81",
"license": "MIT",
"main": "./lib/blessed.js",
"bin": "./bin/tput.js",
"preferGlobal": false,
"repository": "git://github.com/chjj/blessed.git",
"homepage": "https://github.com/chjj/blessed",
"bugs": { "url": "http://github.com/chjj/blessed/issues" },
"keywords": ["curses", "tui"],
"tags": ["curses", "tui"],
"scripts": { "test": "node test", "bench": "node test --bench" }
"keywords": ["curses", "tui", "tput", "terminfo", "termcap"],
"tags": ["curses", "tui", "tput", "terminfo", "termcap"],
"engines": {
"node": ">= 0.8.0"
},
"browserify": {
"transform": ["./browser/transform.js"]
}
}

143
test/git.diff Normal file
View File

@ -0,0 +1,143 @@
diff --git a/lib/widget.js b/lib/widget.js
index 8785046..4bfefd3 100644
--- a/lib/widget.js
+++ b/lib/widget.js
@@ -511,6 +511,9 @@ Element.prototype.__defineGetter__('left', function() {
});

Element.prototype.__defineGetter__('right', function() {
+ //if (this.options.right == null && this.options.left != null) {
+ // return this.screen.cols - (this.left + this.width);
+ //}
return (this.parent.right || 0) + this.position.right;
});

@@ -532,6 +535,9 @@ Element.prototype.__defineGetter__('top', function() {
});

Element.prototype.__defineGetter__('bottom', function() {
+ //if (this.options.bottom == null && this.options.top != null) {
+ // return this.screen.rows - (this.top + this.height);
+ //}
return (this.parent.bottom || 0) + this.position.bottom;
});

@@ -671,7 +677,20 @@ Box.prototype.render = function(stop) {
var cb = this.childBase
, xxl = xl - (this.border ? 1 : 0)
, xxi;
- while (cb--) for (xxi = xi + (this.border ? 1 : 0); xxi < xxl; xxi++) ci++;
+ while (cb--) {
+ for (xxi = xi + (this.border ? 1 : 0); xxi < xxl; xxi++) {
+ if (this.content[ci] === '\n' || this.content[ci] === '\r') {
+ ci++;
+ if (!cb) break;
+ cb--;
+ } else if (this.content[ci] === '\x1b') {
+ for (; ci < this.content.length; ci++) {
+ if (this.content[ci] === 'm') break;
+ }
+ }
+ ci++;
+ }
+ }
}

var ret = {
@@ -683,6 +702,8 @@ Box.prototype.render = function(stop) {

if (stop) return ret;

+ var lastEscape, hasEscapes, c;
+
for (; yi < yl; yi++) {
if (!lines[yi]) break;
for (xi = this.left; xi < xl; xi++) {
@@ -708,22 +729,52 @@ Box.prototype.render = function(stop) {
} else {
attr = ((this.bold << 18) + (this.underline << 18)) | (this.fg << 9) | this.bg;
ch = this.content[ci++] || ' ';
+
+ // Handle escape codes.
+ // NOTE: We could also change around `attr`, that might be cleaner.
+ // NOTE: Currently, this will not work with newline handling.
+ if (lastEscape) {
+ ch = lastEscape + ch;
+ lastEscape = '';
+ }
+ if (ch === '\x1b') {
+ hasEscapes = true;
+ if (c = /^\x1b\[\d+(?:;\d+)*m/.exec(this.content.substring(ci - 1))) {
+ ci += c[0].length - 1;
+ if (!this.content[c[0].length]) {
+ // Problem: No character to put here
+ // needs to wrap around below.
+ lastEscape = c[0];
+ ch = ' ';
+ } else {
+ ch = c[0] + this.content[ci];
+ }
+ ci++;
+ }
+ }
+ if (hasEscapes && xi === xl - 1) {
+ ch += '\x1b[m';
+ }
}

- // TODO: Allow newlines.
- //if (ch === '\n' || ch === '\r') {
- // ch = ' ';
- // xl = xl - 1 - (this.border ? 1 : 0);
- // for (; xi < xl; xi++) {
- // cell = lines[yi][xi];
- // if (!cell) break;
- // if (attr !== cell[0] || ch !== cell[1]) {
- // lines[yi][xi][0] = attr;
- // lines[yi][xi][1] = ch;
- // lines[yi].dirty = true;
- // }
- // }
- //}
+ // Handle newlines.
+ if (ch === '\n' || ch === '\r') {
+ ch = ' ';
+ if (hasEscapes) ch += '\x1b[m';
+ var xxl = xl - (this.border ? 1 : 0);
+ for (; xi < xxl; xi++) {
+ attr = ((this.bold << 18) + (this.underline << 18)) | (this.fg << 9) | this.bg;
+ cell = lines[yi][xi];
+ if (!cell) break;
+ if (attr !== cell[0] || ch !== cell[1]) {
+ lines[yi][xi][0] = attr;
+ lines[yi][xi][1] = ch;
+ lines[yi].dirty = true;
+ }
+ }
+ if (this.border) xi--;
+ continue;
+ }

if (attr !== cell[0] || ch !== cell[1]) {
lines[yi][xi][0] = attr;
@@ -958,6 +1009,7 @@ List.prototype.__proto__ = ScrollableBox.prototype;
List.prototype.add = function(item) {
var self = this;

+ // TODO: Use box here and get rid of text.
var item = new Text({
screen: this.screen,
parent: this,
diff --git a/test/widget.js b/test/widget.js
index a392a0e..1e62e8c 100644
--- a/test/widget.js
+++ b/test/widget.js
@@ -136,7 +136,7 @@ var progress = new blessed.ProgressBar({

screen.append(progress);

-var lorem = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';
+var lorem = 'Lorem ipsum \x1b[41mdolor sit amet, \nconsectetur adipisicing elit, \x1b[43msed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.';

var stext = new blessed.ScrollableText({
screen: screen,

5
test/helpers.js Normal file
View File

@ -0,0 +1,5 @@
var blessed = require('../'),
screen = blessed.screen();
console.log(blessed.helpers.parseTags('{red-fg}This should be red.{/red-fg}'));
console.log(blessed.helpers.parseTags('{green-bg}This should have a green background.{/green-bg}'));

1
test/logs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*

1
test/lorem.txt Normal file
View File

@ -0,0 +1 @@
Non eram nescius Brute cum quae summis ingeniis exquisitaque doctrina philosophi Graeco sermone tractavissent ea Latinis litteris mandaremus fore ut hic noster labor in varias reprehensiones incurreret nam quibusdam et iis quidem non admodum indoctis totum hoc displicet philosophari quidam autem non tam id reprehendunt si remissius agatur sed tantum studium tamque multam operam ponendam in eo non arbitrantur erunt etiam et ii quidem eruditi Graecis litteris contemnentes Latinas qui se dicant in Graecis legendis operam malle consumere postremo aliquos futuros suspicor qui me ad alias litteras vocent genus hoc scribendi etsi sit elegans personae tamen et dignitatis esse negent Contra quos omnis dicendum breviter existimo Quamquam philosophiae quidem vituperatoribus satis responsum est eo libro quo a nobis philosophia defensa et collaudata est cum esset accusata et vituperata ab Hortensio qui liber cum et tibi probatus videretur et iis quos ego posse iudicare arbitrarer plura suscepi veritus ne movere hominum studia viderer retinere non posse Qui autem si maxime hoc placeat moderatius tamen id volunt fieri difficilem quandam temperantiam postulant in eo quod semel admissum coerceri reprimique non potest ut propemodum iustioribus utamur illis qui omnino avocent a philosophia quam his qui rebus infinitis modum constituant in reque eo meliore quo maior sit mediocritatem desiderent Sive enim ad sapientiam perveniri potest non paranda nobis solum ea sed fruenda etiam sapientia est sive hoc difficile est tamen nec modus est ullus investigandi veri nisi inveneris et quaerendi defatigatio turpis est cum id quod quaeritur sit pulcherrimum etenim si delectamur cum scribimus quis est tam invidus qui ab eo nos abducat sin laboramus quis est qui alienae modum statuat industriae nam ut Terentianus Chremes non inhumanus qui novum vicinum non vult fodere aut arare aut aliquid ferre denique non enim illum ab industria sed ab inliberali labore deterret sic isti curiosi quos offendit noster minime nobis iniucundus labor Iis igitur est difficilius satis facere qui se Latina scripta dicunt contemnere in quibus hoc primum est in quo admirer cur in gravissimis rebus non delectet eos sermo patrius cum idem fabellas Latinas ad verbum e Graecis expressas non inviti legant quis enim tam inimicus paene nomini Romano est qui Ennii Medeam aut Antiopam Pacuvii spernat aut reiciat quod se isdem Euripidis fabulis delectari dicat Latinas litteras oderit Quid si nos non interpretum fungimur munere sed tuemur ea quae dicta sunt ab iis quos probamus eisque nostrum iudicium et nostrum scribendi ordinem adiungimus quid habent cur Graeca anteponant iis quae et splendide dicta sint neque sint conversa de Graecis nam si dicent ab illis has res esse tractatas ne ipsos quidem Graecos est cur tam multos legant quam legendi sunt quid enim est a Chrysippo praetermissum in Stoicis legimus tamen Diogenem Antipatrum Mnesarchum Panaetium multos alios in primisque familiarem nostrum Posidonium quid Theophrastus mediocriterne delectat cum tractat locos ab Aristotele ante tractatos quid Epicurei num desistunt de isdem de quibus et ab Epicuro scriptum est et ab antiquis ad arbitrium suum scribere quodsi Graeci leguntur a Graecis isdem de rebus alia ratione compositis quid est cur nostri a nostris non legantur

80
test/program-mouse.js Executable file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env node
var blessed = require('../')
, util = require('util')
, program;
program = blessed.program({
dump: __dirname + '/logs/mouse.log'
});
// program.setMouse({
// allMotion: true,
// //utfMouse: true
// urxvtMouse: true
// }, true);
program.alternateBuffer();
program.enableMouse();
program.hideCursor();
program.setMouse({ sendFocus: true }, true);
//program._currentMouse.sendFocus = true;
//program.enableMouse(program._currentMouse);
//program.write('\x1b[?1004h');
program.on('mouse', function(data) {
program.cup(data.y, data.x);
program.write(' ', 'blue bg');
program.cup(0, 0);
program.write(util.inspect(data));
});
program.on('resize', function(data) {
setTimeout(function() {
program.clear();
program.cup(0, 0);
program.write(util.inspect({ cols: program.cols, rows: program.rows }));
}, 200);
});
process.on('SIGWINCH', function(data) {
setTimeout(function() {
program.cup(1, 0);
program.write(util.inspect({ winch: true, cols: program.cols, rows: program.rows }));
}, 200);
});
program.on('focus', function(data) {
program.clear();
program.cup(0, 0);
program.write('FOCUSIN');
});
program.on('blur', function(data) {
program.clear();
program.cup(0, 0);
program.write('FOCUSOUT');
});
program.key(['q', 'escape', 'C-c'], function() {
program.showCursor();
program.disableMouse();
program.normalBuffer();
process.exit(0);
});
program.on('keypress', function(ch, data) {
if (data.name === 'mouse') return;
program.clear();
program.cup(0, 0);
program.write(util.inspect(data));
});
// program.getCursor(function(err, data) {
// program.write(util.inspect(data));
// });
// program.manipulateWindow(18, function(err, data) {
// program.write(util.inspect(data));
// });

70
test/tail.js Normal file
View File

@ -0,0 +1,70 @@
// `tail -f` a file.
module.exports = function(file) {
var self = this
, fs = require('fs')
, StringDecoder = require('string_decoder').StringDecoder
, decode = new StringDecoder('utf8')
, buffer = new Buffer(64 * 1024)
, Stream = require('stream').Stream
, s = new Stream
, buff = ''
, pos = 0;
s.readable = true;
s.destroy = function() {
s.destroyed = true;
s.emit('end');
s.emit('close');
};
fs.open(file, 'a+', 0644, function(err, fd) {
if (err) {
s.emit('error', err);
s.destroy();
return;
}
(function read() {
if (s.destroyed) {
fs.close(fd);
return;
}
return fs.read(fd, buffer, 0, buffer.length, pos, function(err, bytes) {
if (err) {
s.emit('error', err);
s.destroy();
return;
}
if (!bytes) {
if (buff) {
stream.emit('line', buff);
buff = '';
}
return setTimeout(read, 1000);
}
var data = decode.write(buffer.slice(0, bytes));
s.emit('data', data);
var data = (buff + data).split(/\n+/)
, l = data.length - 1
, i = 0;
for (; i < l; i++) {
s.emit('line', data[i]);
}
buff = data[l];
pos += bytes;
return read();
});
})();
});
return s;
};

885
test/terminfo Normal file
View File

@ -0,0 +1,885 @@
{ header:
{ dataSize: 3337,
headerSize: 12,
magicNumber: 282,
namesSize: 28,
boolCount: 38,
numCount: 15,
strCount: 413,
strTableSize: 1388,
total: 2322,
extended:
{ dataSize: 1015,
headerSize: 10,
boolCount: 2,
numCount: 0,
strCount: 62,
strTableSize: 126,
lastStrTableOffset: 751,
total: 262 } },
name: 'xterm',
names: [ 'xterm' ],
desc: 'X11 terminal emulator',
bools:
{ auto_left_margin: false,
auto_right_margin: true,
no_esc_ctlc: false,
ceol_standout_glitch: false,
eat_newline_glitch: true,
erase_overstrike: false,
generic_type: false,
hard_copy: false,
has_meta_key: true,
has_status_line: false,
insert_null_glitch: false,
memory_above: false,
memory_below: false,
move_insert_mode: true,
move_standout_mode: true,
over_strike: false,
status_line_esc_ok: false,
dest_tabs_magic_smso: false,
tilde_glitch: false,
transparent_underline: false,
xon_xoff: false,
needs_xon_xoff: false,
prtr_silent: true,
hard_cursor: false,
non_rev_rmcup: false,
no_pad_char: true,
non_dest_scroll_region: false,
can_change: false,
back_color_erase: true,
hue_lightness_saturation: false,
col_addr_glitch: false,
cr_cancels_micro_mode: false,
has_print_wheel: false,
row_addr_glitch: false,
semi_auto_right_margin: false,
cpi_changes_res: false,
lpi_changes_res: false,
backspaces_with_bs: true,
AX: true,
XT: true },
numbers:
{ columns: 80,
init_tabs: 8,
lines: 24,
lines_of_memory: -1,
magic_cookie_glitch: -1,
padding_baud_rate: -1,
virtual_terminal: -1,
width_status_line: -1,
num_labels: -1,
label_height: -1,
label_width: -1,
max_attributes: -1,
maximum_windows: -1,
max_colors: 8,
max_pairs: 64 },
strings:
{ back_tab: '\u001b[Z',
bell: '\u0007',
carriage_return: '\r',
change_scroll_region: '\u001b[%i%p1%d;%p2%dr',
clear_all_tabs: '\u001b[3g',
clear_screen: '\u001b[H\u001b[2J',
clr_eol: '\u001b[K',
clr_eos: '\u001b[J',
column_address: '\u001b[%i%p1%dG',
cursor_address: '\u001b[%i%p1%d;%p2%dH',
cursor_down: '\n',
cursor_home: '\u001b[H',
cursor_invisible: '\u001b[?25l',
cursor_left: '\b',
cursor_normal: '\u001b[?12l\u001b[?25h',
cursor_right: '\u001b[C',
cursor_up: '\u001b[A',
cursor_visible: '\u001b[?12;25h',
delete_character: '\u001b[P',
delete_line: '\u001b[M',
enter_alt_charset_mode: '\u001b(0',
enter_blink_mode: '\u001b[5m',
enter_bold_mode: '\u001b[1m',
enter_ca_mode: '\u001b[?1049h',
enter_insert_mode: '\u001b[4h',
enter_secure_mode: '\u001b[8m',
enter_reverse_mode: '\u001b[7m',
enter_standout_mode: '\u001b[7m',
enter_underline_mode: '\u001b[4m',
erase_chars: '\u001b[%p1%dX',
exit_alt_charset_mode: '\u001b(B',
exit_attribute_mode: '\u001b(B\u001b[m',
exit_ca_mode: '\u001b[?1049l',
exit_insert_mode: '\u001b[4l',
exit_standout_mode: '\u001b[27m',
exit_underline_mode: '\u001b[24m',
flash_screen: '\u001b[?5h$<100/>\u001b[?5l',
init_2string: '\u001b[!p\u001b[?3;4l\u001b[4l\u001b>',
insert_line: '\u001b[L',
key_backspace: '\b',
key_dc: '\u001b[3~',
key_down: '\u001bOB',
key_f1: '\u001bOP',
key_f10: '\u001b[21~',
key_f2: '\u001bOQ',
key_f3: '\u001bOR',
key_f4: '\u001bOS',
key_f5: '\u001b[15~',
key_f6: '\u001b[17~',
key_f7: '\u001b[18~',
key_f8: '\u001b[19~',
key_f9: '\u001b[20~',
key_home: '\u001bOH',
key_ic: '\u001b[2~',
key_left: '\u001bOD',
key_npage: '\u001b[6~',
key_ppage: '\u001b[5~',
key_right: '\u001bOC',
key_sf: '\u001b[1;2B',
key_sr: '\u001b[1;2A',
key_up: '\u001bOA',
keypad_local: '\u001b[?1l\u001b>',
keypad_xmit: '\u001b[?1h\u001b=',
meta_off: '\u001b[?1034l',
meta_on: '\u001b[?1034h',
parm_dch: '\u001b[%p1%dP',
parm_delete_line: '\u001b[%p1%dM',
parm_down_cursor: '\u001b[%p1%dB',
parm_ich: '\u001b[%p1%d@',
parm_index: '\u001b[%p1%dS',
parm_insert_line: '\u001b[%p1%dL',
parm_left_cursor: '\u001b[%p1%dD',
parm_right_cursor: '\u001b[%p1%dC',
parm_rindex: '\u001b[%p1%dT',
parm_up_cursor: '\u001b[%p1%dA',
print_screen: '\u001b[i',
prtr_off: '\u001b[4i',
prtr_on: '\u001b[5i',
reset_1string: '\u001bc',
reset_2string: '\u001b[!p\u001b[?3;4l\u001b[4l\u001b>',
restore_cursor: '\u001b8',
row_address: '\u001b[%i%p1%dd',
save_cursor: '\u001b7',
scroll_forward: '\n',
scroll_reverse: '\u001bM',
set_attributes: '%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m',
set_tab: '\u001bH',
tab: '\t',
key_b2: '\u001bOE',
acs_chars: '``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~',
key_btab: '\u001b[Z',
enter_am_mode: '\u001b[?7h',
exit_am_mode: '\u001b[?7l',
key_end: '\u001bOF',
key_enter: '\u001bOM',
key_sdc: '\u001b[3;2~',
key_send: '\u001b[1;2F',
key_shome: '\u001b[1;2H',
key_sic: '\u001b[2;2~',
key_sleft: '\u001b[1;2D',
key_snext: '\u001b[6;2~',
key_sprevious: '\u001b[5;2~',
key_sright: '\u001b[1;2C',
key_f11: '\u001b[23~',
key_f12: '\u001b[24~',
key_f13: '\u001b[1;2P',
key_f14: '\u001b[1;2Q',
key_f15: '\u001b[1;2R',
key_f16: '\u001b[1;2S',
key_f17: '\u001b[15;2~',
key_f18: '\u001b[17;2~',
key_f19: '\u001b[18;2~',
key_f20: '\u001b[19;2~',
key_f21: '\u001b[20;2~',
key_f22: '\u001b[21;2~',
key_f23: '\u001b[23;2~',
key_f24: '\u001b[24;2~',
key_f25: '\u001b[1;5P',
key_f26: '\u001b[1;5Q',
key_f27: '\u001b[1;5R',
key_f28: '\u001b[1;5S',
key_f29: '\u001b[15;5~',
key_f30: '\u001b[17;5~',
key_f31: '\u001b[18;5~',
key_f32: '\u001b[19;5~',
key_f33: '\u001b[20;5~',
key_f34: '\u001b[21;5~',
key_f35: '\u001b[23;5~',
key_f36: '\u001b[24;5~',
key_f37: '\u001b[1;6P',
key_f38: '\u001b[1;6Q',
key_f39: '\u001b[1;6R',
key_f40: '\u001b[1;6S',
key_f41: '\u001b[15;6~',
key_f42: '\u001b[17;6~',
key_f43: '\u001b[18;6~',
key_f44: '\u001b[19;6~',
key_f45: '\u001b[20;6~',
key_f46: '\u001b[21;6~',
key_f47: '\u001b[23;6~',
key_f48: '\u001b[24;6~',
key_f49: '\u001b[1;3P',
key_f50: '\u001b[1;3Q',
key_f51: '\u001b[1;3R',
key_f52: '\u001b[1;3S',
key_f53: '\u001b[15;3~',
key_f54: '\u001b[17;3~',
key_f55: '\u001b[18;3~',
key_f56: '\u001b[19;3~',
key_f57: '\u001b[20;3~',
key_f58: '\u001b[21;3~',
key_f59: '\u001b[23;3~',
key_f60: '\u001b[24;3~',
key_f61: '\u001b[1;4P',
key_f62: '\u001b[1;4Q',
key_f63: '\u001b[1;4R',
clr_bol: '\u001b[1K',
user6: '\u001b[%i%d;%dR',
user7: '\u001b[6n',
user8: '\u001b[?1;2c',
user9: '\u001b[c',
orig_pair: '\u001b[39;49m',
set_foreground: '\u001b[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m',
set_background: '\u001b[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m',
key_mouse: '\u001b[M',
set_a_foreground: '\u001b[3%p1%dm',
set_a_background: '\u001b[4%p1%dm',
memory_lock: '\u001bl',
memory_unlock: '\u001bm',
Cr: '\u001b]112\u0007',
Cs: '\u001b]12;%p1%s\u0007',
E3: '\u001b[3;J',
Ms: '\u001b]52;%p1%s;%p2%s\u0007',
Se: '\u001b[2 q',
Ss: '\u001b[%p1%d q',
kDC3: '\u001b[3;3~',
kDC4: '\u001b[3;4~',
kDC5: '\u001b[3;5~',
kDC6: '\u001b[3;6~',
kDC7: '\u001b[3;7~',
kDN: '\u001b[1;2B',
kDN3: '\u001b[1;3B',
kDN4: '\u001b[1;4B',
kDN5: '\u001b[1;5B',
kDN6: '\u001b[1;6B',
kDN7: '\u001b[1;7B',
kEND3: '\u001b[1;3F',
kEND4: '\u001b[1;4F',
kEND5: '\u001b[1;5F',
kEND6: '\u001b[1;6F',
kEND7: '\u001b[1;7F',
kHOM3: '\u001b[1;3H',
kHOM4: '\u001b[1;4H',
kHOM5: '\u001b[1;5H',
kHOM6: '\u001b[1;6H',
kHOM7: '\u001b[1;7H',
kIC3: '\u001b[2;3~',
kIC4: '\u001b[2;4~',
kIC5: '\u001b[2;5~',
kIC6: '\u001b[2;6~',
kIC7: '\u001b[2;7~',
kLFT3: '\u001b[1;3D',
kLFT4: '\u001b[1;4D',
kLFT5: '\u001b[1;5D',
kLFT6: '\u001b[1;6D',
kLFT7: '\u001b[1;7D',
kNXT3: '\u001b[6;3~',
kNXT4: '\u001b[6;4~',
kNXT5: '\u001b[6;5~',
kNXT6: '\u001b[6;6~',
kNXT7: '\u001b[6;7~',
kPRV3: '\u001b[5;3~',
kPRV4: '\u001b[5;4~',
kPRV5: '\u001b[5;5~',
kPRV6: '\u001b[5;6~',
kPRV7: '\u001b[5;7~',
kRIT3: '\u001b[1;3C',
kRIT4: '\u001b[1;4C',
kRIT5: '\u001b[1;5C',
kRIT6: '\u001b[1;6C',
kRIT7: '\u001b[1;7C',
kUP: '\u001b[1;2A',
kUP3: '\u001b[1;3A',
kUP4: '\u001b[1;4A',
kUP5: '\u001b[1;5A',
kUP6: '\u001b[1;6A',
kUP7: '\u001b[1;7A',
ka2: '',
kb1: '',
kb3: '',
kc2: '' },
features:
{ unicode: true,
brokenACS: false,
PCRomSet: false,
magicCookie: true,
padding: true,
setbuf: true,
acsc:
{ '`': '',
a: '',
f: '°',
g: '±',
i: '\u000b',
j: '',
k: '',
l: '',
m: '',
n: '',
o: '',
p: '',
q: '',
r: '',
s: '',
t: '',
u: '',
v: '',
w: '',
x: '',
y: '',
z: '',
'{': 'π',
'|': '',
'}': '£',
'~': '·' },
acscr:
{ '': '`',
'': 'a',
'°': 'f',
'±': 'g',
'\u000b': 'i',
'': 'j',
'': 'k',
'': 'l',
'': 'm',
'': 'n',
'': 'o',
'': 'p',
'': 'q',
'': 'r',
'': 's',
'': 't',
'': 'u',
'': 'v',
'': 'w',
'': 'x',
'': 'y',
'': 'z',
'π': '{',
'': '|',
'£': '}',
'·': '~' } } }
Compiling auto_left_margin: false
Compiling auto_right_margin: true
Compiling no_esc_ctlc: false
Compiling ceol_standout_glitch: false
Compiling eat_newline_glitch: true
Compiling erase_overstrike: false
Compiling generic_type: false
Compiling hard_copy: false
Compiling has_meta_key: true
Compiling has_status_line: false
Compiling insert_null_glitch: false
Compiling memory_above: false
Compiling memory_below: false
Compiling move_insert_mode: true
Compiling move_standout_mode: true
Compiling over_strike: false
Compiling status_line_esc_ok: false
Compiling dest_tabs_magic_smso: false
Compiling tilde_glitch: false
Compiling transparent_underline: false
Compiling xon_xoff: false
Compiling needs_xon_xoff: false
Compiling prtr_silent: true
Compiling hard_cursor: false
Compiling non_rev_rmcup: false
Compiling no_pad_char: true
Compiling non_dest_scroll_region: false
Compiling can_change: false
Compiling back_color_erase: true
Compiling hue_lightness_saturation: false
Compiling col_addr_glitch: false
Compiling cr_cancels_micro_mode: false
Compiling has_print_wheel: false
Compiling row_addr_glitch: false
Compiling semi_auto_right_margin: false
Compiling cpi_changes_res: false
Compiling lpi_changes_res: false
Compiling backspaces_with_bs: true
Compiling AX: true
Compiling XT: true
Compiling columns: 80
Compiling init_tabs: 8
Compiling lines: 24
Compiling lines_of_memory: -1
Compiling magic_cookie_glitch: -1
Compiling padding_baud_rate: -1
Compiling virtual_terminal: -1
Compiling width_status_line: -1
Compiling num_labels: -1
Compiling label_height: -1
Compiling label_width: -1
Compiling max_attributes: -1
Compiling maximum_windows: -1
Compiling max_colors: 8
Compiling max_pairs: 64
Compiling back_tab: "\u001b[Z"
return "\x1b[Z";
Compiling bell: "\u0007"
return "\x07";
Compiling carriage_return: "\r"
return "\r";
Compiling change_scroll_region: "\u001b[%i%p1%d;%p2%dr"
var out = ["\x1b["];(params[0]++, params[1]++),out.push(params[0]),out.push(";"),out.push(params[1]),out.push("r");return out.join("");
Compiling clear_all_tabs: "\u001b[3g"
return "\x1b[3g";
Compiling clear_screen: "\u001b[H\u001b[2J"
return "\x1b[H\x1b[2J";
Compiling clr_eol: "\u001b[K"
return "\x1b[K";
Compiling clr_eos: "\u001b[J"
return "\x1b[J";
Compiling column_address: "\u001b[%i%p1%dG"
var out = ["\x1b["];(params[0]++, params[1]++),out.push(params[0]),out.push("G");return out.join("");
Compiling cursor_address: "\u001b[%i%p1%d;%p2%dH"
var out = ["\x1b["];(params[0]++, params[1]++),out.push(params[0]),out.push(";"),out.push(params[1]),out.push("H");return out.join("");
Compiling cursor_down: "\n"
return "\n";
Compiling cursor_home: "\u001b[H"
return "\x1b[H";
Compiling cursor_invisible: "\u001b[?25l"
return "\x1b[?25l";
Compiling cursor_left: "\b"
return "\b";
Compiling cursor_normal: "\u001b[?12l\u001b[?25h"
return "\x1b[?12l\x1b[?25h";
Compiling cursor_right: "\u001b[C"
return "\x1b[C";
Compiling cursor_up: "\u001b[A"
return "\x1b[A";
Compiling cursor_visible: "\u001b[?12;25h"
return "\x1b[?12;25h";
Compiling delete_character: "\u001b[P"
return "\x1b[P";
Compiling delete_line: "\u001b[M"
return "\x1b[M";
Compiling enter_alt_charset_mode: "\u001b(0"
return "\x1b(0";
Compiling enter_blink_mode: "\u001b[5m"
return "\x1b[5m";
Compiling enter_bold_mode: "\u001b[1m"
return "\x1b[1m";
Compiling enter_ca_mode: "\u001b[?1049h"
return "\x1b[?1049h";
Compiling enter_insert_mode: "\u001b[4h"
return "\x1b[4h";
Compiling enter_secure_mode: "\u001b[8m"
return "\x1b[8m";
Compiling enter_reverse_mode: "\u001b[7m"
return "\x1b[7m";
Compiling enter_standout_mode: "\u001b[7m"
return "\x1b[7m";
Compiling enter_underline_mode: "\u001b[4m"
return "\x1b[4m";
Compiling erase_chars: "\u001b[%p1%dX"
var out = ["\x1b["];out.push(params[0]),out.push("X");return out.join("");
Compiling exit_alt_charset_mode: "\u001b(B"
return "\x1b(B";
Compiling exit_attribute_mode: "\u001b(B\u001b[m"
return "\x1b(B\x1b[m";
Compiling exit_ca_mode: "\u001b[?1049l"
return "\x1b[?1049l";
Compiling exit_insert_mode: "\u001b[4l"
return "\x1b[4l";
Compiling exit_standout_mode: "\u001b[27m"
return "\x1b[27m";
Compiling exit_underline_mode: "\u001b[24m"
return "\x1b[24m";
Compiling flash_screen: "\u001b[?5h$<100/>\u001b[?5l"
return "\x1b[?5h\x1b[?5l";
Compiling init_2string: "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"
return "\x1b[!p\x1b[?3;4l\x1b[4l\x1b>";
Compiling insert_line: "\u001b[L"
return "\x1b[L";
Compiling key_backspace: "\b"
return "\b";
Compiling key_dc: "\u001b[3~"
return "\x1b[3~";
Compiling key_down: "\u001bOB"
return "\x1bOB";
Compiling key_f1: "\u001bOP"
return "\x1bOP";
Compiling key_f10: "\u001b[21~"
return "\x1b[21~";
Compiling key_f2: "\u001bOQ"
return "\x1bOQ";
Compiling key_f3: "\u001bOR"
return "\x1bOR";
Compiling key_f4: "\u001bOS"
return "\x1bOS";
Compiling key_f5: "\u001b[15~"
return "\x1b[15~";
Compiling key_f6: "\u001b[17~"
return "\x1b[17~";
Compiling key_f7: "\u001b[18~"
return "\x1b[18~";
Compiling key_f8: "\u001b[19~"
return "\x1b[19~";
Compiling key_f9: "\u001b[20~"
return "\x1b[20~";
Compiling key_home: "\u001bOH"
return "\x1bOH";
Compiling key_ic: "\u001b[2~"
return "\x1b[2~";
Compiling key_left: "\u001bOD"
return "\x1bOD";
Compiling key_npage: "\u001b[6~"
return "\x1b[6~";
Compiling key_ppage: "\u001b[5~"
return "\x1b[5~";
Compiling key_right: "\u001bOC"
return "\x1bOC";
Compiling key_sf: "\u001b[1;2B"
return "\x1b[1;2B";
Compiling key_sr: "\u001b[1;2A"
return "\x1b[1;2A";
Compiling key_up: "\u001bOA"
return "\x1bOA";
Compiling keypad_local: "\u001b[?1l\u001b>"
return "\x1b[?1l\x1b>";
Compiling keypad_xmit: "\u001b[?1h\u001b="
return "\x1b[?1h\x1b=";
Compiling meta_off: "\u001b[?1034l"
return "\x1b[?1034l";
Compiling meta_on: "\u001b[?1034h"
return "\x1b[?1034h";
Compiling parm_dch: "\u001b[%p1%dP"
var out = ["\x1b["];out.push(params[0]),out.push("P");return out.join("");
Compiling parm_delete_line: "\u001b[%p1%dM"
var out = ["\x1b["];out.push(params[0]),out.push("M");return out.join("");
Compiling parm_down_cursor: "\u001b[%p1%dB"
var out = ["\x1b["];out.push(params[0]),out.push("B");return out.join("");
Compiling parm_ich: "\u001b[%p1%d@"
var out = ["\x1b["];out.push(params[0]),out.push("@");return out.join("");
Compiling parm_index: "\u001b[%p1%dS"
var out = ["\x1b["];out.push(params[0]),out.push("S");return out.join("");
Compiling parm_insert_line: "\u001b[%p1%dL"
var out = ["\x1b["];out.push(params[0]),out.push("L");return out.join("");
Compiling parm_left_cursor: "\u001b[%p1%dD"
var out = ["\x1b["];out.push(params[0]),out.push("D");return out.join("");
Compiling parm_right_cursor: "\u001b[%p1%dC"
var out = ["\x1b["];out.push(params[0]),out.push("C");return out.join("");
Compiling parm_rindex: "\u001b[%p1%dT"
var out = ["\x1b["];out.push(params[0]),out.push("T");return out.join("");
Compiling parm_up_cursor: "\u001b[%p1%dA"
var out = ["\x1b["];out.push(params[0]),out.push("A");return out.join("");
Compiling print_screen: "\u001b[i"
return "\x1b[i";
Compiling prtr_off: "\u001b[4i"
return "\x1b[4i";
Compiling prtr_on: "\u001b[5i"
return "\x1b[5i";
Compiling reset_1string: "\u001bc"
return "\x1bc";
Compiling reset_2string: "\u001b[!p\u001b[?3;4l\u001b[4l\u001b>"
return "\x1b[!p\x1b[?3;4l\x1b[4l\x1b>";
Compiling restore_cursor: "\u001b8"
return "\x1b8";
Compiling row_address: "\u001b[%i%p1%dd"
var out = ["\x1b["];(params[0]++, params[1]++),out.push(params[0]),out.push("d");return out.join("");
Compiling save_cursor: "\u001b7"
return "\x1b7";
Compiling scroll_forward: "\n"
return "\n";
Compiling scroll_reverse: "\u001bM"
return "\x1bM";
Compiling set_attributes: "%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m"
var v, stack = [], out = [];;if ((stack.push(v = params[8]), v)) {out.push("\x1b(0")} else {out.push("\x1b(B")}out.push("\x1b[0");if ((stack.push(v = params[5]), v)) {out.push(";1")};if ((stack.push(v = params[1]), v)) {out.push(";4")};if ((stack.push(v = params[0]), v),(stack.push(v = params[2]), v),(stack.push(v = (stack.pop() | stack.pop()) || 0), v)) {out.push(";7")};if ((stack.push(v = params[3]), v)) {out.push(";5")};if ((stack.push(v = params[6]), v)) {out.push(";8")}out.push("m");return out.join("");
Compiling set_tab: "\u001bH"
return "\x1bH";
Compiling tab: "\t"
return "\t";
Compiling key_b2: "\u001bOE"
return "\x1bOE";
Compiling acs_chars: "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"
return "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~";
Compiling key_btab: "\u001b[Z"
return "\x1b[Z";
Compiling enter_am_mode: "\u001b[?7h"
return "\x1b[?7h";
Compiling exit_am_mode: "\u001b[?7l"
return "\x1b[?7l";
Compiling key_end: "\u001bOF"
return "\x1bOF";
Compiling key_enter: "\u001bOM"
return "\x1bOM";
Compiling key_sdc: "\u001b[3;2~"
return "\x1b[3;2~";
Compiling key_send: "\u001b[1;2F"
return "\x1b[1;2F";
Compiling key_shome: "\u001b[1;2H"
return "\x1b[1;2H";
Compiling key_sic: "\u001b[2;2~"
return "\x1b[2;2~";
Compiling key_sleft: "\u001b[1;2D"
return "\x1b[1;2D";
Compiling key_snext: "\u001b[6;2~"
return "\x1b[6;2~";
Compiling key_sprevious: "\u001b[5;2~"
return "\x1b[5;2~";
Compiling key_sright: "\u001b[1;2C"
return "\x1b[1;2C";
Compiling key_f11: "\u001b[23~"
return "\x1b[23~";
Compiling key_f12: "\u001b[24~"
return "\x1b[24~";
Compiling key_f13: "\u001b[1;2P"
return "\x1b[1;2P";
Compiling key_f14: "\u001b[1;2Q"
return "\x1b[1;2Q";
Compiling key_f15: "\u001b[1;2R"
return "\x1b[1;2R";
Compiling key_f16: "\u001b[1;2S"
return "\x1b[1;2S";
Compiling key_f17: "\u001b[15;2~"
return "\x1b[15;2~";
Compiling key_f18: "\u001b[17;2~"
return "\x1b[17;2~";
Compiling key_f19: "\u001b[18;2~"
return "\x1b[18;2~";
Compiling key_f20: "\u001b[19;2~"
return "\x1b[19;2~";
Compiling key_f21: "\u001b[20;2~"
return "\x1b[20;2~";
Compiling key_f22: "\u001b[21;2~"
return "\x1b[21;2~";
Compiling key_f23: "\u001b[23;2~"
return "\x1b[23;2~";
Compiling key_f24: "\u001b[24;2~"
return "\x1b[24;2~";
Compiling key_f25: "\u001b[1;5P"
return "\x1b[1;5P";
Compiling key_f26: "\u001b[1;5Q"
return "\x1b[1;5Q";
Compiling key_f27: "\u001b[1;5R"
return "\x1b[1;5R";
Compiling key_f28: "\u001b[1;5S"
return "\x1b[1;5S";
Compiling key_f29: "\u001b[15;5~"
return "\x1b[15;5~";
Compiling key_f30: "\u001b[17;5~"
return "\x1b[17;5~";
Compiling key_f31: "\u001b[18;5~"
return "\x1b[18;5~";
Compiling key_f32: "\u001b[19;5~"
return "\x1b[19;5~";
Compiling key_f33: "\u001b[20;5~"
return "\x1b[20;5~";
Compiling key_f34: "\u001b[21;5~"
return "\x1b[21;5~";
Compiling key_f35: "\u001b[23;5~"
return "\x1b[23;5~";
Compiling key_f36: "\u001b[24;5~"
return "\x1b[24;5~";
Compiling key_f37: "\u001b[1;6P"
return "\x1b[1;6P";
Compiling key_f38: "\u001b[1;6Q"
return "\x1b[1;6Q";
Compiling key_f39: "\u001b[1;6R"
return "\x1b[1;6R";
Compiling key_f40: "\u001b[1;6S"
return "\x1b[1;6S";
Compiling key_f41: "\u001b[15;6~"
return "\x1b[15;6~";
Compiling key_f42: "\u001b[17;6~"
return "\x1b[17;6~";
Compiling key_f43: "\u001b[18;6~"
return "\x1b[18;6~";
Compiling key_f44: "\u001b[19;6~"
return "\x1b[19;6~";
Compiling key_f45: "\u001b[20;6~"
return "\x1b[20;6~";
Compiling key_f46: "\u001b[21;6~"
return "\x1b[21;6~";
Compiling key_f47: "\u001b[23;6~"
return "\x1b[23;6~";
Compiling key_f48: "\u001b[24;6~"
return "\x1b[24;6~";
Compiling key_f49: "\u001b[1;3P"
return "\x1b[1;3P";
Compiling key_f50: "\u001b[1;3Q"
return "\x1b[1;3Q";
Compiling key_f51: "\u001b[1;3R"
return "\x1b[1;3R";
Compiling key_f52: "\u001b[1;3S"
return "\x1b[1;3S";
Compiling key_f53: "\u001b[15;3~"
return "\x1b[15;3~";
Compiling key_f54: "\u001b[17;3~"
return "\x1b[17;3~";
Compiling key_f55: "\u001b[18;3~"
return "\x1b[18;3~";
Compiling key_f56: "\u001b[19;3~"
return "\x1b[19;3~";
Compiling key_f57: "\u001b[20;3~"
return "\x1b[20;3~";
Compiling key_f58: "\u001b[21;3~"
return "\x1b[21;3~";
Compiling key_f59: "\u001b[23;3~"
return "\x1b[23;3~";
Compiling key_f60: "\u001b[24;3~"
return "\x1b[24;3~";
Compiling key_f61: "\u001b[1;4P"
return "\x1b[1;4P";
Compiling key_f62: "\u001b[1;4Q"
return "\x1b[1;4Q";
Compiling key_f63: "\u001b[1;4R"
return "\x1b[1;4R";
Compiling clr_bol: "\u001b[1K"
return "\x1b[1K";
Compiling user6: "\u001b[%i%d;%dR"
var stack = [], out = ["\x1b["];(params[0]++, params[1]++),out.push(stack.pop()),out.push(";"),out.push(stack.pop()),out.push("R");return out.join("");
Compiling user7: "\u001b[6n"
return "\x1b[6n";
Compiling user8: "\u001b[?1;2c"
return "\x1b[?1;2c";
Compiling user9: "\u001b[c"
return "\x1b[c";
Compiling orig_pair: "\u001b[39;49m"
return "\x1b[39;49m";
Compiling set_foreground: "\u001b[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"
var v, stack = [], out = [];out.push("\x1b[3");if ((stack.push(v = params[0]), v),(stack.push(v = 1), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("4")} else if ((stack.push(v = params[0]), v),(stack.push(v = 3), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("6")} else if ((stack.push(v = params[0]), v),(stack.push(v = 4), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("1")} else if ((stack.push(v = params[0]), v),(stack.push(v = 6), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("3")} else {out.push(params[0])}out.push("m");return out.join("");
Compiling set_background: "\u001b[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"
var v, stack = [], out = [];out.push("\x1b[4");if ((stack.push(v = params[0]), v),(stack.push(v = 1), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("4")} else if ((stack.push(v = params[0]), v),(stack.push(v = 3), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("6")} else if ((stack.push(v = params[0]), v),(stack.push(v = 4), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("1")} else if ((stack.push(v = params[0]), v),(stack.push(v = 6), v),(stack.push(v = (stack.pop() === stack.pop()) || 0), v)) {out.push("3")} else {out.push(params[0])}out.push("m");return out.join("");
Compiling key_mouse: "\u001b[M"
return "\x1b[M";
Compiling set_a_foreground: "\u001b[3%p1%dm"
var out = ["\x1b[3"];out.push(params[0]),out.push("m");return out.join("");
Compiling set_a_background: "\u001b[4%p1%dm"
var out = ["\x1b[4"];out.push(params[0]),out.push("m");return out.join("");
Compiling memory_lock: "\u001bl"
return "\x1bl";
Compiling memory_unlock: "\u001bm"
return "\x1bm";
Compiling Cr: "\u001b]112\u0007"
return "\x1b]112\x07";
Compiling Cs: "\u001b]12;%p1%s\u0007"
var out = ["\x1b]12;"];out.push(params[0]),out.push("\x07");return out.join("");
Compiling E3: "\u001b[3;J"
return "\x1b[3;J";
Compiling Ms: "\u001b]52;%p1%s;%p2%s\u0007"
var out = ["\x1b]52;"];out.push(params[0]),out.push(";"),out.push(params[1]),out.push("\x07");return out.join("");
Compiling Se: "\u001b[2 q"
return "\x1b[2 q";
Compiling Ss: "\u001b[%p1%d q"
var out = ["\x1b["];out.push(params[0]),out.push(" q");return out.join("");
Compiling kDC3: "\u001b[3;3~"
return "\x1b[3;3~";
Compiling kDC4: "\u001b[3;4~"
return "\x1b[3;4~";
Compiling kDC5: "\u001b[3;5~"
return "\x1b[3;5~";
Compiling kDC6: "\u001b[3;6~"
return "\x1b[3;6~";
Compiling kDC7: "\u001b[3;7~"
return "\x1b[3;7~";
Compiling kDN: "\u001b[1;2B"
return "\x1b[1;2B";
Compiling kDN3: "\u001b[1;3B"
return "\x1b[1;3B";
Compiling kDN4: "\u001b[1;4B"
return "\x1b[1;4B";
Compiling kDN5: "\u001b[1;5B"
return "\x1b[1;5B";
Compiling kDN6: "\u001b[1;6B"
return "\x1b[1;6B";
Compiling kDN7: "\u001b[1;7B"
return "\x1b[1;7B";
Compiling kEND3: "\u001b[1;3F"
return "\x1b[1;3F";
Compiling kEND4: "\u001b[1;4F"
return "\x1b[1;4F";
Compiling kEND5: "\u001b[1;5F"
return "\x1b[1;5F";
Compiling kEND6: "\u001b[1;6F"
return "\x1b[1;6F";
Compiling kEND7: "\u001b[1;7F"
return "\x1b[1;7F";
Compiling kHOM3: "\u001b[1;3H"
return "\x1b[1;3H";
Compiling kHOM4: "\u001b[1;4H"
return "\x1b[1;4H";
Compiling kHOM5: "\u001b[1;5H"
return "\x1b[1;5H";
Compiling kHOM6: "\u001b[1;6H"
return "\x1b[1;6H";
Compiling kHOM7: "\u001b[1;7H"
return "\x1b[1;7H";
Compiling kIC3: "\u001b[2;3~"
return "\x1b[2;3~";
Compiling kIC4: "\u001b[2;4~"
return "\x1b[2;4~";
Compiling kIC5: "\u001b[2;5~"
return "\x1b[2;5~";
Compiling kIC6: "\u001b[2;6~"
return "\x1b[2;6~";
Compiling kIC7: "\u001b[2;7~"
return "\x1b[2;7~";
Compiling kLFT3: "\u001b[1;3D"
return "\x1b[1;3D";
Compiling kLFT4: "\u001b[1;4D"
return "\x1b[1;4D";
Compiling kLFT5: "\u001b[1;5D"
return "\x1b[1;5D";
Compiling kLFT6: "\u001b[1;6D"
return "\x1b[1;6D";
Compiling kLFT7: "\u001b[1;7D"
return "\x1b[1;7D";
Compiling kNXT3: "\u001b[6;3~"
return "\x1b[6;3~";
Compiling kNXT4: "\u001b[6;4~"
return "\x1b[6;4~";
Compiling kNXT5: "\u001b[6;5~"
return "\x1b[6;5~";
Compiling kNXT6: "\u001b[6;6~"
return "\x1b[6;6~";
Compiling kNXT7: "\u001b[6;7~"
return "\x1b[6;7~";
Compiling kPRV3: "\u001b[5;3~"
return "\x1b[5;3~";
Compiling kPRV4: "\u001b[5;4~"
return "\x1b[5;4~";
Compiling kPRV5: "\u001b[5;5~"
return "\x1b[5;5~";
Compiling kPRV6: "\u001b[5;6~"
return "\x1b[5;6~";
Compiling kPRV7: "\u001b[5;7~"
return "\x1b[5;7~";
Compiling kRIT3: "\u001b[1;3C"
return "\x1b[1;3C";
Compiling kRIT4: "\u001b[1;4C"
return "\x1b[1;4C";
Compiling kRIT5: "\u001b[1;5C"
return "\x1b[1;5C";
Compiling kRIT6: "\u001b[1;6C"
return "\x1b[1;6C";
Compiling kRIT7: "\u001b[1;7C"
return "\x1b[1;7C";
Compiling kUP: "\u001b[1;2A"
return "\x1b[1;2A";
Compiling kUP3: "\u001b[1;3A"
return "\x1b[1;3A";
Compiling kUP4: "\u001b[1;4A"
return "\x1b[1;4A";
Compiling kUP5: "\u001b[1;5A"
return "\x1b[1;5A";
Compiling kUP6: "\u001b[1;6A"
return "\x1b[1;6A";
Compiling kUP7: "\u001b[1;7A"
return "\x1b[1;7A";
Compiling ka2: ""
Compiling kb1: ""
Compiling kb3: ""
Compiling kc2: ""

BIN
test/test-image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

20
test/tput Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
term="$1"
dir=$(dirname $(readlink -f "$0"))
cd "$dir/.."
if test -z "$term"; then
term="$dir/../usr/xterm"
set -- "$term" "$@"
fi
node test/tput.js "$@" | grep -v 'dir:\|file:' | tee test/logs/terminfo.log
out=$(git diff --color=always --no-index test/terminfo test/logs/terminfo.log)
if test -n "$out"; then
echo "$out" | less -c -R
else
echo 'Files are identical.'
fi

152
test/tput.js Normal file
View File

@ -0,0 +1,152 @@
/**
* Tput for node.js
* Copyright (c) 2013, Christopher Jeffrey (MIT License)
* https://github.com/chjj/blessed
*/
// Compile xterm terminfo/termcap:
// $ tic -a -I -1 usr/xterm.terminfo
// $ tic -a -C -U usr/xterm.termcap
// Compile xterm terminfo/termcap:
// $ tic -a -1 usr/xterm.terminfo
// $ tic -a -1 usr/xterm.terminfo && ls ~/.terminfo
// $ tic -a -1 -o usr usr/xterm.terminfo && mv usr/x/xterm usr/ && rm -rf usr/v usr/x
// $ tic -a -1 -o usr usr/xterm.terminfo && mv usr/x/xterm-256color usr/ && rm -rf usr/v usr/x
// Check tput output:
// $ node test/tput.js xterm | tee out
// $ node test/tput.js xterm --ifile usr/xterm | tee out
// $ node test/tput.js xterm-256color --ifile usr/xterm-256color | tee out
// $ node test/tput.js vt102 --termcap | tee out
// $ node test/tput.js xterm --termcap --cfile usr/xterm.termcap | tee out
// $ node test/tput.js xterm --iprefix ~/.terminfo | tee out
// $ node test/tput.js xterm-256color --ifile ~/.terminfo/x/xterm-256color | tee out
// $ cdiff test/terminfo out
var blessed = require('../');
// Simple argument parser
// Copyright (c) 2012, Christopher Jeffrey (MIT License)
function parseArg() {
var argv = process.argv.slice(2)
, options = [];
function getarg() {
var arg = argv.shift();
if (arg.indexOf('--') === 0) {
// e.g. --opt
arg = arg.split('=');
if (arg.length > 1) {
// e.g. --opt=val
argv.unshift(arg.slice(1).join('='));
}
arg = arg[0];
} else if (arg[0] === '-') {
if (arg.length > 2) {
// e.g. -abc
argv = arg.substring(1).split('').map(function(ch) {
return '-' + ch;
}).concat(argv);
arg = argv.shift();
} else {
// e.g. -a
}
} else {
// e.g. foo
}
return arg;
}
while (argv.length) {
arg = getarg();
if (arg.indexOf('-') === 0) {
arg = arg.replace(/^--?/, '');
if (argv[0] && argv[0].indexOf('-') !== 0) {
options[arg] = argv.shift();
} else {
options[arg] = true;
}
} else {
options.push(arg);
}
}
return options;
}
var argv = parseArg();
var tput = blessed.tput({
terminal: argv[0] !== 'all' && argv[0] !== 'rand'
? argv[0] || __dirname + '/../usr/xterm'
: null,
extended: true,
debug: true,
termcap: argv.termcap,
terminfoFile: argv.i || argv.ifile,
terminfoPrefix: argv.p || argv.iprefix,
termcapFile: argv.c || argv.cfile
});
if (argv[0] === 'all') {
var rl = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
var text = '\x1b[31mWARNING:\x1b[m '
+ 'This will compile every single terminfo file on your disk.\n'
+ 'It will probably use a lot of CPU.\n'
+ 'Do you wish to proceed? (Y/n) ';
rl.question(text, function(result) {
result = result.trim().toLowerCase();
if (result !== 'y') return process.exit(0);
console.log('\x1b[32m(You bet your ass I wish to proceed.)\x1b[m');
blessed.tput.print(
'$<1000/>.$<1000/>.$<1000/>.$<100/>Let\'s go...',
process.stdout.write.bind(process.stdout),
function() {
tput.compileAll(argv[1]);
process.exit(0);
}
);
});
return;
}
if (argv[0] === 'rand') {
var terms = tput.getAll()
, term;
term = terms[(terms.length - 1) * Math.random() | 0];
console.log('Compiling ' + term + '...');
tput.compileTerminfo(term);
console.log('Compiled ' + term + '.');
return;
}
// console.log('Max colors: %d.', tput.colors);
// console.log(tput.strings.acs_chars.split('').map(function(ch) { return ch.charCodeAt(0); }));
// console.log(JSON.stringify(tput.strings.acs_chars));
// process.stdout.write(blessed.tput.sprintf('%-10s\n', 'hello'));
// tput._compile({ name: 'xterm' }, 'set_attributes',
// '%?%p9%t\u001b(0%e\u001b(B%;\u001b[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m');
// console.log(tput.setaf(4) + 'foo' + tput.sgr0());
// console.log(tput.setaf(4) + 'foo' + tput.sgr(0));
// tput.padding = true;
// tput._print('hello$<1000/>world', console.log, function() {
// tput._print('$<1000/>foo$<1000/>bar', console.log, process.exit);
// });

33
test/widget-autopad.js Normal file
View File

@ -0,0 +1,33 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/autopad.log',
smartCSR: true,
autoPadding: true,
warnings: true
});
var box1 = blessed.box({
parent: screen,
top: 'center',
left: 'center',
width: 20,
height: 10,
border: 'line'
});
var box2 = blessed.box({
parent: box1,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line'
});
screen.key('q', function() {
return screen.destroy();
});
screen.render();

33
test/widget-bigtext.js Normal file
View File

@ -0,0 +1,33 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/bigtext.log',
smartCSR: true,
warnings: true
});
var box = blessed.bigtext({
parent: screen,
content: 'Hello',
shrink: true,
width: '80%',
// height: '80%',
height: 'shrink',
// width: 'shrink',
border: 'line',
fch: ' ',
ch: '\u2592',
style: {
fg: 'red',
bg: 'blue',
bold: false
}
});
screen.key('q', function() {
return screen.destroy();
});
screen.render();

90
test/widget-csr.js Normal file
View File

@ -0,0 +1,90 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/csr.log',
smartCSR: true,
warnings: true
});
var lorem = require('fs').readFileSync(__dirname + '/git.diff', 'utf8');
var cleanSides = screen.cleanSides;
function expectClean(value) {
screen.cleanSides = function(el) {
var ret = cleanSides.apply(this, arguments);
if (ret !== value) {
throw new Error('Failed. Expected '
+ value + ' from cleanSides. Got '
+ ret + '.');
}
return ret;
};
}
/*
blessed.box({
parent: screen,
left: 0,
top: 'center',
width: '50%',
height: 2,
style: {
bg: 'green'
},
content: 'This will disallow CSR.'
});
expectClean(false);
*/
var btext = blessed.box({
parent: screen,
left: 'center',
top: 'center',
width: '80%',
height: '80%',
style: {
bg: 'green'
},
border: 'line',
content: 'CSR should still work.'
});
btext._oscroll = btext.scroll;
btext.scroll = function(offset, always) {
expectClean(true);
return btext._oscroll(offset, always);
};
var text = blessed.scrollabletext({
parent: screen,
content: lorem,
border: 'line',
left: 'center',
top: 'center',
draggable: true,
width: '50%',
height: '50%',
mouse: true,
keys: true,
vi: true
});
text._oscroll = text.scroll;
text.scroll = function(offset, always) {
var el = this;
var value = true;
if (el.left < 0) value = true;
if (el.top < 0) value = false;
if (el.left + el.width > screen.width) value = true;
if (el.top + el.height > screen.height) value = false;
expectClean(value);
return text._oscroll(offset, always);
};
text.focus();
screen.key('q', function() {
return screen.destroy();
});
screen.render();

View File

@ -0,0 +1,88 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/dock.log',
smartCSR: true,
dockBorders: true,
warnings: true
});
blessed.box({
parent: screen,
left: -1,
top: -1,
width: '50%+1',
height: '50%+1',
border: 'line',
content: 'Foo'
});
blessed.box({
parent: screen,
left: '50%-1',
top: -1,
width: '50%+3',
height: '50%+1',
content: 'Bar',
border: 'line'
});
blessed.box({
parent: screen,
left: -1,
top: '50%-1',
width: '50%+1',
height: '50%+3',
border: 'line',
content: 'Foo'
});
blessed.listtable({
parent: screen,
left: '50%-1',
top: '50%-1',
width: '50%+3',
height: '50%+3',
border: 'line',
align: 'center',
tags: true,
keys: true,
vi: true,
mouse: true,
style: {
header: {
fg: 'blue',
bold: true
},
cell: {
fg: 'magenta',
selected: {
bg: 'blue'
}
}
},
data: [
[ 'Animals', 'Foods', 'Times', 'Numbers' ],
[ 'Elephant', 'Apple', '1:00am', 'One' ],
[ 'Bird', 'Orange', '2:15pm', 'Two' ],
[ 'T-Rex', 'Taco', '8:45am', 'Three' ],
[ 'Mouse', 'Cheese', '9:05am', 'Four' ]
]
}).focus();
// blessed.box({
// parent: screen,
// left: '50%-1',
// top: '50%-1',
// width: '50%+1',
// height: '50%+1',
// border: 'line',
// content: 'Bar'
// });
screen.key('q', function() {
return screen.destroy();
});
screen.render();

125
test/widget-dock.js Normal file
View File

@ -0,0 +1,125 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/dock.log',
smartCSR: true,
dockBorders: true,
warnings: true
});
var topleft = blessed.box({
parent: screen,
left: 0,
top: 0,
width: '50%',
height: '50%',
border: {
type: 'line',
left: false,
top: false,
right: true,
bottom: false
},
// border: 'line',
content: 'Foo'
});
var topright = blessed.box({
parent: screen,
left: '50%-1',
top: 0,
width: '50%+1',
height: '50%',
border: {
type: 'line',
left: true,
top: false,
right: false,
bottom: false
},
// border: 'line',
content: 'Bar'
});
var bottomleft = blessed.box({
parent: screen,
left: 0,
top: '50%-1',
width: '50%',
height: '50%+1',
border: {
type: 'line',
left: false,
top: true,
right: false,
bottom: false
},
border: 'line',
content: 'Foo'
});
var bottomright = blessed.listtable({
parent: screen,
left: '50%-1',
top: '50%-1',
width: '50%+1',
height: '50%+1',
border: {
type: 'line',
left: true,
top: true,
right: false,
bottom: false
},
// border: 'line',
align: 'center',
tags: true,
keys: true,
vi: true,
mouse: true,
style: {
header: {
fg: 'blue',
bold: true
},
cell: {
fg: 'magenta',
selected: {
bg: 'blue'
}
}
},
data: [
[ 'Animals', 'Foods', 'Times', 'Numbers' ],
[ 'Elephant', 'Apple', '1:00am', 'One' ],
[ 'Bird', 'Orange', '2:15pm', 'Two' ],
[ 'T-Rex', 'Taco', '8:45am', 'Three' ],
[ 'Mouse', 'Cheese', '9:05am', 'Four' ]
]
});
bottomright.focus();
var over = blessed.box({
parent: screen,
left: 'center',
top: 'center',
width: '50%',
height: '50%',
draggable: true,
border: {
type: 'line',
left: false,
top: true,
right: true,
bottom: true
},
content: 'Drag Me'
});
screen.key('q', function() {
return screen.destroy();
});
screen.render();

36
test/widget-exit.js Normal file
View File

@ -0,0 +1,36 @@
var blessed = require('../');
var screen = blessed.screen({
dump: __dirname + '/logs/exit.log',
smartCSR: true,
autoPadding: true,
warnings: true,
ignoreLocked: ['C-q']
});
var box = blessed.prompt({
parent: screen,
left: 'center',
top: 'center',
width: '70%',
height: 'shrink',
border: 'line'
});
screen.render();
box.input('Input: ', '', function(err, data) {
screen.destroy();
if (process.argv[2] === 'resume') {
process.stdin.resume();
} else if (process.argv[2] === 'end') {
process.stdin.setRawMode(false);
process.stdin.end();
}
if (err) throw err;
console.log('Input: ' + data);
});
screen.key('C-q', function(ch, key) {
return screen.destroy();
});

70
test/widget-file.js Normal file
View File

@ -0,0 +1,70 @@
var blessed = require('../');
var screen = blessed.screen({
tput: true,
smartCSR: true,
dump: __dirname + '/logs/file.log',
warnings: true
});
var fm = blessed.filemanager({
parent: screen,
border: 'line',
style: {
selected: {
bg: 'blue'
}
},
height: 'half',
width: 'half',
top: 'center',
left: 'center',
label: ' {blue-fg}%path{/blue-fg} ',
cwd: process.env.HOME,
keys: true,
vi: true,
scrollbar: {
bg: 'white',
ch: ' '
}
});
var box = blessed.box({
parent: screen,
style: {
bg: 'green'
},
border: 'line',
height: 'half',
width: 'half',
top: 'center',
left: 'center',
hidden: true
});
fm.refresh();
screen.render();
screen.key('q', function() {
screen.destroy();
});
screen.key(['s', 'p'], function() {
fm.hide();
screen.render();
setTimeout(function() {
fm.pick(function(err, file) {
box.show();
box.setContent(err ? err + '' : file);
screen.render();
setTimeout(function() {
box.hide();
fm.reset(function() {
fm.show();
screen.render();
});
}, 2000);
});
}, 2000);
});

253
test/widget-form.js Normal file
View File

@ -0,0 +1,253 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/form.log',
warnings: true
});
var form = blessed.form({
parent: screen,
mouse: true,
keys: true,
vi: true,
left: 0,
top: 0,
width: '100%',
//height: 12,
style: {
bg: 'green',
// border: {
// inverse: true
// },
scrollbar: {
inverse: true
}
},
content: 'foobar',
scrollable: true,
// border: {
// type: 'ch',
// ch: ' '
// },
scrollbar: {
ch: ' '
}
//alwaysScroll: true
});
form.on('submit', function(data) {
output.setContent(JSON.stringify(data, null, 2));
screen.render();
});
form.key('d', function() {
form.scroll(1, true);
screen.render();
});
form.key('u', function() {
form.scroll(-1, true);
screen.render();
});
var set = blessed.radioset({
parent: form,
left: 1,
top: 1,
shrink: true,
//padding: 1,
//content: 'f',
style: {
bg: 'magenta'
}
});
var radio1 = blessed.radiobutton({
parent: set,
mouse: true,
keys: true,
shrink: true,
style: {
bg: 'magenta'
},
height: 1,
left: 0,
top: 0,
name: 'radio1',
content: 'radio1'
});
var radio2 = blessed.radiobutton({
parent: set,
mouse: true,
keys: true,
shrink: true,
style: {
bg: 'magenta'
},
height: 1,
left: 15,
top: 0,
name: 'radio2',
content: 'radio2'
});
var text = blessed.textbox({
parent: form,
mouse: true,
keys: true,
style: {
bg: 'blue'
},
height: 1,
width: 20,
left: 1,
top: 3,
name: 'text'
});
text.on('focus', function() {
text.readInput();
});
var check = blessed.checkbox({
parent: form,
mouse: true,
keys: true,
shrink: true,
style: {
bg: 'magenta'
},
height: 1,
left: 28,
top: 1,
name: 'check',
content: 'check'
});
var check2 = blessed.checkbox({
parent: form,
mouse: true,
keys: true,
shrink: true,
style: {
bg: 'magenta'
},
height: 1,
left: 28,
top: 14,
name: 'foooooooo2',
content: 'foooooooo2'
});
var submit = blessed.button({
parent: form,
mouse: true,
keys: true,
shrink: true,
padding: {
left: 1,
right: 1
},
left: 29,
top: 3,
shrink: true,
name: 'submit',
content: 'submit',
style: {
bg: 'blue',
focus: {
bg: 'red'
}
}
});
submit.on('press', function() {
form.submit();
});
var box1 = blessed.box({
parent: form,
left: 1,
top: 10,
height: 10,
width: 10,
content: 'one',
style: {
bg: 'cyan'
}
});
var box2 = blessed.box({
parent: box1,
left: 1,
top: 2,
height: 8,
width: 9,
content: 'two',
style: {
bg: 'magenta'
}
});
var box3 = blessed.box({
parent: box2,
left: 1,
top: 2,
height: 6,
width: 8,
content: 'three',
style: {
bg: 'yellow'
}
});
var box4 = blessed.box({
parent: box3,
left: 1,
top: 2,
height: 4,
width: 7,
content: 'four',
style: {
bg: 'blue'
}
});
var output = blessed.scrollabletext({
parent: form,
mouse: true,
keys: true,
left: 0,
top: 20,
height: 5,
left: 0,
right: 0,
style: {
bg: 'red'
},
content: 'foobar'
});
var bottom = blessed.line({
parent: form,
type: 'line',
orientation: 'horizontal',
left: 0,
right: 0,
top: 50,
style: {
fg: 'blue'
}
});
screen.key('q', function() {
return screen.destroy();
});
form.focus();
form.submit();
screen.render();

70
test/widget-image.js Normal file
View File

@ -0,0 +1,70 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/image.log',
smartCSR: true,
warnings: true
});
// To ensure our w3mimgdisplay search works:
if (process.argv[2] === 'find') {
blessed.image.w3mdisplay = '/does/not/exist';
process.argv.length = 2;
}
var file = process.argv[2] || __dirname + '/test-image.png';
var image = blessed.image({
parent: screen,
type: 'overlay',
left: 'center',
top: 'center',
width: 'shrink',
height: 'shrink',
style: {
bg: 'green'
},
draggable: true
});
setTimeout(function() {
image.setImage(file, function() {
// XXX For some reason the image sometimes envelopes
// the entire screen at the end if this is uncommented:
// NOTE: Might have to do with an uncached ratio and
// a bad termSize being reported.
screen.render();
setTimeout(function() {
image.rtop = 4;
image.rleft = 10;
screen.render();
setTimeout(function() {
image.rtop = 2;
image.rleft = 7;
screen.render();
setTimeout(function() {
image.detach();
screen.render();
setTimeout(function() {
screen.append(image);
image.enableMouse();
screen.render();
}, 1000);
}, 1000);
}, 1000);
}, 5000);
});
}, 1000);
image.focus();
screen.key('i', function() {
screen.displayImage(file);
});
screen.key('q', function() {
return screen.destroy();
});
screen.render();

37
test/widget-insert.js Normal file
View File

@ -0,0 +1,37 @@
var blessed = require('../');
var screen = blessed.screen({
dump: __dirname + '/logs/insert.log',
warnings: true
});
var box = blessed.box({
parent: screen,
//align: 'center',
style: {
bg: 'blue'
},
height: 5,
top: 'center',
left: 0,
width: 12,
tags: true,
content: '{yellow-fg}line{/yellow-fg}{|}1',
//valign: 'middle'
});
screen.render();
box.insertBottom('{yellow-fg}line{/yellow-fg}{|}2');
box.insertTop('{yellow-fg}line{/yellow-fg}{|}0');
screen.render();
setTimeout(function() {
box.deleteTop();
screen.render();
}, 2000);
screen.key('q', function() {
screen.destroy();
});

165
test/widget-layout.js Normal file
View File

@ -0,0 +1,165 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/layout.log',
smartCSR: true,
autoPadding: true,
warnings: true
});
var layout = blessed.layout({
parent: screen,
top: 'center',
left: 'center',
width: '50%',
height: '50%',
border: 'line',
layout: process.argv[2] === 'grid' ? 'grid' : 'inline',
style: {
bg: 'red',
border: {
fg: 'blue'
}
}
});
var box1 = blessed.box({
parent: layout,
top: 'center',
left: 'center',
width: 20,
height: 10,
border: 'line',
content: '1'
});
var box2 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '2'
});
var box3 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '3'
});
var box4 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '4'
});
var box5 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '5'
});
var box6 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '6'
});
var box7 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '7'
});
var box8 = blessed.box({
parent: layout,
top: 'center',
left: 'center',
width: 20,
height: 10,
border: 'line',
content: '8'
});
var box9 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '9'
});
var box10 = blessed.box({
parent: layout,
top: 'center',
left: 'center',
width: 20,
height: 10,
border: 'line',
content: '10'
});
var box11 = blessed.box({
parent: layout,
top: 0,
left: 0,
width: 10,
height: 5,
border: 'line',
content: '11'
});
var box12 = blessed.box({
parent: layout,
top: 'center',
left: 'center',
width: 20,
height: 10,
border: 'line',
content: '12'
});
if (process.argv[2] !== 'grid') {
for (var i = 0; i < 10; i++) {
blessed.box({
parent: layout,
// width: i % 2 === 0 ? 10 : 20,
// height: i % 2 === 0 ? 5 : 10,
width: Math.random() > 0.5 ? 10 : 20,
height: Math.random() > 0.5 ? 5 : 10,
border: 'line',
content: (i + 1 + 12) + ''
});
}
}
screen.key('q', function() {
return screen.destroy();
});
screen.render();

122
test/widget-listbar.js Normal file
View File

@ -0,0 +1,122 @@
var blessed = require('../')
, screen;
var auto = true;
screen = blessed.screen({
dump: __dirname + '/logs/listbar.log',
autoPadding: auto,
warnings: true
});
var box = blessed.box({
parent: screen,
top: 0,
right: 0,
width: 'shrink',
height: 'shrink',
content: '...'
});
var bar = blessed.listbar({
//parent: screen,
bottom: 0,
left: 3,
right: 3,
height: auto ? 'shrink' : 3,
mouse: true,
keys: true,
autoCommandKeys: true,
border: 'line',
vi: true,
style: {
bg: 'green',
item: {
bg: 'red',
hover: {
bg: 'blue'
},
//focus: {
// bg: 'blue'
//}
},
selected: {
bg: 'blue'
}
},
commands: {
'one': {
keys: ['a'],
callback: function() {
box.setContent('Pressed one.');
screen.render();
}
},
'two': function() {
box.setContent('Pressed two.');
screen.render();
},
'three': function() {
box.setContent('Pressed three.');
screen.render();
},
'four': function() {
box.setContent('Pressed four.');
screen.render();
},
'five': function() {
box.setContent('Pressed five.');
screen.render();
},
'six': function() {
box.setContent('Pressed six.');
screen.render();
},
'seven': function() {
box.setContent('Pressed seven.');
screen.render();
},
'eight': function() {
box.setContent('Pressed eight.');
screen.render();
},
'nine': function() {
box.setContent('Pressed nine.');
screen.render();
},
'ten': function() {
box.setContent('Pressed ten.');
screen.render();
},
'eleven': function() {
box.setContent('Pressed eleven.');
screen.render();
},
'twelve': function() {
box.setContent('Pressed twelve.');
screen.render();
},
'thirteen': function() {
box.setContent('Pressed thirteen.');
screen.render();
},
'fourteen': function() {
box.setContent('Pressed fourteen.');
screen.render();
},
'fifteen': function() {
box.setContent('Pressed fifteen.');
screen.render();
}
}
});
screen.append(bar);
bar.focus();
screen.key('q', function() {
return screen.destroy();
});
screen.render();

100
test/widget-listtable.js Normal file
View File

@ -0,0 +1,100 @@
var blessed = require('../')
, screen;
screen = blessed.screen({
dump: __dirname + '/logs/listtable.log',
autoPadding: false,
fullUnicode: true,
warnings: true
});
var DU = '杜';
var JUAN = '鹃';
/*
var box = blessed.box({
parent: screen,
top: 'center',
left: 'center',
data: null,
border: 'line',
align: 'center',
tags: true,
keys: true,
width: '90%',
height: '80%',
style: {
bg: 'red'
}
});
*/
var table = blessed.listtable({
//parent: screen,
top: 'center',
left: 'center',
data: null,
border: 'line',
align: 'center',
tags: true,
keys: true,
//width: '80%',
width: 'shrink',
height: '70%',
vi: true,
mouse: true,
style: {
border: {
fg: 'red'
},
header: {
fg: 'blue',
bold: true
},
cell: {
fg: 'magenta',
selected: {
bg: 'blue'
}
}
}
});
var data1 = [
[ 'Animals', 'Foods', 'Times' ],
[ 'Elephant', 'Apple', '1:00am' ],
[ 'Bird', 'Orange', '2:15pm' ],
[ 'T-Rex', 'Taco', '8:45am' ],
[ 'Mouse', 'Cheese', '9:05am' ]
];
data1[1][0] = '{red-fg}' + data1[1][0] + '{/red-fg}';
data1[2][0] += ' (' + DU + JUAN + ')';
var data2 = [
[ 'Animals', 'Foods', 'Times', 'Numbers' ],
[ 'Elephant', 'Apple', '1:00am', 'One' ],
[ 'Bird', 'Orange', '2:15pm', 'Two' ],
[ 'T-Rex', 'Taco', '8:45am', 'Three' ],
[ 'Mouse', 'Cheese', '9:05am', 'Four' ]
];
data2[1][0] = '{red-fg}' + data2[1][0] + '{/red-fg}';
data2[2][0] += ' (' + DU + JUAN + ')';
screen.key('q', function() {
return screen.destroy();
});
table.focus();
table.setData(data2);
screen.append(table);
screen.render();
setTimeout(function() {
table.setData(data1);
screen.render();
}, 3000);

Some files were not shown because too many files have changed in this diff Show More