Compare commits

..
1208 Commits
Author SHA1 Message Date
Daniel Imms f30c38f773 Merge pull request #2515 from Tyriar/r420
v4.2.0
2019-10-25 05:50:45 -07:00
Daniel bfe11b7081 v4.2.0 2019-10-25 05:38:17 -07:00
Daniel Imms a800dd3aab Merge pull request #2514 from Tyriar/scroll
Apply scrollSensitivity on fast scroll too
2019-10-25 05:32:39 -07:00
Daniel a5a0779aa9 Apply scrollSensitivity on fast scroll too
Fixes #2513
2019-10-25 05:22:03 -07:00
Daniel Imms 4fe5a5a0bb Merge pull request #2512 from Tyriar/refine_range
Refine IViewportRange API to use 'cursor positions' for x value
2019-10-25 04:48:51 -07:00
Daniel Imms 974c721f66 Merge pull request #2511 from Tyriar/marker_doc
Clarify marker API docs
2019-10-25 04:45:06 -07:00
Daniel 851fb7ae38 Refine IViewportRange API to use 'cursor positions' for x value
Fixes #2484
2019-10-25 04:43:34 -07:00
jerch 1c72a66567 Merge pull request #2507 from jerch/remove_obsolete_mouseencodings
remove URXVT and UTF8 mouse encoding from codebase
2019-10-25 13:37:00 +02:00
jerch 6f8919ab93 Merge branch 'master' into remove_obsolete_mouseencodings 2019-10-25 13:20:20 +02:00
Daniel dac2da05bf Clarify marker API docs 2019-10-25 04:13:03 -07:00
Daniel Imms 7487d61fe2 Merge pull request #2510 from Tyriar/line_one
Set disposed marker line to -1
2019-10-25 04:08:45 -07:00
Daniel 67e5974eee Set disposed marker line to -1
Another indicator that it's disposed/invalid
2019-10-25 04:04:17 -07:00
jerch 21c3b3243d Merge branch 'master' into remove_obsolete_mouseencodings 2019-10-25 12:53:40 +02:00
Daniel Imms 4bd721c749 Merge pull request #2505 from Tyriar/lgtm_line
Fix lgtm suppression comment line
2019-10-25 03:49:48 -07:00
Jörg Breitbart ee2c1f71ef fix typo in debug msg 2019-10-25 12:43:34 +02:00
Jörg Breitbart a721e4884d Merge branch 'remove_obsolete_mouseencodings' of github.com:jerch/xterm.js into remove_obsolete_mouseencodings 2019-10-25 12:42:17 +02:00
Jörg Breitbart 31be1ebc53 remove DECSET 1005 and 1015 from InputHandler 2019-10-25 12:41:31 +02:00
jerch be59c74eae Merge branch 'master' into remove_obsolete_mouseencodings 2019-10-25 12:02:18 +02:00
jerch c1a0b26150 Merge pull request #2508 from jerch/fix_2423
limit parse buffer size
2019-10-25 12:01:51 +02:00
Jörg Breitbart 13ddaf8f98 limit parse buffer size 2019-10-24 22:32:10 +02:00
jerch 6dc6748876 Merge branch 'master' into remove_obsolete_mouseencodings 2019-10-24 22:07:41 +02:00
jerch 527379d343 Merge pull request #2360 from jerch/left_right_scroll
Support column sequences SL (scroll left), SR (scroll right), DECIC (insert columns) and DECDC (delete columns).
2019-10-24 22:03:30 +02:00
Jörg Breitbart 5ea016d537 remove URXVT and UTF8 encoding from codebase 2019-10-24 21:57:22 +02:00
jerch bb424bd86f Merge branch 'master' into left_right_scroll 2019-10-24 21:46:02 +02:00
Daniel Imms a6f4855f66 Merge pull request #2506 from Tyriar/mp3_sound
Use mp3 audio instead of wav
2019-10-24 12:05:39 -07:00
Daniel Imms fe08f34918 Use mp3 audio instead of wav
wav needs ffmpeg which vscode does not ship with, mp3 is best for compat
2019-10-24 12:04:45 -07:00
Jörg Breitbart 68d6d5576c force screen update for altered lines 2019-10-24 21:01:59 +02:00
Jörg Breitbart a4d561d3b9 xterm testfiles for SL/SR/DECIC/DECDC with DECSTBM 2019-10-24 20:36:01 +02:00
Jörg Breitbart c223524f77 respect DECSTBM 2019-10-24 19:27:35 +02:00
Daniel Imms f8fa962ec7 Fix lgtm suppression comment line 2019-10-24 09:35:12 -07:00
jerch 2a46f5f147 Merge branch 'master' into left_right_scroll 2019-10-24 18:31:51 +02:00
Daniel Imms 080188c468 Merge pull request #2504 from jerch/fix_2495
fix typo in TextDecoder
2019-10-24 09:29:42 -07:00
jerch 1392abb6eb Merge branch 'master' into left_right_scroll 2019-10-24 18:07:35 +02:00
Jörg Breitbart 30d3d46027 make linter happy 2019-10-24 18:04:44 +02:00
Jörg Breitbart 6d620166b4 fix typo in decoder and add a test case 2019-10-24 17:52:03 +02:00
Daniel Imms 276463e95e Merge pull request #2501 from xtermjs/Tyriar-patch-1
Remove double space in dts
2019-10-23 11:37:30 -07:00
Daniel Imms 84e4cf7e9c Remove double space in dts 2019-10-23 11:37:17 -07:00
Daniel Imms d9f58c0dbb Merge pull request #2491 from miggs125/issue#2456
Prevent search result from being deselected if it is the only result
2019-10-22 07:32:26 -07:00
Daniel Imms 3e753f1370 Merge branch 'master' into issue#2456 2019-10-22 07:17:47 -07:00
Daniel Imms 616d341e8c Avoid initializing to undefined 2019-10-22 07:17:37 -07:00
Daniel Imms 15392c6c87 Merge pull request #2493 from leomoty/forbid-only
Forbid only in mocha
2019-10-22 07:15:17 -07:00
Daniel Imms 5e2001f4b5 Space out if 2019-10-22 07:14:32 -07:00
Daniel Imms 5194098f12 Merge pull request #2497 from Tyriar/warn_not_throw
Warn don't throw when open is called on unattached element
2019-10-22 07:02:30 -07:00
Daniel Imms 3ce552cdec Warn don't throw when open is called on unattached element
Related microsoft/vscode#83016
2019-10-22 06:56:05 -07:00
Miguel R 720c8c4623 Merge branch 'master' into issue#2456 2019-10-22 04:14:14 +00:00
Miguel Roncancio 243874c644 change comment 2019-10-21 23:51:47 -04:00
Miguel Roncancio 5d547bffb0 change return value, import ISelectionPosition 2019-10-21 23:49:28 -04:00
Miguel Roncancio 495f97cf95 change return value, import ISelectionPosition 2019-10-21 23:39:01 -04:00
Leonardo Bressan Motyczka 5c2479944e Ensure test-unit fails fast if .only present 2019-10-22 03:00:40 +00:00
Leonardo Bressan Motyczka 51ef0d0680 Update test-unit to allow double dash args 2019-10-22 03:00:18 +00:00
Daniel Imms 2b39887a37 Merge pull request #2492 from jmbockhorst/publicViewportRange
Expose IViewportRange in the public API
2019-10-21 19:18:03 -07:00
Daniel Imms 7c82f9c7d4 Merge pull request #2496 from Tyriar/lgtm_alerts
Fix alerts on lgtm.com
2019-10-21 19:11:23 -07:00
Daniel Imms 1dbe482fcb Suppress server alerts 2019-10-21 19:03:53 -07:00
Daniel Imms cfd158cbff Remove unused imports 2019-10-21 18:48:49 -07:00
Daniel Imms 9826f3a14c Remove unneeded defensive check 2019-10-21 18:47:43 -07:00
Daniel Imms 6f7c91d0cd Remove useless local var assignment 2019-10-21 18:47:18 -07:00
Daniel Imms bcdebe7648 Remove duplicate switch case
Guessing this one was the result of a bad merge?
2019-10-21 18:46:26 -07:00
Daniel Imms 09b244ed2f Fix NaN comparison 2019-10-21 18:44:03 -07:00
Leonardo Bressan Motyczka 7576e8c202 test-api: Fail fast if .only is used 2019-10-21 22:27:25 -03:00
Jon Bockhorst 7b752be68a Expose IViewportRange in the public API 2019-10-21 20:24:03 -05:00
Daniel Imms d02086e5c6 Add test to cover search multiple times 2019-10-21 15:23:59 -07:00
Daniel Imms 5c172c74b2 Merge branch 'master' into issue#2456 2019-10-21 14:34:10 -07:00
Daniel Imms d29fc6d5de Merge pull request #2489 from Tyriar/test_fiix
Remove .only from fit test
2019-10-21 14:31:10 -07:00
miguel 449ede1d57 Prevent search result from being deselected if it is the only result
remove leading whitespace
prevent single search term deselection in findPrevious
2019-10-21 15:58:44 -04:00
Daniel Imms fc10816615 Remove .only from fit test 2019-10-21 11:27:01 -07:00
Daniel Imms 631107698e Merge pull request #2483 from leomoty/fit-tests
Introduce FitAddon tests
2019-10-18 12:13:34 -07:00
Daniel Imms 33d58ec3d2 Merge pull request #2485 from eamodio/feature/scroll-sensitivity
Adds scrollSensitivity option for scrolling speed
2019-10-18 11:42:44 -07:00
Eric Amodio f445bc763b Adds scrollSensitivity option for scrolling speed 2019-10-18 14:30:46 -04:00
Daniel Imms f8a62a23e5 Speed tests up by avoiding page loads 2019-10-18 11:23:11 -07:00
Leonardo Bressan Motyczka a92635b22c Introduce FitAddon tests 2019-10-18 14:53:09 -03:00
Leonardo Bressan Motyczka 44a4bd788f Adjust proposeDimensions to behave like resize 2019-10-18 14:48:56 -03:00
Daniel Imms eb252433ce Merge pull request #2470 from jmbockhorst/linkPosition
Support link position in hover tooltip callback
2019-10-18 08:47:16 -07:00
Daniel Imms 499d6c26f0 Merge branch 'master' into linkPosition 2019-10-17 12:38:14 -07:00
Daniel 8350804858 Adjust to use 1-based, note in API 2019-10-17 12:36:03 -07:00
Daniel Imms 9df547d746 Merge pull request #2482 from Tyriar/2452_website_update
Create a PR for website update after a release
2019-10-17 12:26:45 -07:00
Daniel Imms 7537adfb72 Merge branch 'master' into 2452_website_update 2019-10-17 12:00:13 -07:00
Daniel caf075dcb0 Create a PR for website update after a release 2019-10-17 11:54:32 -07:00
Jon Bockhorst 57581ca4ef Updated IViewportCellPosition wording 2019-10-17 12:40:32 -05:00
Daniel Imms a604389cc0 Merge pull request #2481 from Tyriar/2154_force_release_var
Allow builds to specify a force release var
2019-10-17 10:28:34 -07:00
Jon Bockhorst 08475eb495 Update API to use IViewportRange and IViewportCellPosition 2019-10-17 12:25:42 -05:00
Daniel Imms 91d1f97754 Merge pull request #2476 from Tyriar/2459_win_scroll
Fix scrollback going missing when increase size on Windows
2019-10-17 10:19:46 -07:00
Daniel Imms 990be060f2 Allow builds to specify a force release var
This will let us automate patch releases by queuing a manual build

Fixes #2154
2019-10-17 10:00:45 -07:00
Daniel Imms 29e53c9c11 Merge pull request #2477 from leomoty/devcontainer-hotfix
Allows to run all integration tests inside devcontainer
2019-10-17 09:19:25 -07:00
Daniel Imms da42738881 Merge pull request #2474 from glneto/master
#2463 Add comma as a default word separator
2019-10-17 09:07:06 -07:00
Geraldo Neto 9753a7d425 Merge branch 'master' into master 2019-10-16 20:16:56 -03:00
Leonardo Bressan Motyczka 07308485a4 Update MouseTracking puppeteer window size
This allows all tests to successfully run in devcontainer
2019-10-16 20:08:57 -03:00
Leonardo Bressan Motyczka 3d500ba802 Launch puppeteer without sandbox 2019-10-16 20:07:56 -03:00
Leonardo Bressan Motyczka e8dc563ccf Include puppeteer deps on devcontainer 2019-10-16 20:05:45 -03:00
Daniel Imms ee245230c9 Merge branch 'master' into 2459_win_scroll 2019-10-16 15:44:19 -07:00
Daniel Imms 843ea1b610 Fix scrollback going missing when increase size on Windows
This also forces the scroll bar to sync after a resize early, this may fix
other bugs.

Fixes #2459
2019-10-16 15:41:47 -07:00
Geraldo Neto 9f80ce25c2 Add : and ; to the word separator 2019-10-16 19:23:50 -03:00
Daniel Imms bd57e305e1 Merge pull request #2475 from Tyriar/vsc_82309
Protect against exception when clicking on mouse zones
2019-10-16 11:08:16 -07:00
Daniel Imms 740d261d7a Protect against exception when clicking on mouse zones
Still not sure how this happens but seems harmless to just not use the row as
wrapped here.

See microsoft/vscode#82309
2019-10-16 11:07:22 -07:00
Geraldo Neto 1bc246323c Add comma as a default word separator 2019-10-15 22:42:12 -03:00
Daniel Imms 91cbeecf52 Merge pull request #2473 from Tyriar/2471
Mark element and textarea APIs as | undefined
2019-10-15 16:41:59 -07:00
Daniel Imms cfe8022867 Mark element and textarea APIs as | undefined
Didn't fix all the issues in Terminal.ts as they will be covered in layering
refactor

Fixes #2471
2019-10-15 16:29:13 -07:00
Daniel Imms 99db619a5c Merge pull request #2375 from csurquin/feat/fast-scrolling
Support fast scrolling using a modifier key
2019-10-15 16:23:17 -07:00
Daniel Imms 4f8cda9f3a Remove bad whitespace 2019-10-15 16:22:41 -07:00
Daniel Imms 9fdb674f20 Use min of 1 for fast scroll 2019-10-15 16:22:09 -07:00
Daniel Imms e76b8f86b5 Pull modifier code into helper, apply to lines scrolled 2019-10-15 16:21:20 -07:00
Daniel Imms 0083c23b2d Merge branch 'master' into feat/fast-scrolling 2019-10-15 16:10:44 -07:00
Jon Bockhorst 040f9f49d9 Support link position in hover tooltip callback 2019-10-14 14:25:02 -05:00
Daniel Imms cbb79a77f9 Merge pull request #2467 from Tyriar/2387_dont_do_ctrl_arrow_on_mac
Don't use ctrl+up/down hack on macOS
2019-10-14 11:53:27 -07:00
Daniel Imms a97fe2df1c Merge pull request #2469 from leomoty/dispose-test
Add integration test for terminal dispose
2019-10-14 10:58:07 -07:00
Leonardo Bressan Motyczka ff13f74858 Add integration test for terminal dispose 2019-10-14 13:20:18 -03:00
Daniel Imms 3d6815ca6f Add tests for alt+up/down 2019-10-11 16:05:54 -07:00
Daniel Imms da11e31fe5 Don't use ctrl+up/down hack on macOS
Fixes #2387
2019-10-11 16:01:28 -07:00
Daniel Imms e224b865fd Merge pull request #2465 from syrusakbary/patch-1
Added WebAssembly.sh
2019-10-10 13:54:25 -07:00
Syrus Akbary 821a7afc01 Added WebAssembly.sh 2019-10-10 13:05:28 -07:00
Daniel Imms 84b56b7691 Merge pull request #2453 from Tyriar/2445_reveal_search
Reveal search results in line just below viewport
2019-10-08 07:05:21 -07:00
Daniel Imms 8288a26b49 Merge pull request #2455 from JeffreyCA/unfocused-cursor-style
Update unfocused cursor to match current cursor style
2019-10-08 06:43:03 -07:00
Daniel Imms d87bae374b Merge pull request #2454 from saisandeepvaddi/master
add ten hands to real-world uses list
2019-10-08 06:36:55 -07:00
JeffreyCA 7c982fc0ce Fix lint warnings 2019-10-07 22:51:03 -07:00
JeffreyCA 1eb6e37187 Refresh terminal even if blinking is enabled so cursor changes are immediately visible 2019-10-07 22:36:37 -07:00
JeffreyCA efbdbd3f3b Render non-block cursors as-is when terminal is unfocused 2019-10-07 22:25:47 -07:00
Sai Sandeep Vaddi 7fc57da85a add ten hands to real-world uses list 2019-10-07 23:45:03 -04:00
Daniel Imms 6f5e5215f2 Reveal search results in line just below viewport
Fixes #2445
2019-10-07 14:27:29 -07:00
Daniel Imms cad9477eef Merge pull request #2451 from Tyriar/1416_fit_infinity
Generalize verify integers check
2019-10-07 10:46:07 -07:00
Daniel Imms 4fde8db060 Merge pull request #2450 from Tyriar/1158_throw_bad_open
Throw when open is called on element not on DOM
2019-10-07 10:45:38 -07:00
Daniel Imms 724bcc3766 Generalize verify integers check
Fixes #1416
2019-10-07 10:28:51 -07:00
Daniel Imms 52ae8fc14b Throw when open is called on element not on DOM
Fixes #1158
2019-10-07 10:21:34 -07:00
Daniel Imms e14b1f75fe Merge pull request #2449 from Tyriar/release_41
Release v4.1.0
2019-10-07 09:54:48 -07:00
Daniel Imms da5bf975b4 Merge branch 'master' into release_41 2019-10-07 09:44:30 -07:00
Daniel Imms 22398c0927 v4.1.0 2019-10-07 09:42:20 -07:00
Daniel Imms 43b291112e Merge pull request #2448 from Tyriar/597_cmd_arrow
Don't handle cmd+arrow
2019-10-07 08:27:42 -07:00
Daniel Imms 87a1fca726 Merge pull request #2447 from Tyriar/ts36
Upgrade to typescript 3.6
2019-10-07 08:27:28 -07:00
Daniel Imms 52e211915e Don't handle cmd+arrow
Fixes #597
2019-10-07 08:02:58 -07:00
Daniel Imms 92c991132f Upgrade to typescript 3.6 2019-10-07 07:55:48 -07:00
jerch 89ac2834f1 Merge branch 'master' into left_right_scroll 2019-10-04 20:12:34 +02:00
Daniel Imms 358c09a108 Merge branch 'master' into feat/fast-scrolling 2019-09-28 09:30:23 -07:00
Daniel Imms ff790236c1 Merge pull request #2442 from Tyriar/2441_windows_demo
Fix demo on Windows
2019-09-28 09:29:47 -07:00
Daniel Imms 9014a27d7d Fix demo on Windows
Fixes #2441
2019-09-28 09:25:41 -07:00
Daniel Imms 5236d4aabf Merge branch 'master' into feat/fast-scrolling 2019-09-28 08:51:28 -07:00
Daniel Imms ea922fe548 Merge pull request #2422 from jerch/write_enhancement
write callback support
2019-09-25 17:19:42 -07:00
Daniel Imms 22b06cada7 Merge pull request #2425 from Tyriar/constant_key_board
Use more C0 constants in Keyboard
2019-09-25 17:06:17 -07:00
Daniel Imms 5a65286c54 Merge branch 'master' into write_enhancement 2019-09-25 17:03:00 -07:00
Daniel Imms 0e8883ac99 Strongly type addSocketListener 2019-09-25 17:00:31 -07:00
Daniel Imms 5cb0bcea0f Merge pull request #2437 from kafeg/patch-1
Update README.md
2019-09-24 08:18:38 -07:00
Vitaly Petrov 2fd24849b2 Update README.md 2019-09-24 17:46:12 +03:00
Daniel Imms b81711e3da Merge pull request #2434 from Tyriar/2433_npe
Fix NPE when open called twice (master)
2019-09-23 10:55:21 -07:00
Daniel Imms 0c740213e3 Merge branch 'master' into 2433_npe 2019-09-23 07:49:34 -07:00
Daniel Imms f3b7866a19 Fix NPE when open called twice
Fixes #2433
2019-09-23 07:47:02 -07:00
Jörg Breitbart d34d1f56cb simplify attach addon 2019-09-22 22:33:55 +02:00
Jörg Breitbart 322565807b Merge branch 'master' into write_enhancement 2019-09-22 20:59:28 +02:00
Jörg Breitbart 1178ef2a12 Merge branch 'write_enhancement' of github.com:jerch/xterm.js into write_enhancement 2019-09-22 20:57:26 +02:00
Jörg Breitbart 6aab756ccd integration callback tests 2019-09-22 20:57:00 +02:00
Jörg Breitbart d1bd603382 unit tests 2019-09-22 20:39:09 +02:00
Daniel Imms 191932cce2 Merge pull request #2431 from Tyriar/2117_tests
Add tests for IL, DL and DCH
2019-09-14 14:31:00 -07:00
Daniel Imms bc7ba7bd85 Simplify test 2019-09-14 12:57:41 -07:00
Daniel Imms 74ba282056 Add tests for DCH (CSI Ps P)
Part of #2117
2019-09-14 12:15:16 -07:00
Daniel Imms 96f944522e Add tests for DL (CSI Ps M)
Part of #2117
2019-09-14 12:05:00 -07:00
Daniel Imms bf209fb71f Add tests for IL (CSI Ps L)
Part of #2117
2019-09-14 11:53:42 -07:00
Daniel Imms 3b537c7e9f Improve api jsdoc 2019-09-13 09:32:38 -07:00
Daniel Imms ce39c0633c Merge pull request #2429 from Tyriar/update_addons
Use v4 for addon peer dependency and release
2019-09-13 09:18:11 -07:00
Daniel Imms aba4d76ec6 v0.2.1 of all addons 2019-09-13 09:16:55 -07:00
Daniel Imms 91734f7659 Set addon peer deps to v4
Fixes #2428
2019-09-13 09:16:22 -07:00
Jörg Breitbart 1ac3cf8fca use callback in paste integration test 2019-09-13 16:45:40 +02:00
Jörg Breitbart c2ec16a16c encapsulate deferred writing in WriteBuffer class 2019-09-13 16:31:28 +02:00
Jörg Breitbart e402772cf7 Merge branch 'master' into write_enhancement 2019-09-13 13:30:10 +02:00
Jörg Breitbart d9ba19ba9e remove write sync hack from Terminal.test.ts 2019-09-13 13:23:59 +02:00
Jörg Breitbart a95e451227 add params in doc 2019-09-13 13:19:33 +02:00
Jörg Breitbart fe74b5588d use write callback in benchmark test 2019-09-13 13:11:23 +02:00
Jörg Breitbart dcbc7e1014 remove writeln from core 2019-09-13 13:06:54 +02:00
Jörg Breitbart 50e552262a remove writeUtf8 from core 2019-09-13 13:00:47 +02:00
Jörg Breitbart 597757d0ee use write callbacks in addon integration tests 2019-09-13 12:44:13 +02:00
Daniel Imms 5d3313a8ca Merge pull request #2427 from Tyriar/dist_remove
Remove extra build in publish Release job
2019-09-12 15:33:17 -07:00
Daniel Imms 9d291d1d12 Remove extra build in publish Release job
We no longer publish a dist dir
2019-09-12 15:16:03 -07:00
Daniel Imms 7da361af9f Merge pull request #2424 from Tyriar/logging_data
Improve debug logging by printing character codes
2019-09-12 14:02:58 -07:00
Daniel Imms 761e437c69 Allow lazy evaluated log params 2019-09-12 13:38:30 -07:00
Daniel Imms fc4f345446 Don't transform incoming data
This would run for all data
2019-09-12 11:24:04 -07:00
Daniel Imms 0a4883b2b3 Use more C0 constants in Keyboard 2019-09-12 11:14:41 -07:00
Daniel Imms 293f54e8dd Improve debug logging by printing character codes 2019-09-12 11:06:22 -07:00
Jörg Breitbart 05fad38240 fix private access in integration tests 2019-09-12 13:58:52 +02:00
Jörg Breitbart 75ba717bd7 merge write methods, optional callback 2019-09-12 13:36:58 +02:00
jerch 19f0fc0aa9 Merge branch 'master' into left_right_scroll 2019-09-12 10:55:36 +02:00
Daniel Imms ffd27dfef0 Merge pull request #2419 from Tyriar/master_changes
Master changes for 4.0.1 fixes
2019-09-11 14:50:58 -07:00
Daniel Imms e042f25b8d Expose ctor at window.Terminal
Fixes #2415
2019-09-11 14:39:26 -07:00
Daniel Imms 7f9f757042 Fix web links addon support in Edge
regex.flags isn't supported on Edge

Fixes #2417
2019-09-11 14:39:11 -07:00
Daniel Imms 6211dcd923 Merge pull request #2412 from Tyriar/v4
Publish v4.0.0
2019-09-10 17:02:57 -07:00
Daniel Imms 2f2d941557 Merge branch 'master' into v4 2019-09-10 17:02:11 -07:00
Daniel Imms 9a13479692 v4.0.0 2019-09-10 17:00:18 -07:00
Daniel Imms e34b557f67 Remove experimental flag from ITerminalAddon.activate 2019-09-10 16:29:25 -07:00
Daniel Imms 26a09f05a5 Merge pull request #2410 from Tyriar/bump_addons
Bump addon versions for v4 release
2019-09-10 15:54:52 -07:00
Daniel Imms 230d26afc7 Bump addon versions for v4 release 2019-09-10 15:54:01 -07:00
Daniel Imms 3aa0599722 Merge pull request #2406 from Tyriar/doc_update
Fix paths in example for v4
2019-09-09 10:27:08 -07:00
Daniel Imms 238d81dbc8 Merge pull request #2405 from Tyriar/sourcemaps
Expose source maps on demo server
2019-09-09 10:26:58 -07:00
Daniel Imms b990eb42c6 Fix paths in example for v4
Fixes #2146
2019-09-09 10:25:07 -07:00
Daniel Imms 1f12d365c8 Expose source maps on demo server
Fixes #2258
2019-09-09 10:21:37 -07:00
Daniel Imms fdfa871b37 Merge pull request #2404 from Tyriar/addon_readmes
Add/polish the readme for all addons
2019-09-09 09:32:44 -07:00
Daniel Imms 87c167a212 Improve logging for addon publish 2019-09-09 09:32:32 -07:00
Daniel Imms f7dade1023 Add/polish the readme for all addons
Fixes #2193
2019-09-09 09:28:33 -07:00
Daniel Imms 5e1de3b062 Merge branch 'master' into feat/fast-scrolling 2019-09-07 13:49:42 -07:00
Daniel Imms 91691085f6 Merge pull request #2402 from Tyriar/2401_dont_scroll
Don't execute move to cell when the user has scrolled up
2019-09-06 09:38:59 -07:00
Daniel Imms 81c5fd4988 Don't execute move to cell when the user has scrolled up
Fixes #2401
2019-09-06 09:27:20 -07:00
jerch 54739d625f Merge branch 'master' into left_right_scroll 2019-09-05 21:54:22 +02:00
Daniel Imms 9fdae76cca Merge pull request #2400 from Tyriar/webpack
webpack@4.39.3
2019-09-05 12:45:54 -07:00
Daniel Imms b6683b7e9f webpack@4.39.3
Fixes security alert on set-value
2019-09-05 12:22:54 -07:00
Daniel Imms 62215ac493 Merge pull request #2399 from xtermjs/dependabot/npm_and_yarn/mixin-deep-1.3.2
Bump mixin-deep from 1.3.1 to 1.3.2
2019-09-05 12:18:34 -07:00
jerch bc5e1e6012 Merge pull request #2323 from jerch/mouse_services
CoreMouseService
2019-09-05 21:08:48 +02:00
jerch 6a5223b9fb Merge branch 'master' into mouse_services 2019-09-05 20:59:11 +02:00
dependabot[bot] b85db39dc4 Bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-09-05 18:45:17 +00:00
Daniel Imms aac8f9f76c Merge pull request #2398 from Tyriar/2395_repo
Add repo field to addon package.json
2019-09-05 11:44:04 -07:00
Daniel Imms cc94dfd013 Add repo field to addon package.json
Fixes #2395
2019-09-05 11:27:03 -07:00
jerch 1b832b05a0 Merge pull request #2397 from jerch/fix_function_identifier
fix stacking of multiple intermediates
2019-09-04 13:55:46 +02:00
Jörg Breitbart 6d66c6a0c8 tests for function identifiers; fix stacking of multiple intermediates 2019-09-02 10:07:12 +02:00
jerch 97bf796c43 Merge branch 'master' into left_right_scroll 2019-08-23 20:37:13 +02:00
jerch 4fd651f86f Merge branch 'master' into mouse_services 2019-08-23 20:36:36 +02:00
jerch 3938231c16 Merge pull request #2392 from jerch/fix_2389
fix several bugs in Params
2019-08-23 20:33:21 +02:00
Jörg Breitbart 87eb942d32 remove comment 2019-08-23 20:21:58 +02:00
jerch 54ff71f982 Merge branch 'master' into left_right_scroll 2019-08-23 16:45:42 +02:00
Jörg Breitbart 36b3bbd541 Merge branch 'master' into mouse_services 2019-08-23 16:37:16 +02:00
Jörg Breitbart a7e64ad537 fix bugs 2019-08-23 15:32:05 +02:00
Daniel Imms a67f57d693 Merge pull request #2388 from ShahzadUmair/Support-for-bubbling-scroll
Support for bubbling scroll events to parent(s)
2019-08-22 09:12:41 -07:00
Daniel Imms f91aa75c80 Indent second line of if condition 2019-08-22 09:12:04 -07:00
Daniel Imms 211700518f Merge pull request #2391 from Tyriar/2390_paste_api
Expose paste API
2019-08-22 09:06:27 -07:00
Daniel Imms a2d890cf74 Add paste api integration tests 2019-08-22 08:54:28 -07:00
Daniel Imms 9c7cf8e6e6 Cover another paste case 2019-08-22 08:39:50 -07:00
Daniel Imms 441d27cb5a Expose paste API
Fixes #2390
2019-08-22 08:39:02 -07:00
UmairShahzad 582934390d restructured bubble scroll 2019-08-21 00:57:41 +05:00
UmairShahzad e91c1c28d8 Merge remote-tracking branch 'upstream/master' into Support-for-bubbling-scroll 2019-08-21 00:46:07 +05:00
Jörg Breitbart f7827c4df8 add basic tests for commands 2019-08-17 18:52:11 +02:00
Jörg Breitbart 4b5709c68d add DECIC/DECDC to interface 2019-08-17 18:13:56 +02:00
Jörg Breitbart 4fe78dfe34 Merge branch 'master' into left_right_scroll 2019-08-17 17:57:31 +02:00
Jörg Breitbart 64c06d34fa remove any types 2019-08-17 14:45:11 +02:00
Jörg Breitbart a215362764 drop leftover aux button support, cleanup remnants 2019-08-17 13:41:15 +02:00
Jörg Breitbart 82d1bd86da only report on loglevel debug, explain events 2019-08-17 13:30:54 +02:00
Jörg Breitbart ae914c17d8 Merge branch 'master' into mouse_services 2019-08-16 22:06:04 +02:00
jerch 5a9e6fe94b Merge pull request #2346 from jerch/parser_hooks
Parser API
2019-08-16 21:26:33 +02:00
Jörg Breitbart 1c20057ed3 add parser property to interface 2019-08-16 21:14:49 +02:00
Jörg Breitbart 29a6f3f3ca Merge branch 'master' into parser_hooks 2019-08-16 21:00:24 +02:00
Daniel Imms 54d21579dd Merge pull request #2385 from lramos15/viewport-no-scroll
Don't scroll terminal search result if within viewport
2019-08-16 09:39:17 -07:00
Logan Ramos f3d8e74d6f Remove forgotten console .log 2019-08-16 10:55:16 -04:00
Logan Ramos 85444def9f Don't scroll terminal search result if within viewport 2019-08-16 10:50:44 -04:00
UmairShahzad 6c3b084fe9 added scroll bubbling on wheel and touch move events 2019-08-15 07:41:23 +05:00
Daniel Imms 95ff15457b Merge pull request #2381 from Tyriar/2380_links
Ensure selection service mousedown happens after mouse zone manager
2019-08-12 18:10:30 -07:00
Daniel Imms 63fd3be67a Ensure selection service mousedown happens after mouse zone manager
Fixes #2380
2019-08-12 17:56:26 -07:00
Jörg Breitbart a2c266a005 rename handler type aliases to XyType to avoid ambiguity with class based types 2019-08-11 18:45:34 +02:00
Jörg Breitbart 3a5d0bd368 fix escHandlers type and disposing 2019-08-11 18:38:35 +02:00
Jörg Breitbart 7c47fafb07 Merge branch 'parser_hooks' of github.com:jerch/xterm.js into parser_hooks 2019-08-11 17:55:42 +02:00
Jörg Breitbart b35383915d cleanup interfaces 2019-08-11 17:55:24 +02:00
Daniel Imms d05d6e6848 Merge branch 'master' into parser_hooks 2019-08-11 08:38:37 -07:00
Jörg Breitbart f677516e95 better interfaces, cleanup 2019-08-11 16:45:35 +02:00
Daniel Imms f3b9dc00b6 Merge pull request #2378 from Tyriar/2204_refresh
Fix dom -> canvas renderer switch not drawing viewport
2019-08-10 18:23:28 -07:00
Daniel Imms c758d7de55 Merge pull request #2377 from Tyriar/2076_remove_applyAddon
Remove applyAddon, stabilize loadAddon
2019-08-10 17:54:53 -07:00
Daniel Imms 63af42ba38 Merge pull request #2376 from Tyriar/2361
Move buffer tests to Terminal.test.ts and re-enable
2019-08-10 17:53:09 -07:00
Daniel Imms dd42eccb91 Fix dom -> canvas renderer switch not drawing viewport
Fixes #2204
2019-08-10 17:51:17 -07:00
Daniel Imms ba1274ba12 Remove applyAddon, stabilize loadAddon
Fixes #2076
2019-08-10 14:31:14 -07:00
Daniel Imms 13dde8061f Move buffer tests to Terminal.test.ts and re-enable
Fixes #2361
2019-08-10 14:23:17 -07:00
Daniel Imms e58a84df6a Merge branch 'master' into parser_hooks 2019-08-10 14:15:11 -07:00
Corentin Surquin a353a8cffe Allow to disable fast scrolling 2019-08-10 19:45:41 +02:00
Corentin Surquin 73a17cfacb Support fast scrolling using a modifier key 2019-08-10 19:45:41 +02:00
Daniel Imms e254d61c65 Merge pull request #2374 from Tyriar/2373_blink
Fix DOM blink for non-block cursors
2019-08-10 07:52:26 -07:00
Daniel Imms afe08d82d8 Merge branch 'master' into 2373_blink 2019-08-10 07:39:49 -07:00
Daniel Imms 598d37a023 Fix DOM blink for non-block cursors
Fixes #2373
2019-08-10 07:38:44 -07:00
Daniel Imms 30161c3b5a Merge pull request #2371 from Tyriar/2370
Fix mouse events class apply on open
2019-08-09 10:07:43 -07:00
Daniel Imms 0a9de5eb8c Merge branch 'master' into 2370 2019-08-09 09:56:16 -07:00
Daniel Imms 811c24b866 Fix mouse events class apply on open
Fixes #2370
2019-08-09 09:55:31 -07:00
Jörg Breitbart 0469e271da cache ParserApi, remove namespace 2019-08-08 21:58:02 +02:00
Jörg Breitbart 1286eb618a rename to OscHandler and DcsHandler 2019-08-08 19:41:12 +02:00
Jörg Breitbart 20fa447033 namespace parser related stuff 2019-08-08 19:34:00 +02:00
Jörg Breitbart a97742c765 Merge branch 'master' into parser_hooks 2019-08-08 18:51:12 +02:00
Daniel Imms 58e1b0db38 Merge pull request #2355 from jerch/fix_2354
DECSTBM issues
2019-08-07 07:51:18 -07:00
Daniel Imms 61e582969e Merge pull request #2366 from Tyriar/2365_shift_click
Don't throw if first click is incremental
2019-08-07 07:42:45 -07:00
Daniel Imms 29d8493a7a Don't throw if first click is incremental
Fixes #2365
2019-08-07 07:18:27 -07:00
Jörg Breitbart 4200e8356b apply BCE to SU/SD 2019-08-04 17:07:56 +02:00
Jörg Breitbart 8bc0099434 linter nonsense 2019-08-04 15:37:47 +02:00
Jörg Breitbart 9a903ca1c5 add DECIC/DECDC 2019-08-04 15:32:32 +02:00
Jörg Breitbart 5483a052cc always reset wrapped flag 2019-08-04 15:15:59 +02:00
Jörg Breitbart bd132d1f74 implement left/right scroll 2019-08-04 15:04:40 +02:00
Jörg Breitbart 6285cbf976 fix IL/DL test 2019-08-04 13:46:37 +02:00
Jörg Breitbart 00298531ed respect scroll margins in CUU/CUD/CPL/CNL; test files 2019-08-04 12:20:44 +02:00
Jörg Breitbart 2a533e7236 map DECEL back to eraseInLine 2019-08-04 09:00:07 +02:00
Jörg Breitbart 4e8a1c5656 Merge remote-tracking branch 'upstream/master' into parser_hooks 2019-08-04 08:56:34 +02:00
Jörg Breitbart eccd6d7bdf enable NEL test 2019-08-03 15:05:44 +02:00
Jörg Breitbart 497a5e6e84 fix DECSTBM with IND 2019-08-03 15:00:30 +02:00
Jörg Breitbart 84d7591506 increase test timeout 2019-08-02 21:06:16 +02:00
Jörg Breitbart 0958f0ef91 fix DECSTBM with LF 2019-08-02 15:29:26 +02:00
Jörg Breitbart d28b601066 doc multi button tests as not doable 2019-08-01 16:52:19 +02:00
Jörg Breitbart bf2cc23eb0 tests for DECSET 1003 2019-08-01 16:15:55 +02:00
Jörg Breitbart b8b3cdbc3e increase test timeout 2019-08-01 12:08:07 +02:00
Jörg Breitbart 565b0791d8 fix osx tests 2019-08-01 11:50:15 +02:00
Jörg Breitbart 51feff3330 Merge branch 'mouse_services' of github.com:jerch/xterm.js into mouse_services 2019-08-01 01:16:49 +02:00
Jörg Breitbart 4dec88212e fix mouse tests 2019-08-01 01:16:29 +02:00
Jörg Breitbart aa8165a756 Merge branch 'master' into mouse_services 2019-07-31 23:12:05 +02:00
jerch a89771a8de Merge pull request #2321 from jerch/mouse_report_tests
Mouse tracking tests
2019-07-31 23:06:44 +02:00
Daniel Imms 6840f51b52 Merge branch 'master' into mouse_report_tests 2019-07-31 12:21:18 -07:00
Daniel Imms d20068c2db Merge pull request #2353 from Tyriar/multiple_dispose
Make dispose idempotent
2019-07-31 11:02:59 -07:00
Daniel Imms efaa78faee Make dispose idempotent
Fixes #2351
2019-07-31 10:55:39 -07:00
Jörg Breitbart bbd7275ad7 make linter happy 2019-07-31 14:44:50 +02:00
Jörg Breitbart 7252a5921d cleanup parser rules and docs 2019-07-31 14:20:36 +02:00
Jörg Breitbart 83a1340cc4 abort and cleanup subparsers for CAN and SUB 2019-07-31 12:03:12 +02:00
Jörg Breitbart 812fc5e6ec register functions by prefix/intermediate/final bytes 2019-07-31 04:49:01 +02:00
jerch 9d32dc4522 Merge branch 'master' into mouse_services 2019-07-26 18:23:57 +02:00
jerch 54586f75eb Merge branch 'master' into mouse_report_tests 2019-07-26 18:19:37 +02:00
Jörg Breitbart d78c062169 Merge branch 'master' into parser_hooks 2019-07-26 18:15:43 +02:00
Jörg Breitbart 0106bdcb73 parser tests for addDcsHandler 2019-07-26 18:11:31 +02:00
Jörg Breitbart 0a2d9a2120 addOscHandler integration test 2019-07-26 17:48:36 +02:00
Jörg Breitbart bffa78585e test cases for payload limits 2019-07-26 17:35:37 +02:00
Jörg Breitbart a9b2728c07 add DCS interface, payload limits for DCS/OSC 2019-07-26 15:59:24 +02:00
Jörg Breitbart 82aaef29f1 dcs parser tests 2019-07-26 15:07:24 +02:00
Jörg Breitbart c9b7aefb88 reset internal state on unhook 2019-07-26 02:56:48 +02:00
Jörg Breitbart 229a7ec755 Merge branch 'parser_hooks' of github.com:jerch/xterm.js into parser_hooks 2019-07-26 01:58:59 +02:00
Jörg Breitbart 6606024c2b support for multiple DCS handler 2019-07-26 01:58:42 +02:00
Daniel Imms 689fb6b6ad Merge pull request #2348 from xtermjs/Tyriar-patch-1
Fix NPE on dispose when it hasn't been opened
2019-07-25 16:53:25 -07:00
Daniel Imms 3dc52184e5 Fix NPE on dispose when it hasn't been opened 2019-07-25 16:49:26 -07:00
Daniel Imms 41331150ff Merge branch 'master' into parser_hooks 2019-07-25 14:43:53 -07:00
Daniel Imms 26948f044d Merge pull request #2345 from xtermjs/Tyriar-patch-1
Remove describe.only
2019-07-25 14:31:12 -07:00
Jörg Breitbart f985c30847 add addEscHandler 2019-07-25 22:44:08 +02:00
Jörg Breitbart 1f4dde601e remove experimental from addCsiHandler 2019-07-25 21:38:50 +02:00
Jörg Breitbart c87b3fd942 integration test for addOscHandler 2019-07-25 21:37:51 +02:00
Jörg Breitbart f626e1c93d fix OSC parsing 2019-07-25 20:38:14 +02:00
Daniel Imms 3f53f0ed29 Remove describe.only 2019-07-25 10:57:03 -07:00
Daniel Imms 378982a3ff Merge pull request #2344 from lramos15/search-tests
Puppeteer Tests for the Search Addon
2019-07-25 10:54:06 -07:00
Daniel Imms dc8f9f0a6d Merge branch 'master' into search-tests 2019-07-25 10:50:42 -07:00
Logan Ramos dcb39a658c Case sensitivity enabled 2019-07-25 10:41:55 -07:00
Logan Ramos 6869184864 More RegEx tests 2019-07-25 10:39:11 -07:00
Logan Ramos bb4c694f8d More search tests 2019-07-25 10:33:33 -07:00
Daniel Imms 33d4e08eba Merge pull request #2343 from Tyriar/cancel_events
Cancel keydown events when not in screenReaderMode
2019-07-25 10:19:53 -07:00
Daniel Imms 41f418e91e Revert tests to how they used to be 2019-07-25 10:13:50 -07:00
Daniel Imms bc30182752 Merge branch 'master' into cancel_events 2019-07-25 10:10:17 -07:00
Daniel Imms 7479131747 Cancel keydown events when not in screenReaderMode
This caused issues with embedder keybinding systems firing when they
shouldn't be. The fix is to only allow it in screenReaderMode as a
compromise so keys are echoed.
2019-07-25 10:08:41 -07:00
Daniel Imms 9715bdc45c Merge pull request #2340 from lramos15/lramos15/searchaddon-change
Changes default search addon behavior
2019-07-25 09:18:06 -07:00
Logan Ramos badfac2091 Merge branch 'lramos15/searchaddon-change' into search-tests 2019-07-25 09:10:06 -07:00
Logan Ramos a1be1f0b35 Code cleanup 2019-07-25 09:02:32 -07:00
Logan Ramos ea72a3b594 Fix incremental search bug 2019-07-25 08:50:37 -07:00
Jörg Breitbart d8364d749c remove null type from dcsHandler 2019-07-25 01:15:18 +02:00
Daniel Imms db936701f4 Include incremental in getSearchOptions 2019-07-24 16:09:57 -07:00
Logan Ramos d104f39a9d Incremental previous search 2019-07-24 16:01:07 -07:00
Logan Ramos 9ff5dc5858 Merge remote-tracking branch 'origin/lramos15/searchaddon-change' into search-tests 2019-07-24 15:33:26 -07:00
Jörg Breitbart 20a8e56201 Merge branch 'mouse_report_tests' of github.com:jerch/xterm.js into mouse_report_tests 2019-07-25 00:30:51 +02:00
Jörg Breitbart 113847aedf Merge branch 'master' into mouse_report_tests 2019-07-25 00:30:31 +02:00
Logan Ramos f3f52e6920 Changed default Search Addon behavior 2019-07-24 15:30:09 -07:00
Jörg Breitbart e32dbc6137 Merge branch 'master' into mouse_services 2019-07-25 00:29:06 +02:00
Logan Ramos cae3d59e23 Change search addon behavior 2019-07-24 15:09:59 -07:00
Daniel Imms 4ee0e3fec4 Merge branch 'master' into mouse_report_tests 2019-07-24 15:04:34 -07:00
Logan Ramos 7860dccdcf Search addon tests 2019-07-24 14:53:14 -07:00
Logan Ramos 79dcef0e6c Merge remote-tracking branch 'xterm/master' into search-tests 2019-07-24 14:05:00 -07:00
Daniel Imms 52c562d4b1 Merge pull request #2338 from Tyriar/debug_log
Move verbose logs in InputHandler to debug level
2019-07-24 12:27:44 -07:00
Daniel Imms 8447bcbb3b Merge branch 'master' into debug_log 2019-07-24 12:21:41 -07:00
Daniel Imms 8d76998df3 Merge pull request #2315 from Tyriar/layering4
Move renderer into browser
2019-07-24 12:21:27 -07:00
Daniel Imms 752243d95f Move verbose logs in InputHandler to debug level 2019-07-24 12:21:10 -07:00
Daniel Imms 1c0a263b03 Merge branch 'master' into layering4 2019-07-24 11:46:20 -07:00
Jörg Breitbart 4fba080d34 deactivate wheel left/right, docs 2019-07-24 15:14:37 +02:00
Jörg Breitbart f68769e5f3 Merge branch 'master' into mouse_services 2019-07-24 14:14:19 +02:00
Jörg Breitbart fb38bd13cd fix general purpose test script 2019-07-24 12:51:24 +02:00
Jörg Breitbart 6391742951 Merge branch 'master' into mouse_report_tests 2019-07-24 11:22:14 +02:00
Daniel Imms cb094b27a6 Merge pull request #2335 from Tyriar/unit_exit_code
Fix unit tests and the returned exit code
2019-07-23 14:41:41 -07:00
Daniel Imms ac8107d1df Fix lint errors 2019-07-23 14:32:13 -07:00
Daniel Imms edfef95bb3 Get tests passing 2019-07-23 14:22:49 -07:00
Daniel Imms ca0b8fdd8c Exit with correct exit code in test-unit 2019-07-23 14:19:07 -07:00
Jörg Breitbart 776c6dffea refactor buttons, wheel with left right 2019-07-23 20:16:42 +02:00
Jörg Breitbart 88faf1bcfe Merge branch 'master' into mouse_services 2019-07-23 18:27:34 +02:00
Jörg Breitbart 6463a1fe51 increase mouse test timeout 2019-07-23 17:15:30 +02:00
Jörg Breitbart 595465ec4f fix azure tasks 2019-07-23 17:04:38 +02:00
Jörg Breitbart edf881b19c macOS integration tests 2019-07-23 17:02:23 +02:00
Jörg Breitbart 711865f19a sanitize code extraction 2019-07-23 16:57:56 +02:00
Jörg Breitbart 50e5eb63df macos fix part4 2019-07-23 16:27:15 +02:00
Jörg Breitbart 2c3f9c9ca5 macos fix part3 2019-07-23 16:08:44 +02:00
Jörg Breitbart 10c61d47a2 macos fix part2 2019-07-23 16:03:15 +02:00
Jörg Breitbart 5b3d2fcef9 Merge branch 'mouse_report_tests' of github.com:jerch/xterm.js into mouse_report_tests 2019-07-23 15:52:08 +02:00
Jörg Breitbart 435cb3bd0a partial fix macos 2019-07-23 15:51:57 +02:00
Daniel Imms 62c25b0bba Fix all auto-fixable tslint issues 2019-07-22 14:08:34 -07:00
Daniel Imms d63985a50f Merge branch 'master' into mouse_report_tests 2019-07-22 14:06:59 -07:00
Daniel Imms 7db22c2408 Merge pull request #2329 from Tyriar/announce_input
Announce characters in screen readers when typing and using backspace
2019-07-22 12:40:50 -07:00
Jörg Breitbart bca69a75b4 fix report eval for buttons > 5 2019-07-22 20:18:06 +02:00
Daniel Imms 9e3ca6af18 Merge branch 'master' into announce_input 2019-07-22 10:52:29 -07:00
Daniel Imms ea019e8e66 Merge pull request #2328 from Tyriar/log_data_sent
Debug log data being sent
2019-07-22 10:49:47 -07:00
Daniel Imms c8a719b64a Clear textarea when ^C or enter is pressed 2019-07-22 10:49:40 -07:00
Daniel Imms d2a311b128 Debug log data being sent 2019-07-22 10:42:40 -07:00
Daniel Imms 6a68a24739 Debug log data being sent 2019-07-22 10:42:18 -07:00
Daniel Imms cabd0ca3bc Announce character when typing
Fixes #2327
2019-07-22 10:34:06 -07:00
Jörg Breitbart 3e5b075a0a remove modifier restriction for 1000 2019-07-22 16:32:24 +02:00
Jörg Breitbart 25ed7f7a7f added modifier tests 2019-07-22 15:22:14 +02:00
Logan Ramos ab9e92fcf1 Initial search tests 2019-07-19 17:45:39 -07:00
Jörg Breitbart 986bdac191 create wheel event remote 2019-07-20 00:45:12 +02:00
Jörg Breitbart 044476ae4f Merge branch 'master' into mouse_report_tests 2019-07-20 00:05:38 +02:00
Jörg Breitbart e5b28d4e72 Merge branch 'mouse_services' of github.com:jerch/xterm.js into mouse_services 2019-07-19 23:58:02 +02:00
Jörg Breitbart f239e10ed6 use enums instead 2019-07-19 23:55:18 +02:00
Daniel Imms 6465ab960e Merge branch 'master' into mouse_services 2019-07-19 12:08:10 -07:00
Daniel Imms 9a433e90e8 Merge pull request #2322 from elisescu/master
Add tty-share to the list of real world uses
2019-07-19 08:58:36 -07:00
Jörg Breitbart b64ed4f540 cleanup sendEvent, switch reported button during move 2019-07-19 17:04:12 +02:00
Jörg Breitbart cbddbc6e83 some changes in mouse event handling:
- use onProtocolChange
- remove mouse states from Terminal.ts
- remove selectionService from InputHandler
- fix up events in VT200 mode
- fix move event with no buttons in ANY mode
2019-07-19 16:21:30 +02:00
Jörg Breitbart df0cf253ac debounce only move events 2019-07-19 02:56:24 +02:00
Jörg Breitbart e38a68e396 debounce events at grid level 2019-07-19 02:46:03 +02:00
Jörg Breitbart 4858bdc464 CoreMouseService 2019-07-19 01:45:27 +02:00
Jörg Breitbart ee3cbae35a modifier test examples 2019-07-18 00:00:41 +02:00
Vasile Popescu 2b43731270 Add tty-share to the list of real world uses 2019-07-17 21:16:27 +02:00
Jörg Breitbart d4f65b7d0e remove copied over bug comments 2019-07-17 18:42:04 +02:00
Jörg Breitbart 27e8f7aa31 mixed col/row in report parser 2019-07-17 18:10:09 +02:00
Jörg Breitbart 4e56eed914 basic mousing tracking api tests 2019-07-17 18:07:44 +02:00
jerch d55fb1e922 Merge pull request #2316 from jerch/mouse_modes
Mouse modes test script
2019-07-16 22:38:12 +02:00
jerch 48109cac6b Merge branch 'master' into mouse_modes 2019-07-16 22:06:14 +02:00
Jörg Breitbart 78c1569a6e cleanup 2019-07-16 22:05:06 +02:00
Jörg Breitbart 5b52094aa2 respect protocol and modifiers 2019-07-14 23:58:07 +02:00
Daniel Imms 2b7be05da3 Move 3 render layers to browser 2019-07-14 12:36:37 -07:00
Daniel Imms 9830a077c1 Move BaseRenderLayer into browser 2019-07-14 12:22:11 -07:00
Daniel Imms cdefb3e7f2 Remove more terminal from render layers and cache 2019-07-14 12:07:43 -07:00
Daniel Imms 60ae9add3f Remove most terminal refs from BaseRenderLayer 2019-07-14 11:48:44 -07:00
Jörg Breitbart e5728ca78f test script for mouse modes 2019-07-14 20:34:51 +02:00
Daniel Imms a48260279c Fix import in webgl addon 2019-07-14 11:20:25 -07:00
Daniel Imms bd95c83ca2 Start using services in most render layers 2019-07-14 10:15:58 -07:00
Daniel Imms 868125f258 Don't pass terminal around within render layers
Will ease migration to services
2019-07-14 10:04:51 -07:00
Daniel Imms 60194179f8 Move CharAtlasCache to browser 2019-07-14 09:43:54 -07:00
Daniel Imms 64062d1a25 Move CharAtlasUtils into browser 2019-07-14 09:38:49 -07:00
Daniel Imms c0253c1093 Move DynamicCharAtlas to browser 2019-07-14 09:31:04 -07:00
Daniel Imms 58dbc98361 Move BaseCharAtlas to browser 2019-07-14 09:26:09 -07:00
Daniel Imms 4edae7c7ae Merge pull request #2314 from Tyriar/sec
Update some dev dependencies
2019-07-14 09:08:30 -07:00
Daniel Imms 8b3a649d65 Update express-ws, ts-loader and webpack 2019-07-14 09:02:29 -07:00
Daniel Imms 94b77aaf8c Update express
Fixes security issue in negotiator
2019-07-14 08:57:09 -07:00
Daniel Imms a94a361e1c Merge pull request #2311 from Tyriar/layering3
Move range updating to DirtyRowService and add dependency injection
2019-07-14 08:55:50 -07:00
Daniel Imms 2c50af356a Remove note in readme 2019-07-14 08:53:03 -07:00
Daniel Imms 5e0b1b251f Merge branch 'master' into layering3 2019-07-14 00:44:28 -07:00
Daniel Imms ff017f8960 Merge pull request #2313 from xtermjs/dependabot/npm_and_yarn/extend-3.0.2
Bump extend from 3.0.1 to 3.0.2
2019-07-14 00:41:56 -07:00
Daniel Imms 1df737c394 Fix decorator error 2019-07-14 00:41:37 -07:00
dependabot[bot] b97c704c21 Bump extend from 3.0.1 to 3.0.2
Bumps [extend](https://github.com/justmoon/node-extend) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/justmoon/node-extend/releases)
- [Changelog](https://github.com/justmoon/node-extend/blob/master/CHANGELOG.md)
- [Commits](https://github.com/justmoon/node-extend/compare/v3.0.1...v3.0.2)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 07:19:39 +00:00
Daniel Imms 05992e093b Merge branch 'master' into layering3 2019-07-14 00:17:48 -07:00
Daniel Imms 8deef83c60 Add tslint rule to prevent import from out
Fixes #1996
2019-07-14 00:16:20 -07:00
Daniel Imms fb6d4e2bfe Remove imports from out 2019-07-13 23:54:44 -07:00
Daniel Imms a0e2c9b270 Fix naming issue with serviceBrand 2019-07-13 23:45:25 -07:00
Daniel Imms 358a707835 Fix most lint and tests 2019-07-13 23:44:08 -07:00
Daniel Imms 9315b50897 Use createInstance on service hungry objects 2019-07-13 22:56:54 -07:00
Daniel Imms 88c88f1141 Adopt DI in browser services 2019-07-13 22:26:13 -07:00
Daniel Imms f4208d0389 Merge pull request #2312 from xtermjs/dependabot/npm_and_yarn/lodash-4.17.14
Bump lodash from 4.17.10 to 4.17.14
2019-07-13 22:20:15 -07:00
dependabot[bot] 283d1b1105 Bump lodash from 4.17.10 to 4.17.14
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.10 to 4.17.14.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.10...4.17.14)

Signed-off-by: dependabot[bot] <support@github.com>
2019-07-14 05:04:11 +00:00
Daniel Imms 5cc8ad802c Get type safety in DI, fix character joiner not using buffer service 2019-07-13 22:02:13 -07:00
Daniel Imms 8359605951 Add license and credit to VS Code 2019-07-13 19:54:01 -07:00
Daniel Imms 21fbe25858 Dependency Injection prototype 2019-07-13 19:50:16 -07:00
Daniel Imms c078f3db48 Move range updating to DirtyRowService 2019-07-13 18:25:22 -07:00
Daniel Imms 5709e5ff30 Merge pull request #2310 from Tyriar/layering2
Move MouseZoneManager and Viewport into browser
2019-07-13 18:13:13 -07:00
Daniel Imms 9aaaf6d8db Move Viewport to browser 2019-07-13 17:50:43 -07:00
Daniel Imms 8aa296933d Break Viewport's dependency on ITerminal 2019-07-13 17:49:44 -07:00
Daniel Imms 4dfe3a6079 Move MouseZoneManager to browser 2019-07-13 17:43:23 -07:00
Daniel Imms ca4e3d3fc4 Merge pull request #2309 from Tyriar/layering
Move several components to sub-projects
2019-07-13 17:40:19 -07:00
Daniel Imms 78f015308a Re-enable linkifier unicode tests in Terminal.test.ts 2019-07-13 17:28:09 -07:00
Daniel Imms 2eec18e7f5 Remove ITerminal from MouseZoneManager 2019-07-13 14:35:31 -07:00
Daniel Imms 0cd4093e53 Move Linkifier to browser 2019-07-13 14:15:28 -07:00
Daniel Imms f0a02e3188 Move linkifier types into browser 2019-07-13 13:53:16 -07:00
Daniel Imms 1ffa568a2f Remove ITerminal from Linkifier 2019-07-13 13:47:17 -07:00
Daniel Imms a696f4747a Move clipboard to browser 2019-07-13 13:18:44 -07:00
Daniel Imms 4d9d6fbd86 Merge pull request #2304 from Tyriar/inputhandler_bufferservice
Use IBufferService for buffer access in InputHandler
2019-07-13 11:09:04 -07:00
Daniel Imms 46002599d3 Prefix all logging with 'xterm.js'
This makes it easier to differentiate messages in large apps
2019-07-13 10:11:02 -07:00
Daniel Imms 0c038352f3 Remove debug internal option completely and add option APIs 2019-07-13 10:00:15 -07:00
Daniel Imms f314543135 Log bad linkifier instead of throwing 2019-07-13 09:48:16 -07:00
Daniel Imms cd01d8ad56 Lint 2019-07-13 09:47:11 -07:00
Daniel Imms 2977a53cc1 Use log service everywhere, fix log printing
Fixes #1560
2019-07-13 09:44:16 -07:00
Daniel Imms 94199ae124 Introduce logLevel option
Part of #1560
2019-07-13 09:36:21 -07:00
Daniel Imms af9c050e93 Remove ITerminal usage in DECRQSS 2019-07-13 01:46:01 -07:00
Daniel Imms 49fa86d6bb Get rows/cols in input hander from buffer service 2019-07-13 01:38:02 -07:00
Daniel Imms dd239b9811 Use IBufferService for buffer access in InputHandler 2019-07-13 00:52:54 -07:00
Daniel Imms 61b219ce22 Merge pull request #2303 from Tyriar/compositionhelper_browser
Move CompositionHelper into browser
2019-07-13 00:30:27 -07:00
Daniel Imms 27a946286a Make browser import absolute 2019-07-13 00:25:37 -07:00
Daniel Imms b929f82101 Move CompositionHelper into browser 2019-07-13 00:23:56 -07:00
Daniel Imms 4a442888ce Merge pull request #2288 from jerch/cleanup_sequences_files
fix edge cases in inputhandler methods
2019-07-11 15:37:42 -07:00
Daniel Imms b658f7ba44 Merge branch 'master' into cleanup_sequences_files 2019-07-11 15:25:17 -07:00
Daniel Imms e99de7a910 Merge pull request #2302 from Tyriar/2301_mouse_events
Don't trigger selection when mouse events are on
2019-07-11 11:12:21 -07:00
Daniel Imms 7a37bd880e Add test for mouse events 2019-07-11 11:07:03 -07:00
Daniel Imms da9b4b1a69 Don't trigger selection when mouse events are on
Fixes #2301
2019-07-11 09:34:45 -07:00
Jörg Breitbart eb707bb1d7 better typing in test file 2019-07-11 02:41:20 +02:00
Jörg Breitbart 6ec093a717 Merge branch 'cleanup_sequences_files' of github.com:jerch/xterm.js into cleanup_sequences_files 2019-07-10 23:39:20 +02:00
Jörg Breitbart 24b26c7311 force closing of pty 2019-07-10 23:39:05 +02:00
Daniel Imms c2a4ff1c72 Merge branch 'master' into cleanup_sequences_files 2019-07-10 11:57:33 -07:00
Daniel Imms a9961c867d Merge pull request #2297 from qwefgh90/master
Add NgTerminal to the users list
2019-07-10 11:48:51 -07:00
Daniel Imms a32c46758f Improve grammar 2019-07-10 11:48:30 -07:00
Jörg Breitbart cc3bb83ced getting rid of native access in test file 2019-07-10 14:57:49 +02:00
Changwon Choe 6f58572d1f Add NgTerminal to the users list 2019-07-10 12:48:18 +09:00
Jörg Breitbart ab25997192 change to max/min 2019-07-09 22:30:00 +02:00
Jörg Breitbart 9d2418ece6 remove comment 2019-07-09 21:41:17 +02:00
Jörg Breitbart d8650ad722 Merge branch 'master' into cleanup_sequences_files 2019-07-09 00:44:12 +02:00
Daniel Imms 44a843bbe6 Merge pull request #2294 from Tyriar/fix_keyup
Don't handle keyup that is handled by custom handler
2019-07-08 15:36:54 -07:00
Daniel Imms bf35ee8016 Fix lint 2019-07-08 15:29:09 -07:00
Daniel Imms cf3cf38e60 Don't handle keyup that is handled by custom handler
Fixes #2293
2019-07-08 15:25:30 -07:00
Jörg Breitbart 691a8addfc cleanup; doc; move cursor methods next to each other 2019-07-08 23:59:46 +02:00
Jörg Breitbart 3d6f87ea7f reset cursor on DECOM 2019-07-08 23:22:46 +02:00
Jörg Breitbart e91c223bb0 respect DECSTBM margins in DECOM mode 2019-07-08 23:09:53 +02:00
Jörg Breitbart cb25e2d4e0 save/restore charset in DECSC/DECRC 2019-07-08 02:42:02 +02:00
Jörg Breitbart bc867bf12b partial fix DECSTBM IL/DL 2019-07-08 02:11:46 +02:00
Jörg Breitbart 5122fdc441 document wonky usage of Terminal.reset 2019-07-08 00:55:26 +02:00
Jörg Breitbart 8654133b15 move leftover sequence methods to InputHandler 2019-07-08 00:39:05 +02:00
Jörg Breitbart 41cc99a919 DECSTBM SU/SD 2019-07-08 00:19:21 +02:00
Jörg Breitbart e2366fa83d rewrite DECSTBM 2019-07-07 23:37:02 +02:00
Jörg Breitbart 46f89cd4ff fix NPE 2019-07-07 22:22:19 +02:00
Jörg Breitbart ef58f1fef8 add vttest wrapping testfile 2019-07-07 22:19:45 +02:00
Jörg Breitbart 9d4cafc4c9 fix ICH 2019-07-07 21:18:03 +02:00
Jörg Breitbart 7e7730d176 fix ECH 2019-07-07 21:15:14 +02:00
Jörg Breitbart 926c298371 fix DCH 2019-07-07 21:10:38 +02:00
Jörg Breitbart 9a64c549f8 fix ED3 test 2019-07-07 20:54:12 +02:00
Jörg Breitbart d26a643727 use fill for _resetBufferLine 2019-07-07 20:45:54 +02:00
Jörg Breitbart cd1d194dbd apply cursor restrictions 2019-07-07 20:40:27 +02:00
Jörg Breitbart 204847b134 fix DECSC 2019-07-07 19:54:47 +02:00
Jörg Breitbart fe59e632a9 Merge branch 'cleanup_sequences_files' of github.com:jerch/xterm.js into cleanup_sequences_files 2019-07-06 20:46:30 +02:00
Jörg Breitbart e6ac138620 Merge branch 'master' into cleanup_sequences_files 2019-07-06 20:45:50 +02:00
jerch 68694dab9d Merge pull request #2241 from jerch/parser_colon_notation
colon notation for the parser
2019-07-06 20:04:00 +02:00
Daniel Imms 6665a06b01 Merge branch 'master' into cleanup_sequences_files 2019-07-06 10:22:20 -07:00
jerch be6226785f Merge branch 'master' into parser_colon_notation 2019-07-06 18:22:43 +02:00
Jörg Breitbart 6d22772d16 fix REP to be in line with vttest 2019-07-06 18:09:38 +02:00
Jörg Breitbart fa9857aedf simplify cursor movements 2019-07-06 16:47:48 +02:00
Jörg Breitbart a2bf5fe975 fix typo 2019-07-06 16:13:21 +02:00
Jörg Breitbart eb7b8f9020 restrict cursor movements 2019-07-06 15:59:18 +02:00
Jörg Breitbart d18b799624 fix HT, HTS, CHT 2019-07-05 02:04:42 +02:00
Jörg Breitbart 44035d14ab fix no wraparound mode 2019-07-05 00:56:57 +02:00
Jörg Breitbart 82ff113107 add DECALN 2019-07-04 23:50:56 +02:00
Daniel Imms f889796852 Merge pull request #2289 from Tyriar/sound_browser
Move sound into browser
2019-07-04 14:09:40 -07:00
Daniel Imms 49b5eda160 Merge branch 'master' into sound_browser 2019-07-04 13:14:01 -07:00
Daniel Imms 47164d2f68 Move sound into browser 2019-07-04 12:31:21 -07:00
Daniel Imms fb6ec7ffb8 Merge pull request #2287 from Tyriar/webgl_simplify_atlas
Enable strict mode in webgl addon
2019-07-04 09:21:44 -07:00
Daniel Imms bc07225394 Enable strict mode in webgl addon
Fixes #2286
2019-07-04 09:08:56 -07:00
Daniel Imms 40bc62c383 Enable strict null checks in webgl addon
Part of #2286
2019-07-04 08:58:42 -07:00
Daniel Imms ff82d35a3d Merge pull request #2285 from Tyriar/webgl_simplify_atlas
Simplify webgl atlas and ensure it exists in GlyphRenderer to prevent NPE
2019-07-04 08:49:39 -07:00
Jörg Breitbart d858022f23 fix several escape sequence files 2019-07-04 17:45:10 +02:00
Daniel Imms 0898de147f Ensure GlyphRenderer._atlas exists on beginFrame
This should fix an exception breaking it in vscode
2019-07-04 08:36:44 -07:00
Daniel Imms 38f2e7a81d Simplify webgl atlas by removing BaseCharAtlas 2019-07-04 08:28:21 -07:00
Jörg Breitbart 5f8d07ac62 cleanup Types.ts, docs for ZDM 2019-07-04 13:50:03 +02:00
Jörg Breitbart 6a691f2548 fix parser docs 2019-07-04 13:01:18 +02:00
Jörg Breitbart 7bd0325128 remove example snippet from docs 2019-07-04 12:42:43 +02:00
Jörg Breitbart 009b3c6ef8 simply error parsing state 2019-07-04 12:38:14 +02:00
Jörg Breitbart 75d41abf33 re-enable commented out tests 2019-07-04 12:37:32 +02:00
Jörg Breitbart 6bcd8e3bfd ParamsArray to Types.ts 2019-07-04 12:12:11 +02:00
Daniel Imms 69dcabbfce Merge branch 'master' into parser_colon_notation 2019-07-03 16:58:37 -07:00
Daniel Imms f235d70f30 Merge pull request #2284 from Tyriar/blank_line
Remove blankLine localized string
2019-07-03 10:42:35 -07:00
Daniel Imms 048e95e34b Remove blankLine localized string
Using a nbsp is more correct and lets the screen reader handle how it wants

Fixes #2260
2019-07-03 10:23:53 -07:00
Daniel Imms c55e938ce9 Merge pull request #2283 from lramos15/lramos15/select-fix
Double wide characters could have halves selected
2019-07-03 08:48:11 -07:00
Logan Ramos 2a405d5f97 Fix scroll bar logic 2019-07-03 08:37:59 -07:00
Daniel Imms 1bab14aef6 Merge pull request #2281 from lramos15/lramos15/centered-scroll
Centers search scroll in viewport
2019-07-02 16:03:21 -07:00
Logan Ramos 345bf11389 Remove extra import 2019-07-02 15:57:23 -07:00
Logan Ramos 60c2248cb4 Centers scroll in viewport 2019-07-02 15:09:30 -07:00
Jörg Breitbart 17ca958542 js array integration test for addCsiHandler 2019-07-02 22:38:20 +02:00
Jörg Breitbart 65b757bc19 fix typos in docs 2019-07-02 22:04:12 +02:00
Jörg Breitbart f276150ce4 remove IParams from public API 2019-07-02 20:41:21 +02:00
Jörg Breitbart 357faa71df value range restrictions: clamp max, reject < -1 2019-07-02 18:27:13 +02:00
Jörg Breitbart a1acd4b318 Merge branch 'master' into parser_colon_notation 2019-07-02 16:44:43 +02:00
Jörg Breitbart 7dd5dfab7a make params mandatory 2019-07-02 16:14:28 +02:00
Jörg Breitbart 5827b4b0d1 change to int32_t 2019-07-02 15:18:39 +02:00
Daniel Imms d691327cb5 Merge pull request #2279 from Tyriar/selection_manager_browser
Make SelectionManager a service and move into browser
2019-06-30 10:21:36 -07:00
Daniel Imms 47b6756ead isMSWindows -> isWindows 2019-06-29 18:57:59 -07:00
Daniel Imms 79d8f05528 Make Terminal.selectionService private 2019-06-29 18:50:54 -07:00
Daniel Imms 3806f67fc0 Move SelectionService into browser (+strict) 2019-06-29 18:41:48 -07:00
Daniel Imms 48f68a7702 Add used members from SelectionService to interface 2019-06-29 14:34:48 -07:00
Daniel Imms 7ee2219314 Rename SelectionManager to SelectionService 2019-06-29 14:27:50 -07:00
Daniel Imms 4d22d1d008 Reset modes on reset 2019-06-29 14:15:04 -07:00
Daniel Imms a706dd9de9 Merge branch 'master' into selection_manager_browser 2019-06-29 14:09:54 -07:00
Daniel Imms b4ae5e1aff Merge branch 'master' into parser_colon_notation 2019-06-29 13:54:02 -07:00
Daniel Imms 73be720ecc Merge pull request #2277 from Tyriar/guard
Guard integer only APIs when floats are used
2019-06-29 13:52:21 -07:00
Daniel Imms a61fbf7a51 Merge pull request #2278 from MaxRis/to-master/reset-wrapped-line-flag
Reset isWrapped line flag.
2019-06-29 08:38:57 -07:00
Max Risuhin f9e8334141 Reset isWrapped line flag. 2019-06-29 16:02:15 +03:00
Daniel Imms b4886df796 Guard integer only APIs when floats are used
Fixes #2261
2019-06-28 16:42:42 -07:00
Daniel Imms 6fb7a06f19 Merge pull request #2276 from Tyriar/2275_lower_zIndex
Lower z-indexes
2019-06-28 12:52:56 -07:00
Daniel Imms d8099f7fe9 Lower z-indexes
Canvas layers: 0-4
Helpers: 5
A11y tree: 10

Fixes #2275
2019-06-28 12:46:57 -07:00
Daniel Imms f9eeea5917 Merge pull request #2274 from Tyriar/out-test
Git ignore out-test
2019-06-27 18:44:59 -07:00
Daniel Imms 7e09ac7f04 Merge pull request #2273 from Tyriar/tslint_celan
Enforce underscore prefix for protected members
2019-06-27 18:44:41 -07:00
Daniel Imms 788ab83ac1 Merge branch 'master' into tslint_celan 2019-06-27 18:37:43 -07:00
Daniel Imms 10fedf4ccf Enforce underscore prefix for protected members 2019-06-27 18:36:44 -07:00
Daniel Imms 8cf5a7ee40 Git ignore out-test 2019-06-27 18:26:02 -07:00
Daniel Imms 48b915459a Merge pull request #2269 from Tyriar/d_map
Use TS declarationMap
2019-06-27 11:46:45 -07:00
Daniel Imms 7f4e1a7e97 Add explicit blacklist entry for .d.ts.map 2019-06-27 11:40:39 -07:00
Daniel Imms c107f3c5f7 Merge branch 'master' into d_map 2019-06-27 11:32:13 -07:00
Daniel Imms a96734220a Use TS declarationMap
This will make go to definition go to the implementation instead of
the .d.ts file
2019-06-27 11:31:36 -07:00
Daniel Imms 73521390d2 Merge pull request #2268 from termius/include-css
Include CSS into the package
2019-06-27 07:57:03 -07:00
Vadim Zakondyrin 6c8f88754b Include CSS into the package 2019-06-27 10:21:58 +06:00
Jörg Breitbart 63a4e8ffde Merge branch 'master' into parser_colon_notation 2019-06-25 16:07:50 +02:00
Daniel Imms c50a6ef415 Merge pull request #2262 from Tyriar/word_sep
Add wordSeparator to demo
2019-06-24 20:27:45 -07:00
Daniel Imms b138d6574e Merge branch 'master' into word_sep 2019-06-24 20:27:39 -07:00
Daniel Imms 5459c48525 Add wordSeparator to demo 2019-06-24 20:20:08 -07:00
Daniel Imms 6b036e1222 Merge pull request #2190 from jerch/benchmark_integration
inital integration of xterm-benchmark
2019-06-24 19:50:58 -07:00
Jörg Breitbart 00d4c8162d remove azure job, change api test path 2019-06-24 22:53:13 +02:00
Jörg Breitbart b6b810b625 Merge branch 'benchmark_integration' of github.com:jerch/xterm.js into benchmark_integration 2019-06-24 22:47:37 +02:00
Jörg Breitbart 901b995a21 Merge branch 'master' into benchmark_integration 2019-06-24 22:47:20 +02:00
Daniel Imms 88308f058c Remove ITerminal dependency in SelectionManager 2019-06-23 14:29:59 -07:00
Daniel Imms 4ecd0d2053 Merge branch 'master' into selection_manager_browser 2019-06-23 14:28:12 -07:00
Daniel Imms 479010d29e Merge pull request #2256 from Tyriar/tests
Fix composition tests
2019-06-23 14:27:42 -07:00
Daniel Imms 83b8e1bd30 Fix composition tests 2019-06-23 14:21:05 -07:00
Daniel Imms 33a640a7a8 Move applicationCursor into core service 2019-06-23 14:06:06 -07:00
Daniel Imms 99a31b3862 Merge pull request #1790 from Tyriar/webgl2
WebGL Renderer
2019-06-23 13:28:35 -07:00
Daniel Imms 533f3bd0dc Remove unneeded TODOs 2019-06-23 13:12:49 -07:00
Daniel Imms fdae27e7ea Remove unused Platform.ts in webgl 2019-06-23 13:11:25 -07:00
Daniel Imms e10adaf3d2 Have yarn clean also delete addon out/ 2019-06-23 13:10:37 -07:00
Daniel Imms fb420d70e4 Merge branch 'master' into webgl2 2019-06-23 13:01:42 -07:00
Daniel Imms f4f1e0276e Merge pull request #2247 from Tyriar/core_service
Move handler into CoreService and adopt
2019-06-23 13:01:27 -07:00
Daniel Imms 910ece4f09 Merge branch 'master' into benchmark_integration 2019-06-23 10:26:33 -07:00
Daniel Imms bfa7a2df76 Move handler into CoreService and adopt
This also fine tunes some of the data events to not clear selection
and scroll to the bottom of the viewport anymore.

Part of #1507
Fixes #2112
2019-06-23 10:10:17 -07:00
Daniel Imms 94a2ad9416 Merge pull request #2246 from Tyriar/alt_click_functional
Change alt click to functional and move into browser
2019-06-22 19:37:00 -07:00
Daniel Imms 87897a7ee5 Move selection manager types into browser 2019-06-22 18:27:25 -07:00
Daniel Imms f903dbde45 Add some tests for MoveToCell 2019-06-22 18:16:33 -07:00
Daniel Imms 22a7e48f04 Move alt click into browser 2019-06-22 18:00:03 -07:00
Daniel Imms 13a63efdab Change AltClickHandler to be functional 2019-06-22 17:55:59 -07:00
Daniel Imms 7454701c0b Remove AltHandler member usage 2019-06-22 17:53:11 -07:00
Daniel Imms da1484ac47 Return a sequence from AltClickHandler 2019-06-22 09:44:25 -07:00
Daniel Imms 00969508d9 Remove some private member deps in AltClickHandler 2019-06-22 09:40:11 -07:00
Daniel Imms 731070fdc2 Merge pull request #2245 from Tyriar/clipboard_term_dep
Remove some terminal dependencies in Clipboard and SelectionManager
2019-06-21 20:39:06 -07:00
Daniel Imms 9174f60d94 Move screen element into ctor 2019-06-21 20:20:48 -07:00
Daniel Imms 0ba90a9349 Adopt options service in selection manager 2019-06-21 20:12:17 -07:00
Daniel Imms 72f615da14 Remove some of terminal dependency in SelectionManager 2019-06-21 20:08:58 -07:00
Daniel Imms 0bb2b3446d Merge branch 'master' into clipboard_term_dep 2019-06-21 20:02:07 -07:00
Daniel Imms 62e2b00bd5 Remove terminal dep in clipboard 2019-06-21 19:54:11 -07:00
Daniel Imms b7dba18847 Merge branch 'master' into webgl2 2019-06-21 19:38:44 -07:00
Daniel Imms 60eb13e223 Merge pull request #2244 from MaxRis/word-separator-option
Define wordSeparator option
2019-06-21 11:53:36 -07:00
Max Risuhin 1b2811075c Define wordSeparator option 2019-06-21 16:35:26 +03:00
Daniel Imms 96eafd32db Merge pull request #2242 from VivaLosDoyers/readme_typo_fix
Fix a typo in the README
2019-06-18 19:13:21 -07:00
Jörg Breitbart 1dc4e36972 fix CSI bug, cleanup test 2019-06-19 00:42:20 +02:00
Michael Miller a0ccc9b78b Fix a type in the README
"Perfomant" should be "Performant"
2019-06-18 15:28:41 -07:00
Jörg Breitbart a28761bf3e restructured test folder 2019-06-19 00:07:09 +02:00
Jörg Breitbart 8ce67cb880 add COLORTERM to env in demo 2019-06-18 18:55:24 +02:00
Jörg Breitbart c80ff1e1d1 cleanup interface 2019-06-18 15:37:53 +02:00
Jörg Breitbart fc778c76c2 add usage example for action handler 2019-06-18 15:23:36 +02:00
Jörg Breitbart f984204570 parser tests 2019-06-18 14:56:32 +02:00
Jörg Breitbart 069e51064a remove as number[] type conversions from tests 2019-06-18 14:47:35 +02:00
Jörg Breitbart 6f047aa7ea SGR tests, fix bug in 38:5 handling 2019-06-18 14:40:15 +02:00
Jörg Breitbart e8290af194 Merge branch 'master' into benchmark_integration 2019-06-18 03:08:07 +02:00
Jörg Breitbart c558d485e0 apply colon handling to SGR 2019-06-18 03:00:53 +02:00
Jörg Breitbart 62007c3be4 comment storable amount of params in parser 2019-06-17 23:42:56 +02:00
Jörg Breitbart 1dd63a6d66 apply type over codebase 2019-06-17 23:31:54 +02:00
Daniel Imms 5321f0373f Fix quote and comma 2019-06-17 13:42:44 -07:00
Jörg Breitbart c5385a640d add ":" to param transitions, fix parse loop and tests 2019-06-17 21:54:51 +02:00
Jörg Breitbart cec1aa3f33 interfaces, add test for clone 2019-06-17 21:17:56 +02:00
Jörg Breitbart 24c39f664d remove unused import 2019-06-17 20:55:29 +02:00
Jörg Breitbart 383849b36f Params type implementation 2019-06-17 20:49:12 +02:00
Daniel Imms 1b7862ce8a Move slice typed array util into webgl addon 2019-06-17 07:35:52 -07:00
Daniel Imms 5100c7a30d Use Constants from core 2019-06-16 00:17:14 -07:00
Daniel Imms bc24a6cdd1 Merge branch 'master' into webgl2 2019-06-16 00:13:15 -07:00
Daniel Imms 795ca2af2e Merge pull request #2239 from Tyriar/charjoiner_layer
Move some parts of renderer to browser
2019-06-16 00:12:55 -07:00
Daniel Imms de86d140c5 Fix absolute imports 2019-06-16 00:02:10 -07:00
Daniel Imms a6f4931810 Move DomRendererRowFactory to browser 2019-06-15 23:59:32 -07:00
Daniel Imms c4f903e283 Move atlas/Constants to browser 2019-06-15 23:53:45 -07:00
Daniel Imms c0e27b98e8 Move LRUMap to browser 2019-06-15 23:51:36 -07:00
Daniel Imms b5093e0c29 Move GridCache to browser 2019-06-15 23:47:35 -07:00
Daniel Imms e35d911fd1 Move char joiner registry to browser layer 2019-06-15 23:45:03 -07:00
Daniel Imms 308cf8247a Remove terminal dep in char joiner registry 2019-06-15 23:40:31 -07:00
Daniel Imms d4e50293a1 Merge pull request #2238 from Tyriar/selection_layering
Move SelectionModel to browser
2019-06-15 23:34:39 -07:00
Daniel Imms 6e90b7371b Move SelectionModel to browser, fix strict 2019-06-15 23:28:51 -07:00
Daniel Imms 9980457eef Remove terminal dep from SelectionModel 2019-06-15 23:10:25 -07:00
Daniel Imms b1004f2007 Merge branch 'master' into benchmark_integration 2019-06-15 22:47:33 -07:00
Daniel Imms 26c854db49 Merge pull request #2237 from Tyriar/mouse_service
Introduce mouse service
2019-06-15 21:07:44 -07:00
Daniel Imms 702ecb185f Merge branch 'master' into mouse_service 2019-06-15 19:42:24 -07:00
Daniel Imms 8a59389358 Merge pull request #2236 from Tyriar/fix_broken_tests
Fix restore cursor related tests
2019-06-15 19:41:45 -07:00
Daniel Imms a4d18a3b23 Introduce mouse service 2019-06-15 19:40:51 -07:00
Daniel Imms 9bb16e4b16 Fix restore cursor related tests
Weird failure happening sometimes after #2217, not sure why pipelines
didn't pick it up.
2019-06-15 19:24:14 -07:00
Daniel Imms 8b4901e8f3 Reduce diff 2019-06-15 16:43:01 -07:00
Daniel Imms 7148358acf Prevent crash on true color, add TODOs for it 2019-06-15 16:40:45 -07:00
Daniel Imms 1ebae41a8b Pull attribute compat stuff into addon 2019-06-15 16:35:38 -07:00
Daniel Imms 45ec3b1e57 Merge branch 'master' into webgl2 2019-06-15 14:50:23 -07:00
Daniel Imms 20809a042f Merge pull request #2235 from Tyriar/webgl_prep
Pulling unrelated changes in from WebGL PR
2019-06-15 14:49:42 -07:00
Daniel Imms 6e04058783 Reduce diff 2019-06-15 14:47:44 -07:00
Daniel Imms 29db1a2b2b Refresh viewport after setting renderer and set correct end refresh row 2019-06-15 14:44:05 -07:00
Daniel Imms ed9000cb1d Clarify ITheme.selection color 2019-06-15 14:42:30 -07:00
Daniel Imms 2bd043b664 Remove FLAGS constant
Only WebGL uses this
2019-06-15 14:42:04 -07:00
Daniel Imms 04ba3510e4 Adopt automated released in webgl addon 2019-06-15 14:37:44 -07:00
Daniel Imms 05188a985c Merge branch 'master' into webgl2 2019-06-15 14:37:04 -07:00
Daniel Imms 49ba3c8068 Merge pull request #2234 from Tyriar/trigger_build
npmignore webpack.config.js (test automated release)
2019-06-15 14:30:21 -07:00
Daniel Imms a46c723020 npmignore webpack.config.js (test automated release)
Part of #2165
2019-06-15 14:29:41 -07:00
Daniel Imms c68f413c48 Merge pull request #2233 from Tyriar/publish_improvements_2
Publish addons with right cwd and don't exit
2019-06-15 14:27:43 -07:00
Daniel Imms 91c4ca5e0d Publish addons with right cwd and don't exit
Part of #2165
2019-06-15 14:27:04 -07:00
Daniel Imms 8de555d7d9 Merge pull request #2232 from Tyriar/publish_improvements
Add publish dry run feature and automate addon released based on changed files
2019-06-15 14:16:38 -07:00
Daniel Imms d06fd04465 Move addon const under addon comment 2019-06-15 14:10:48 -07:00
Daniel Imms 64403f2dca Publish addons and xterm based on whether files changed
Fixes #2165
2019-06-15 14:06:45 -07:00
Daniel Imms 15c99869f5 Start of publishing addons
Part of #2165
2019-06-15 13:51:13 -07:00
Daniel Imms 2e83483e08 Support dry run publishing using --dry 2019-06-15 13:42:52 -07:00
Daniel Imms 846a1897e9 Merge pull request #2217 from termius/fix-cursor
Fix saved cursor position on resize of alt screen
2019-06-15 13:22:19 -07:00
Daniel Imms 699e721c45 Add a test for DECRC 2019-06-15 13:17:43 -07:00
Daniel Imms 173c4d83b3 Merge branch 'master' into fix-cursor 2019-06-15 13:04:28 -07:00
Daniel Imms 07b6b69be7 Remove old comment 2019-06-15 00:30:45 -07:00
Daniel Imms 15647a0301 Speed up webgl tests 2019-06-15 00:27:12 -07:00
Daniel Imms dd9b755329 Fix webgl api tests 2019-06-15 00:17:48 -07:00
Daniel Imms 765297e67c Add addon typings 2019-06-15 00:11:34 -07:00
Daniel Imms d272422c0b Fix webgl addon version 2019-06-15 00:06:04 -07:00
Daniel Imms eae0ab9e02 Add a webgl button to the demo 2019-06-15 00:04:02 -07:00
Daniel Imms 50d6711fc8 Fix webgl packaging 2019-06-15 00:01:00 -07:00
Daniel Imms d7daa53b50 Move webgl renderer into addon dir 2019-06-14 23:55:17 -07:00
Daniel Imms 535c8a5d4b Merge branch 'master' into webgl2 2019-06-14 23:20:03 -07:00
Daniel Imms 27d724a13a Merge pull request #2231 from Tyriar/refactor_buffer_line
Pull types and classes out of BufferLine
2019-06-14 23:15:08 -07:00
Daniel Imms 91598814c6 Fix lint 2019-06-14 23:00:48 -07:00
Daniel Imms ae216c3088 Move AttributeData into separate file 2019-06-14 23:00:33 -07:00
Daniel Imms 45682f0e76 Move Content to Constants 2019-06-14 22:55:06 -07:00
Daniel Imms 4330741c5d Move CellData into new file 2019-06-14 22:51:08 -07:00
Daniel Imms 3adddbf95a Move some buffer constants into buffer/Constants 2019-06-14 22:39:35 -07:00
Daniel Imms b7cdbb99ca Remove default exports in webgl char atlas files 2019-06-14 22:27:07 -07:00
Daniel Imms ddb9fbd1d6 Improve type safety in webgl 2019-06-14 22:25:43 -07:00
Daniel Imms 3a7aa77950 Remove remaining parts of renderer API, fix webgl tests 2019-06-14 22:18:53 -07:00
Daniel Imms 6c232a0e11 Remove renderer API 2019-06-14 22:03:55 -07:00
Daniel Imms 6ff90451ff Merge branch 'master' into webgl2 2019-06-14 21:52:46 -07:00
Daniel Imms d2f800f6a9 Merge pull request #2229 from Tyriar/types_constants
Split Types.ts into Types.d.ts and Constants.ts
2019-06-14 21:46:59 -07:00
Daniel Imms 7b6dd9fe9d Rename browser Types.ts to .d.ts 2019-06-14 21:39:22 -07:00
Daniel Imms 913faef3b8 Split src/ Types.ts into d.ts and Constants 2019-06-14 21:38:19 -07:00
Daniel Imms 0b2df9d611 Split common/ Types.ts into .d.ts and Constants.ts 2019-06-14 21:30:51 -07:00
Daniel Imms 6e9c7888d2 Merge pull request #2228 from Tyriar/fix_dpr_change
Fix screen dpr change not refreshing canvas renderer
2019-06-14 21:08:11 -07:00
Daniel Imms 332cc3901d Merge pull request #2222 from Tyriar/2220_setTheme
Fix NPE in _setTheme
2019-06-14 20:57:33 -07:00
Daniel Imms c94183a5a1 Merge branch 'master' into fix_dpr_change 2019-06-14 20:56:51 -07:00
Daniel Imms 4daf67245d Merge branch 'master' into webgl2 2019-06-14 20:56:27 -07:00
Daniel Imms 2584de8630 Clear webgl model after theme or dpr change 2019-06-14 20:55:52 -07:00
Daniel Imms 4b4b58e662 Fix screen dpr change not refreshing canvas renderer 2019-06-14 20:38:35 -07:00
Daniel Imms e53cae8c69 Fix screen dpr change not refreshing canvas renderer 2019-06-14 20:37:58 -07:00
Daniel Imms e959cce899 Remove webgl LRUMap 2019-06-14 19:35:05 -07:00
Daniel Imms 21d07d1f0e Remove unused portion of CharAtlasGenerator 2019-06-14 19:34:31 -07:00
Daniel Imms d4169f3538 Fix tests 2019-06-14 19:31:42 -07:00
Daniel Imms a19ea1ec52 Remove forked LifeCycle and TypedArray files 2019-06-14 15:46:07 -07:00
Daniel Imms cdc9f792a5 Merge pull request #2227 from Tyriar/2224_dom_cursor
Show text when cursor blinks in DOM renderer
2019-06-14 12:57:11 -07:00
Daniel Imms 1a44e3634a Show text when cursor blinks in DOM renderer
Fixes #2224
2019-06-14 12:39:01 -07:00
Daniel Imms a5e466869c Fix lint 2019-06-13 09:51:22 -07:00
Daniel Imms 57eaa24ea0 Fix NPE in _setTheme
Fixes #2220
2019-06-13 08:51:42 -07:00
Daniel Imms ee81f50f3a Fix conflicts 2019-06-12 18:25:05 -07:00
Daniel Imms 7c6db2ef5b Merge branch 'master' into webgl2 2019-06-12 18:20:39 -07:00
Daniel Imms 26f967ec3f Merge pull request #2221 from blink1073/style-field
Add a style field to package.json
2019-06-12 14:04:48 -07:00
Steven Silvester d2c32c6f2d declare style field 2019-06-12 04:45:11 -05:00
Daniel Imms 68db0661fc Merge pull request #2219 from Tyriar/addon_webpack
Webpack addons
2019-06-10 15:14:54 -07:00
Daniel Imms c4311cb88a Merge pull request #2216 from Tyriar/drop_ie_support
Partially support IE11
2019-06-10 15:14:38 -07:00
Daniel Imms 3e91f08e34 Bump addon versions 2019-06-10 14:51:09 -07:00
Daniel Imms d9ce9e96f5 Remove packageAddons step on install
It's not needed when the demo doesn't use it
2019-06-10 14:47:10 -07:00
Daniel Imms b657a1f30e Use addon tsc output in the demo, similar to the core lib 2019-06-10 14:41:43 -07:00
Daniel Imms 989610e8c3 Webpack the addons 2019-06-10 14:28:07 -07:00
Vadim Zakondyrin 311f6b6e84 Fix saved cursor position on resize of alt screen 2019-06-10 14:27:48 +06:00
Daniel Imms 044a7e327f Clarify partial support 2019-06-09 19:35:47 -07:00
Daniel Imms f9b92f8865 Add note about partial support for IE11 2019-06-09 16:19:03 -07:00
Daniel Imms 1bbb51fc17 Fix compile 2019-06-09 15:57:24 -07:00
Daniel Imms 02868c1033 Remove support for IE11
Fixes #1889
2019-06-09 15:52:37 -07:00
Jörg Breitbart 5f8b7cda04 Merge branch 'master' into benchmark_integration 2019-06-09 23:09:57 +02:00
Jörg Breitbart e77969372b setup benchmark pipeline with eval run 2019-06-09 23:00:11 +02:00
Daniel Imms 566f5944dd Merge pull request #2214 from Tyriar/strings_browser
Move Strings to browser
2019-06-09 13:33:25 -07:00
Jörg Breitbart b559a5a39b lower resources needed for test 2019-06-09 22:23:15 +02:00
Jörg Breitbart 1794532cb1 test pipeline 2019-06-09 22:08:41 +02:00
Jörg Breitbart e0d69db23e better separation of benchmarks 2019-06-09 21:53:24 +02:00
Daniel Imms 46ce3d29c3 API polish/grammar/wrapping 2019-06-09 12:07:27 -07:00
Daniel Imms 39cff978df Add missing docs to xterm.d.ts
Fixes #2215
2019-06-09 12:03:00 -07:00
Daniel Imms f59b3f000d Move Strings to browser 2019-06-09 11:46:20 -07:00
Jörg Breitbart 03839f06b8 remove remnants 2019-06-09 18:02:17 +02:00
Jörg Breitbart fc7411c807 remove wrong d.ts 2019-06-09 17:35:25 +02:00
Jörg Breitbart e920f1db86 cleaner approach 2019-06-09 17:31:57 +02:00
Jörg Breitbart 3204d9d7c9 fix benchmark script 2019-06-09 15:19:48 +02:00
Jörg Breitbart 674914bbb7 moving benchmarks out of './src':
Harder than I thought for several reasons:
- need access to common to tests the subparts, thus the unified tsconfig
  in tests does not work (need the path translation to those parts)
- moving next to src I cannot use direct imports anymore (source files
  are out of rootDir), thus have to rely on d.ts files in out which is
  quite suboptimal as many parts do not expose the declaration files
  (can only type Terminal as any atm)
- compiler output has to resemble the '../out/..' import logic of the TS
  files or require fails, thus moved the ouput to './benchmark' for now

Conclusion: Not yet there, maybe not a good idea at all to move those
tests out of './src' as they heavily rely on not exported internals.
Needs more fiddling with the repo structure.
2019-06-09 14:51:44 +02:00
Jörg Breitbart 1b31c01b75 Merge branch 'master' into benchmark_integration 2019-06-09 12:37:06 +02:00
Daniel Imms 16217003aa Merge pull request #2211 from Tyriar/remove_ee
Remove old event emitter, rename new one to EventEmitter
2019-06-08 21:55:57 -07:00
Daniel Imms 07cef1ec9e Increase attach addon timeouts 2019-06-08 21:51:24 -07:00
Daniel Imms 73a08f7850 Consolidate service init 2019-06-08 21:46:13 -07:00
Daniel Imms 5aeb70bea4 Merge branch 'master' into remove_ee 2019-06-08 21:45:30 -07:00
Daniel Imms 58ec3f9973 Merge pull request #2210 from Tyriar/buffer_owner
Move buffer ownership to IBufferService
2019-06-08 21:43:32 -07:00
Daniel Imms 1b07a03b2f Properly reset buffer after Terminal.reset 2019-06-08 21:39:10 -07:00
Daniel Imms 80ce33f9ef Rename EventEmitter2 to EventEmitter
Fixes #2029
2019-06-08 21:33:02 -07:00
Daniel Imms 447fc4f3fa Remove old event emitter
Fixes #2029
2019-06-08 21:30:31 -07:00
Daniel Imms f49daf02a3 Fix tests and imports 2019-06-08 20:52:37 -07:00
Daniel Imms 09b0bbed32 Move buffer/buffers ownership to BufferService 2019-06-08 20:21:29 -07:00
Daniel Imms c5c370801c Merge pull request #2209 from Tyriar/render_service
Create RenderService in browser (previously RenderCoordinator)
2019-06-08 20:04:19 -07:00
Daniel Imms e21826f6cb Move MouseHelper.test into browser 2019-06-08 19:40:18 -07:00
Daniel Imms 5dbab76bed Move MouseHelper into browser 2019-06-08 19:34:38 -07:00
Daniel Imms cbfbe232d0 Rename coordinator to service 2019-06-08 19:28:43 -07:00
Daniel Imms 54d7bb0b38 Move RenderService into browser 2019-06-08 19:26:31 -07:00
Daniel Imms 9ad01080f3 Introduce RenderService
Used to be RenderCoordinator
2019-06-08 19:24:48 -07:00
Daniel Imms c314eaaf86 Merge pull request #2208 from Tyriar/buffer_common
Move buffer to common
2019-06-08 19:08:43 -07:00
Daniel Imms b1eecf10ff Remove relative imports with common 2019-06-08 18:05:12 -07:00
Daniel Imms f2e60d4c43 Remove ! in Buffer ctor 2019-06-08 18:01:27 -07:00
Daniel Imms 9a237cb205 Move BufferSet* into common 2019-06-08 18:00:04 -07:00
Daniel Imms 62ff97c82d Move BufferSet deps to common 2019-06-08 17:58:56 -07:00
Daniel Imms 658cd987d9 Move Buffer.test and test utils to common 2019-06-08 17:56:55 -07:00
Daniel Imms 50378403cf Move Buffer to common 2019-06-08 17:43:40 -07:00
Daniel Imms 5c93f2971e Move buffer types to common 2019-06-08 17:17:17 -07:00
Daniel Imms 291fc7368d Fix remaining tests 2019-06-08 17:12:18 -07:00
Daniel Imms c44524b553 Use MockBufferService in tests 2019-06-08 17:06:43 -07:00
Daniel Imms 0dfc1afc21 Create BufferService 2019-06-08 16:59:28 -07:00
Daniel Imms a6540c8d06 Freeze DEFAULT_OPTIONS to prevent accidental edits 2019-06-08 16:48:12 -07:00
Daniel Imms cd61f95612 Adopt options service in buffer 2019-06-08 16:46:03 -07:00
Daniel Imms e2cea7578b Adopt options service in buffer 2019-06-08 16:24:36 -07:00
Daniel Imms 00501bd2e8 Merge pull request #2207 from Tyriar/common_browser
Merge core into common, rename ui to browser
2019-06-08 16:19:21 -07:00
Daniel Imms 6e91875bc4 Rename ui to browser 2019-06-08 16:14:29 -07:00
Daniel Imms 98cda5ca86 Remove duplicate imports 2019-06-08 16:12:20 -07:00
Daniel Imms f8e7ff24d9 Merge core into common
Part of #1507
2019-06-08 16:09:27 -07:00
Daniel Imms df4a96493c Merge pull request #2206 from Tyriar/options_move
Move OptionsService into services folder
2019-06-08 16:04:22 -07:00
Daniel Imms 1704548b46 Move OptionsService into services folder 2019-06-08 15:58:44 -07:00
Daniel Imms b9954ec643 Merge pull request #2205 from Tyriar/char_dim_service
Create CharSizeService
2019-06-08 15:53:25 -07:00
Daniel Imms 9df3a3671d Adopt CharSizeService in RenderCoordinator 2019-06-08 15:46:12 -07:00
Daniel Imms 6375d9b88e Fix event firing 2019-06-08 15:45:07 -07:00
Daniel Imms 47fab14efc Adopt in Terminal 2019-06-08 15:29:16 -07:00
Daniel Imms 0f2d560e01 Adopt in SelectionManager 2019-06-08 15:26:53 -07:00
Daniel Imms 53c3151de6 Adopt in Viewport 2019-06-08 15:25:34 -07:00
Daniel Imms 760128e0f6 Adopt in renderers 2019-06-08 15:24:30 -07:00
Daniel Imms bfcd2b52c2 Adopt CharSizeService in CompositionHelper 2019-06-08 15:22:17 -07:00
Daniel Imms 6246bb5026 Adopt CharSizeService in MouseHelper 2019-06-08 15:20:03 -07:00
Daniel Imms 38bb122bbd CharDimensions -> CharSize 2019-06-08 15:09:55 -07:00
Daniel Imms 2e243feebe Create ICharDimensionsService 2019-06-08 14:54:05 -07:00
Daniel Imms 395530da96 Merge branch 'master' into benchmark_integration 2019-06-08 14:24:33 -07:00
Daniel Imms 2eb77cc4da Merge pull request #2203 from Tyriar/char_width
Move CharWidth into common and move API tests into ./test
2019-06-08 14:24:14 -07:00
Daniel Imms a1e4cd6931 Remove node folder 2019-06-08 14:19:47 -07:00
Daniel Imms 4493ed2575 Rename .integration to .test, this fixes debugging that test 2019-06-08 11:58:52 -07:00
Daniel Imms a29c0fa095 Move other api tests into test folder 2019-06-08 11:50:35 -07:00
Daniel Imms a365b57361 Move node to root-level tests folder 2019-06-08 11:49:14 -07:00
Daniel Imms 0917ce34c6 Move CharWidth.api into node module 2019-06-08 11:39:16 -07:00
Daniel Imms 1546e0c12d Move CharWidth into common 2019-06-08 11:35:52 -07:00
Daniel Imms e758a78f2e Move integration tests into CharWidth.api 2019-06-08 11:32:32 -07:00
Daniel Imms 75d4890e7d Fix debugging launch targets 2019-06-08 11:32:22 -07:00
Jörg Breitbart cb6f3b3be4 Merge branch 'benchmark_integration' of github.com:jerch/xterm.js into benchmark_integration 2019-06-07 22:43:06 +02:00
Daniel Imms 3e3eb4cd76 Merge branch 'master' into benchmark_integration 2019-06-07 12:57:50 -07:00
Jörg Breitbart 1e06af15ac Merge branch 'master' into benchmark_integration 2019-06-07 21:48:24 +02:00
Jörg Breitbart 8e1ebe42b1 fix import, set copyright note 2019-06-07 21:39:07 +02:00
Daniel Imms 7139ee1192 Merge pull request #2199 from jerch/fix_REP
fix repeat preceding character sequence (REP)
2019-06-07 11:02:35 -07:00
Jörg Breitbart 15215a97ff Merge branch 'master' into benchmark_integration 2019-06-07 19:25:01 +02:00
Jörg Breitbart ce91fba1d9 fix typo 2019-06-07 19:14:52 +02:00
Jörg Breitbart b17164520c skip benchmark folders in git 2019-06-07 19:14:04 +02:00
Jörg Breitbart 925e58deb1 remove private access 2019-06-07 18:51:57 +02:00
Jörg Breitbart 5f0e024404 fix REP 2019-06-07 14:45:14 +02:00
Daniel Imms 4cfba558fa Merge pull request #2198 from jerch/2189_terminfo_issue
change TERM to xterm-256color in demo
2019-06-06 20:45:04 -07:00
Jörg Breitbart f3977afe77 change TERM to xterm-256color in demo 2019-06-07 00:36:30 +02:00
Daniel Imms 5c21a6c532 Merge pull request #2197 from xtermjs/fix_soft_reset
Properly clone default attr data on DECSTR
2019-06-06 15:13:54 -07:00
Daniel Imms d271095e28 Freeze DEFAULT_ATTR_DATA to hard fail when not cloned 2019-06-06 15:05:34 -07:00
Daniel Imms 767eec3a2c Properly clone default attr data on DECSTR
Fixes #2196
2019-06-06 14:59:31 -07:00
Daniel Imms 357e6dcd02 Merge pull request #2195 from xtermjs/Tyriar-patch-1
Fix addon import quotes
2019-06-06 12:56:30 -07:00
Daniel Imms f5ee335a43 Fix addon import quotes 2019-06-06 12:56:04 -07:00
Daniel Imms 7f4ba5bf57 Merge pull request #2194 from Tyriar/addon_docs
Add addon docs to README
2019-06-06 12:55:10 -07:00
Daniel Imms c4db8879ac Improve grammar, add old addon link 2019-06-06 12:54:50 -07:00
Daniel Imms 1473afd1b6 Add addon docs to README
Fixes #2192
2019-06-06 12:40:06 -07:00
Daniel Imms 65ba5f06de Merge pull request #2191 from xtermjs/dependabot/npm_and_yarn/js-yaml-3.13.1
Bump js-yaml from 3.12.0 to 3.13.1
2019-06-06 11:35:12 -07:00
dependabot[bot] 678433a92f Bump js-yaml from 3.12.0 to 3.13.1
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.0 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.0...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2019-06-06 18:22:16 +00:00
Jörg Breitbart 3ff3a5d78d add benchmark for write and writeUtf8 2019-06-06 15:46:52 +02:00
Jörg Breitbart e1f7c8a2df link against npm package 2019-06-06 02:59:42 +02:00
Jörg Breitbart 06949df560 make linter happy 2019-06-06 02:43:22 +02:00
Jörg Breitbart e05ae83d6a inital integration of xterm-benchmark 2019-06-06 02:31:41 +02:00
jerch 69ad7554bd Merge pull request #2187 from jerch/parser_inner_loops
relocate parser look ahead loops
2019-06-05 16:19:59 +02:00
Jörg Breitbart cc05dcf763 Merge branch 'parser_inner_loops' of github.com:jerch/xterm.js into parser_inner_loops 2019-06-05 16:15:21 +02:00
Jörg Breitbart d1ec40016c Merge branch 'master' into parser_inner_loops 2019-06-05 16:15:09 +02:00
Jörg Breitbart 489cbfc3da delete remnants 2019-06-05 16:14:16 +02:00
Daniel Imms c35ea040c7 Merge branch 'master' into parser_inner_loops 2019-06-05 06:51:42 -07:00
Daniel Imms 91ec163b4f Merge pull request #2183 from Tyriar/search_strict
Turn on TS strict mode in search addon
2019-06-05 06:26:48 -07:00
Daniel Imms 2526b2d76d Merge branch 'master' into search_strict 2019-06-05 06:22:05 -07:00
Daniel Imms 360bf64562 Merge pull request #2188 from Tyriar/test_warning
Fix test warning
2019-06-05 06:21:46 -07:00
Daniel Imms c1c55aeb78 Merge pull request #2186 from Tyriar/typings_test
Remove typings test
2019-06-05 06:13:05 -07:00
Daniel Imms 4e9163fee4 Fix test warning 2019-06-05 05:35:48 -07:00
Jörg Breitbart 97b11164c1 cleanup code 2019-06-05 10:21:37 +02:00
Jörg Breitbart bf6c684652 relocate loop shortcuts, cleanup parse 2019-06-05 10:15:12 +02:00
Daniel Imms 0ab72d5ce9 Merge branch 'master' into search_strict 2019-06-04 23:54:11 -07:00
Daniel Imms 155d552b35 Merge pull request #2184 from Tyriar/typings_buffer_cell
Correct IBufferLine.getCell API
2019-06-04 23:53:51 -07:00
Daniel Imms 9994047dc7 Remove typings test
Fixes #2185
2019-06-04 23:52:17 -07:00
Daniel Imms c8cd47b51a Correct IBufferLine.getCell API
Fixes #2182
2019-06-04 23:38:39 -07:00
Daniel Imms 031fbde580 Turn on TS strict in search addon
Fixes #2163
2019-06-04 23:37:12 -07:00
Daniel Imms be2c29c95a Remove old redeclared xterm types in search addon 2019-06-04 23:19:26 -07:00
Daniel Imms 27f040f145 Merge pull request #2180 from xtermjs/remove_package_scope
Remove @xtermjs package scope
2019-06-04 15:35:52 -07:00
Daniel Imms 7cc00e09ac Fix typings location 2019-06-04 11:38:44 -07:00
Daniel Imms fee08d74e0 Remove old ITerminalAddon def 2019-06-04 11:34:55 -07:00
Daniel Imms 1a8c7ef596 Bump versions
A lot of them were wrong, updating and publishing on this
2019-06-04 11:11:03 -07:00
Daniel Imms d4be839d8d Remove @xtermjs package scope
Too big of a change for now, I think we should do this when/if we
move to GH package registry (we would have to I think).
2019-06-04 11:07:11 -07:00
jerch d5fddae788 Merge pull request #2177 from jerch/1823_parser_cleanup
parser cleanup
2019-06-03 01:28:06 +02:00
Jörg Breitbart 9442d6e7ff enum for table packing 2019-06-03 01:23:54 +02:00
Jörg Breitbart e1243473e8 use NON_ASCII_PRINTABLE, cleanup ERROR action 2019-06-03 00:28:32 +02:00
Jörg Breitbart 4f412cb6b0 use fill for default transition; create r from blueprint 2019-06-03 00:11:25 +02:00
Jörg Breitbart 9bd7c49003 remove transition table Array fallback, cleanup tests 2019-06-02 23:10:59 +02:00
Daniel Imms e1353c1912 Merge pull request #2164 from Tyriar/addons_in_repo
Move new format addons into repo, remove old addons
2019-06-02 13:06:41 -07:00
Daniel Imms 2b96be0506 Merge branch 'master' into addons_in_repo 2019-06-02 12:58:54 -07:00
jerch 35df028136 Merge pull request #2176 from jerch/single_testfile_argument
ability to inject particular testfile to yarn test
2019-06-02 21:54:37 +02:00
Jörg Breitbart 9b6e182bf6 simplify arg handling 2019-06-02 21:38:24 +02:00
Jörg Breitbart 21bad6b974 ability to inject particular testfile to yarn test 2019-06-02 21:27:48 +02:00
Daniel Imms ad909929cf Merge branch 'master' into addons_in_repo 2019-06-02 10:21:34 -07:00
Daniel Imms c8e267334d Merge pull request #2172 from Tyriar/bracketed_paste_test
Add test for bracketed paste
2019-06-01 19:52:48 -07:00
Daniel Imms c202773f6a Fix prepublishOnly again for new path 2019-06-01 15:14:13 -07:00
Daniel Imms d464341630 Rename to GH org for scope @xtermjs 2019-06-01 15:10:29 -07:00
Daniel Imms 6c18f5c1fe Use scoped packages, fix some typing issues 2019-06-01 15:07:59 -07:00
Daniel Imms 6817a20092 Fix addon prepublish scripts 2019-06-01 14:49:20 -07:00
Daniel Imms eafb322db3 Merge branch 'master' into webgl2 2019-06-01 14:36:59 -07:00
Daniel Imms b5be5c06ad Merge branch 'master' into addons_in_repo 2019-06-01 14:36:55 -07:00
Daniel Imms db2e2f6d7c Merge pull request #2171 from Tyriar/options_service
Introduce options service, move options handling code into common
2019-06-01 14:36:39 -07:00
Daniel Imms 9abb9ddf76 Merge branch 'master' into bracketed_paste_test 2019-06-01 14:31:59 -07:00
Daniel Imms 86d410bfe9 Also test exit bracketed paste mode 2019-06-01 14:31:36 -07:00
Daniel Imms 2925e976e0 Add test for bracketed paste
Part of #2170
Part of #2117
2019-06-01 14:29:26 -07:00
Daniel Imms df411c9308 Merge branch 'master' into webgl2 2019-06-01 11:13:49 -07:00
Daniel Imms d955873787 Merge branch 'master' into addons_in_repo 2019-06-01 11:13:46 -07:00
Daniel Imms ba758ad800 Merge branch 'master' into options_service 2019-06-01 11:13:42 -07:00
Daniel Imms 67db5884d5 Merge pull request #2168 from Tyriar/parser_core
Move EscapeSequenceParser to core
2019-06-01 10:59:48 -07:00
Daniel Imms 22c6a879bb Merge branch 'master' into parser_core 2019-06-01 10:11:31 -07:00
Daniel Imms 463b427000 Merge branch 'master' into addons_in_repo 2019-06-01 09:42:45 -07:00
Daniel Imms fb022eeae5 Merge branch 'master' into options_service 2019-06-01 09:38:36 -07:00
Daniel Imms 8a3c60d495 Clean up 2019-06-01 09:38:09 -07:00
Daniel Imms 041bd7a5d1 Move RenderCoordinator options listener out of Terminal 2019-06-01 09:34:13 -07:00
Daniel Imms 3ba7069787 Introduce options service 2019-06-01 09:29:11 -07:00
Daniel Imms 919c53a4b4 Merge pull request #2169 from Tyriar/dont_path_map_self
Remove path mapping to self modules
2019-06-01 08:52:40 -07:00
Daniel Imms 343d4c3348 Remove path mapping to self modules
This would cause imports in the common module to reference out/ instead
of src/, this leads to weird behavior when errors are introduced.
2019-06-01 08:38:58 -07:00
Daniel Imms 9068107f5a Remove path mapping to self modules
This would cause imports in the common module to reference out/ instead
of src/, this leads to weird behavior when errors are introduced.
2019-06-01 08:37:37 -07:00
jerch cedc8640b5 cleanup transition table class 2019-06-01 10:01:10 +02:00
Daniel Imms 4163b13be0 Move EscapeSequenceParser to core 2019-05-31 22:34:51 -07:00
Daniel Imms 087a40ff07 Fix AttachAddon test name 2019-05-31 21:51:17 -07:00
Daniel Imms 65189e0f28 Don't publish yarnrc 2019-05-31 21:49:46 -07:00
Daniel Imms 8e1f0697b9 Remove zmodem npm script, move scripts above deps 2019-05-31 21:47:37 -07:00
Daniel Imms 38ea4d1d1d Fix lint 2019-05-31 21:40:15 -07:00
Daniel Imms 27fc4d1639 Remove old style addon test 2019-05-31 21:39:37 -07:00
Daniel Imms 42d2ed0d3a Make addon tsconfigs more consistent 2019-05-31 21:29:44 -07:00
Daniel Imms 27b8cf9785 Remove old fit addon 2019-05-31 21:25:53 -07:00
Daniel Imms df72c70800 Add new fit addon 2019-05-31 21:25:35 -07:00
Daniel Imms 9637ee8d76 Make addons use consistent structure 2019-05-31 21:08:05 -07:00
Daniel Imms 42eb5e6b97 Remove all old addons except fit (no replacement yet) 2019-05-31 21:04:17 -07:00
Daniel Imms d9a074899b Remove temporary ITerminalAddon declarations 2019-05-31 20:09:38 -07:00
Daniel Imms 8235bf5dad Add search addon 2019-05-31 20:07:12 -07:00
Daniel Imms a1a63f99ff Add attach addon 2019-05-31 19:58:12 -07:00
Daniel Imms 1cde8a3167 Get tests passing 2019-05-31 19:34:10 -07:00
Daniel Imms ba5fe4bac2 Remove dependency on real web-links addon 2019-05-31 19:24:31 -07:00
Daniel Imms 3fa55475aa Remove unused coveralls npm script 2019-05-31 19:23:38 -07:00
Daniel Imms 65d420486d Clean up included web-links files 2019-05-31 19:23:19 -07:00
Daniel Imms 887b34110c Common web links sources 2019-05-31 19:02:54 -07:00
Daniel Imms 996555c556 Remove accidental sub-module 2019-05-31 19:02:30 -07:00
Daniel Imms 413f9ca3a1 Import web links into demo via node path 2019-05-31 18:58:48 -07:00
Daniel Imms 96b96cfcf8 Move tsconfig.all.json out of src 2019-05-31 18:14:10 -07:00
Daniel Imms 5b86f9291e Fix conflicts in webgl renderer 2019-05-31 18:10:46 -07:00
Daniel Imms 9feaf628b3 Merge remote-tracking branch 'origin/master' into webgl2 2019-05-31 18:06:42 -07:00
Daniel Imms 7a0ed764bd Merge pull request #2157 from Tyriar/1576_remove_static_atlas
Remove experimentalCharAtlas, make dynamic default
2019-05-31 16:08:15 -07:00
Daniel Imms b7a8519173 Merge branch 'master' into 1576_remove_static_atlas 2019-05-31 16:03:33 -07:00
Daniel Imms 0b70083e8f Merge pull request #2162 from Tyriar/remove_xterm_ts
Remove old browserify entry point
2019-05-31 12:28:57 -07:00
Daniel Imms c0ec7d1e6e Remove old browserify entry point
No longer needed after webpack refactor

Missed in #2132
2019-05-31 12:15:31 -07:00
Daniel Imms 653d38b19f Merge pull request #2149 from Tyriar/2148_update_after_ech
Update cells after an ECH
2019-05-31 12:03:42 -07:00
Daniel Imms dea12055de Merge branch 'master' into 2148_update_after_ech 2019-05-31 11:54:07 -07:00
Daniel Imms 468efed19d Merge pull request #2160 from Tyriar/clean_npmignore
Remove webpack config and out from package
2019-05-31 11:50:25 -07:00
Daniel Imms 1c3e7117de Merge pull request #2156 from Tyriar/1237_remove_enableBold
Remove enableBold
2019-05-31 11:12:24 -07:00
Daniel Imms fc91b954f2 Merge pull request #2159 from Tyriar/2158_wp_sourcemaps
Build sourcemaps in lib
2019-05-31 11:11:43 -07:00
Daniel Imms cdaf9d6f63 Remove webpack config and out from package
Part of #2152
2019-05-31 11:11:11 -07:00
Daniel Imms f8c311b59f Build sourcemaps in lib
Fixes #2158
2019-05-31 11:06:41 -07:00
Daniel Imms 53c71b3579 Remove experimentalCharAtlas, make dynamic default
The NoneCharAtlas is still available to swap in if we need it.

Fixes #1576
2019-05-31 10:54:23 -07:00
Daniel Imms b0986494a2 Merge pull request #2155 from Tyriar/1371_remove_destroy
Remove deprecated destroy API
2019-05-31 10:45:31 -07:00
Daniel Imms 94fc2064c2 Remove enableBold
fontWeightBold is the new way to do this

Fixes #1237
2019-05-31 10:43:52 -07:00
Daniel Imms b6b10b7ef6 Remove deprecated destroy API
Fixes #1371
2019-05-31 10:36:51 -07:00
Daniel Imms c08dcac183 Merge pull request #2153 from Tyriar/2152_npmignore
Exclude tslint and devcontainer from npm package
2019-05-31 09:49:02 -07:00
Daniel Imms e4099be954 Exclude tslint and devcontainer from npm package
Fixes #2152
2019-05-31 09:37:51 -07:00
Daniel Imms ac66444c65 Update cells after an ECH
Fixes #2148
2019-05-30 19:53:13 -07:00
Daniel Imms 32d6613811 Merge pull request #2147 from Tyriar/mocha_dev
Move mocha to dev dependencies
2019-05-30 18:01:10 -07:00
Daniel Imms e94812cef1 Move mocha to dev dependencies 2019-05-30 17:33:58 -07:00
Daniel Imms fad6e0f9f0 Merge pull request #2132 from Tyriar/ts_wp
Enable absolute imports and minify distributable
2019-05-30 17:01:10 -07:00
Daniel Imms 5a6287c77c Merge branch 'master' into ts_wp 2019-05-30 16:55:37 -07:00
Daniel Imms 0ed75dc100 Merge pull request #2145 from xtermjs/Tyriar-patch-1
v3.14.0
2019-05-30 16:37:12 -07:00
Daniel Imms b3a631750d v3.14.0 2019-05-30 16:26:37 -07:00
Daniel Imms 9643de4c01 Merge pull request #2141 from Tyriar/ts_3.5
typescript@3.5
2019-05-29 16:38:37 -07:00
Daniel Imms ab1263f669 typescript@3.5 2019-05-29 16:10:54 -07:00
Daniel Imms 64686b5865 Merge branch 'master' into ts_wp 2019-05-28 11:58:58 -07:00
Daniel Imms 9ebe094a2f Merge pull request #2140 from Tyriar/2136_fix_dom_renderer
Fix DOM renderer
2019-05-28 11:56:31 -07:00
Daniel Imms 0c3f2d7222 Revert "Revert "fix: don't use Math.floor in DomRenderer charWidth computation""
This reverts commit 1feb0a27e9.
2019-05-28 09:49:14 -07:00
Daniel Imms a39da0f0d5 Ensure DOM renderer has styles injected on ctor
Fixes #2136
2019-05-28 09:49:03 -07:00
Daniel Imms adac12eded Merge pull request #2134 from Tyriar/fix_underline
Draw underline over char glyph
2019-05-28 08:49:01 -07:00
Daniel Imms 030fb78712 Merge branch 'master' into fix_underline 2019-05-26 21:19:03 -07:00
Daniel Imms 96b3eb982b Draw underline over char glyph 2019-05-26 21:12:36 -07:00
Daniel Imms 8f89ebfe7c Merge branch 'master' into ts_wp 2019-05-26 13:30:53 -07:00
Daniel Imms 746b0169a9 Fix pipelines test script 2019-05-26 13:25:05 -07:00
Daniel Imms efee29d342 Quote test paths 2019-05-26 13:21:01 -07:00
Daniel Imms be11b4fc53 Remove prebuild step 2019-05-26 13:17:57 -07:00
Daniel Imms 5276ad8146 Merge pull request #2133 from Tyriar/remove_scripts
Remove release scripts
2019-05-26 13:17:19 -07:00
Daniel Imms 6ec3a5c1d8 Add mocha
(we never actually declared this)
2019-05-26 13:11:25 -07:00
Daniel Imms 4c42393aa4 Remove release scripts
They're no longer used, azure-pipelines.yml does this now
2019-05-26 13:07:37 -07:00
Daniel Imms 27af4dfa65 Remove nodemon coveralls zmodem.js 2019-05-26 13:06:20 -07:00
Daniel Imms 8ad89f153f Remove test coverage
Doesn't add much or tell the full story now with the integration tests
2019-05-26 13:05:10 -07:00
Daniel Imms a804685f85 Remove gulp and related deps 2019-05-26 13:03:58 -07:00
Daniel Imms c14fd03808 Test addons, don't use gulp 2019-05-26 13:00:08 -07:00
Daniel Imms 5998d22d14 Move css to css/, don't move it around 2019-05-26 12:49:08 -07:00
Daniel Imms eb6e3ab7f7 Fix tests on Windows (hopefully) 2019-05-26 12:43:33 -07:00
Daniel Imms 9f77de42eb Fix unit tests for mac/linux, remove -suite and -debug scripts 2019-05-26 12:37:24 -07:00
Daniel Imms 6cd774ae51 Merge branch 'master' into ts_wp 2019-05-26 12:18:10 -07:00
Daniel Imms c5d5ede15a Build addons and sources before package script 2019-05-26 12:17:57 -07:00
Daniel Imms d7cfd83a84 Explain addon imports in start.js 2019-05-26 12:00:02 -07:00
Daniel Imms 946fbf4a7d Document how the build works 2019-05-26 11:55:46 -07:00
Daniel Imms 4ed3b07199 Remove old dev watch package 2019-05-26 11:48:25 -07:00
Daniel Imms 49c8270b1c Use absolute paths for modules in root project 2019-05-26 11:46:58 -07:00
Daniel Imms d675de0b93 ui project absolute, tweak demo build 2019-05-26 11:38:48 -07:00
Daniel Imms 9ddf83ef26 Create a prod webpack config 2019-05-26 11:23:31 -07:00
Daniel Imms 873f0de0ec Get webpack build working 2019-05-26 11:19:42 -07:00
Daniel Imms 38afe991b2 Kind of working setup 2019-05-26 11:05:23 -07:00
Daniel Imms 1942b4ad51 Merge pull request #2130 from Tyriar/2117_J_tests
Tests for erase in display
2019-05-25 21:34:11 -07:00
Daniel Imms 05ca1cb7dc Up timeouts 2019-05-25 21:25:56 -07:00
Daniel Imms 2f4c5b93fa Merge pull request #2131 from Tyriar/72149_npe
Fix NPE in reflow
2019-05-25 21:23:19 -07:00
Daniel Imms de8d9a720a Fix NPE in reflow
See microsoft/vscode#72149
2019-05-25 21:17:36 -07:00
Daniel Imms 7c2bc70aac Tests for erase in display
Part of #2117
2019-05-25 21:13:47 -07:00
Daniel Imms 44e01ba006 Merge pull request #2128 from Tyriar/1965_optimize_a11y
Only update a11y announcements on animation frame
2019-05-25 19:03:22 -07:00
Daniel Imms 8ffdc14143 Only update a11y announcements on animation frame
Fixes #1965
2019-05-25 11:46:02 -07:00
Daniel Imms fda964b3ea Merge pull request #2127 from jerch/2126_fix
fix losing data after RIS command
2019-05-24 16:39:40 -07:00
Jörg Breitbart b748eca980 fix losing data behind RIS 2019-05-24 23:17:40 +02:00
jerch bbefedb6eb Merge pull request #2125 from jerch/2124_fix_colormode_switches
fix colormode switches
2019-05-24 21:13:59 +02:00
Jörg Breitbart c387180a47 add color mode transition tests 2019-05-24 21:09:11 +02:00
Jörg Breitbart 0e1704f563 cleanup 2019-05-24 20:50:25 +02:00
Daniel Imms b8f55f1c8f Merge pull request #2123 from Tyriar/revert_floor
Revert "fix: don't use Math.floor in DomRenderer charWidth computation"
2019-05-24 06:55:26 -07:00
Daniel Imms a428193424 Merge branch 'master' into revert_floor 2019-05-24 06:50:37 -07:00
Daniel Imms 1feb0a27e9 Revert "fix: don't use Math.floor in DomRenderer charWidth computation"
This reverts commit 23bdb2a6c2.
2019-05-24 06:48:48 -07:00
jerch a92e4adfe2 Merge pull request #2120 from jerch/2108_memory_exhaustion
trim processed chunks from write buffer
2019-05-22 22:28:01 +02:00
Jörg Breitbart 7716e9abda trim already processed chunks 2019-05-22 14:12:15 +02:00
Daniel Imms 6e196da59c Merge pull request #2118 from Tyriar/2117_csi_tests
Add tests for CSI @-I
2019-05-21 22:53:48 -07:00
Daniel Imms 69e8f62149 Make tests way faster by avoiding page reload 2019-05-21 22:43:02 -07:00
Daniel Imms b46757010f Boost timeout of xterm output tests 2019-05-21 22:34:04 -07:00
Daniel Imms a74173adf2 Add tests for CSI @-I
Part of #2117
2019-05-21 22:29:39 -07:00
Daniel Imms c10b18113e Merge pull request #2116 from Tyriar/2097_fix_addon_dispose
Fix new addon dispose
2019-05-21 16:35:28 -07:00
Daniel Imms 7786e59c77 Fix new addon dispose
Fixes #2097
2019-05-21 16:26:50 -07:00
Daniel Imms 10aae5d68a Merge branch 'master' into webgl2 2019-05-21 16:23:05 -07:00
Daniel Imms 9dfac7e674 Merge pull request #2114 from Tyriar/consolidate_api_test_timeout
Move API test timeout to top-level describe
2019-05-21 14:58:37 -07:00
Daniel Imms 922e594fcf Fix lint 2019-05-21 14:51:48 -07:00
Daniel Imms c73aa07135 Merge branch 'master' into consolidate_api_test_timeout 2019-05-21 14:48:22 -07:00
Daniel Imms acea979fe0 Move API test timeout to top-level describe
I learned a thing.
2019-05-21 14:48:03 -07:00
Daniel Imms e4f626e3b6 Merge pull request #2110 from Tyriar/split_out_integration
Split out integration tests into its own job
2019-05-21 14:39:35 -07:00
Daniel Imms 9a4f419820 Merge branch 'master' into split_out_integration 2019-05-21 14:33:27 -07:00
Daniel Imms 209c44898d Merge pull request #2113 from Tyriar/2111_automate_patch_release
Run release against builds on release/* branches
2019-05-21 14:32:12 -07:00
Daniel Imms d3ff32da72 Run release against builds on release/* branches
Fixes #2111
2019-05-21 14:26:28 -07:00
Daniel Imms f81d1cb1cf Increase integration test sleep 2019-05-21 14:20:58 -07:00
Daniel Imms 8f09f58119 Merge branch 'master' into split_out_integration 2019-05-21 12:39:22 -07:00
Daniel Imms ab0eedc513 Fix job name 2019-05-21 11:19:54 -07:00
Daniel Imms 8e460dfe55 Merge pull request #2109 from Tyriar/2107_cursor_report
Fix status reporting
2019-05-21 11:13:32 -07:00
Daniel Imms 37ed1e4796 Split out integration tests into its own job
This will make Linux finish faster and release trigger faster
2019-05-21 11:12:34 -07:00
Daniel Imms d0a3164e99 Fix lint 2019-05-21 11:01:40 -07:00
Daniel Imms 968dd93ba7 Fix status reporting
Fixes #2107
2019-05-21 10:57:26 -07:00
Daniel Imms 493e8ad758 Remove webgl dependence on DEFAULT_ANSI_COLORS 2019-05-19 18:06:25 -07:00
Daniel Imms b79d73d7c0 Add foreground tests 2019-05-19 15:54:49 -07:00
Daniel Imms 4beea9b704 Add tests for webgl bg colors 2019-05-19 15:44:13 -07:00
Daniel Imms 250683364f Use more API in WebglRenderer 2019-05-19 02:23:07 -07:00
Daniel Imms 510985fb4e Add a basic test 2019-05-19 01:49:42 -07:00
Daniel Imms 20dfaae500 Fix runtime error 2019-05-19 00:59:21 -07:00
Daniel Imms 061854b535 Remove more dependencies on rest of project 2019-05-19 00:55:02 -07:00
Daniel Imms 134c2ff859 Move parts of webgl renderer to public API 2019-05-19 00:21:07 -07:00
Daniel Imms 29d3b8281b Copy over typed array utils to webgl 2019-05-18 23:38:49 -07:00
Daniel Imms 6922156d07 Move atlas parts into webgl/ 2019-05-18 23:30:10 -07:00
Daniel Imms f42e53f15a Update for recent changes 2019-05-18 21:56:42 -07:00
Daniel Imms e0ff44441e Merge remote-tracking branch 'origin/master' into webgl2 2019-05-18 21:24:39 -07:00
Daniel Imms 739723fe92 Merge pull request #2101 from Tyriar/bad_comment_
Remove old comment
2019-05-18 21:21:34 -07:00
Daniel Imms 2f08b87d95 Remove old comment 2019-05-18 21:21:02 -07:00
Daniel Imms eb70ddcba5 Merge pull request #2100 from Tyriar/2099_pausing
Support pausing in RenderCoordinator
2019-05-18 21:19:51 -07:00
Daniel Imms 43015f85f4 Move Renderer ownership to RenderCoordinator 2019-05-18 21:15:18 -07:00
Daniel Imms 87dca56dee Support pausing in RenderCoordinator
This actually removes the pause rendering functionality when the resize
and theme changes but simplifies it as a result, they also rarely happen
especially when off screen/hidden.

Fixes #2099
2019-05-18 20:20:46 -07:00
Daniel Imms 72e6863a7f Merge pull request #2098 from Tyriar/2093_logo_demo
Use logo in demo
2019-05-18 20:05:33 -07:00
Daniel Imms e83aa64794 Merge pull request #2096 from Tyriar/render_coordinator
Introduce RenderCoordinator
2019-05-18 20:03:20 -07:00
Daniel Imms c7416a6eaa Use logo in demo
Fixes #2093
2019-05-18 19:56:28 -07:00
Daniel Imms 9ed5920275 Add some basic fg/bg renderer tests 2019-05-18 19:51:44 -07:00
Daniel Imms 497d31bec3 onThemeChange -> setColors 2019-05-18 19:31:35 -07:00
Daniel Imms 24de302d2f onWindowResize -> onDevicePixelRatioChange 2019-05-18 19:27:06 -07:00
Daniel Imms 5f70b3f3be Move window resize listener to render coordinator 2019-05-18 19:22:51 -07:00
Daniel Imms b64cc0a9de Fix ui project build 2019-05-18 19:16:06 -07:00
Daniel Imms 3e4c1b5a21 Move ScreenDprMonitor to be owned by RenderCoordinator
(and a11y manager)
2019-05-18 19:12:37 -07:00
Daniel Imms f698cafccb Move the renderer events to RenderCoordinator 2019-05-18 19:02:42 -07:00
Daniel Imms 8792bb5f36 Introduce a RenderCoordinator that owns common Renderer logic
Part of #2005
2019-05-18 18:47:44 -07:00
Daniel Imms cf867602d1 Use IColorSet instead of IColorManager 2019-05-18 18:24:54 -07:00
Daniel Imms 3df91268c6 Merge remote-tracking branch 'origin/master' into webgl2 2019-05-18 18:24:30 -07:00
Daniel Imms ac48ef977b Merge pull request #2094 from Tyriar/2005_colormanager
Move ColorManager to ui
2019-05-18 18:16:47 -07:00
Daniel Imms 4119c7d1d7 Move ColorManager ownership to Terminal 2019-05-18 18:10:04 -07:00
Daniel Imms 000fefdead Move ColorManager to ui
Part of #2005
Part of #1507
2019-05-18 17:49:48 -07:00
Daniel Imms 2a155d5fb0 Merge branch 'master' into webgl2 2019-05-18 14:38:42 -07:00
Daniel Imms 1e564fdf33 Merge commit 'd261862' into webgl2 2019-05-18 14:27:22 -07:00
Daniel Imms 30567ec3cf Fix event emitter in webgl renderer 2019-05-18 14:24:25 -07:00
Daniel Imms 707d8baddb Merge commit 'fa70aa0983947e4444bcc9c1eeaaa516c1f88fe8' into webgl2 2019-05-18 14:23:40 -07:00
Daniel Imms 72719a6d69 Fix WebGL rendering after UTF-32 by fixing get chardata attr 2019-05-18 14:22:47 -07:00
Daniel Imms 440e097fe3 Merge commit '25745777c653acb53a7bf3864603c1ad7aaaa637' into webgl2 2019-05-18 14:03:29 -07:00
Daniel Imms 33955398e7 Merge pull request #2092 from Tyriar/layering
Move BufferReflow and Marker to core
2019-05-18 09:59:54 -07:00
Daniel Imms dbafc793da Move Marker to core 2019-05-17 23:41:26 -07:00
Daniel Imms 88c1ff6f11 Move BufferReflow to core 2019-05-17 23:37:44 -07:00
Daniel Imms 610c4c9726 Merge pull request #2088 from Tyriar/fix_coveralls
Fix what branch coverage is sent with
2019-05-16 10:47:34 -07:00
Daniel Imms e2214b0239 Fix what branch coverage is sent with 2019-05-16 10:39:53 -07:00
Daniel Imms 23d3a27a6f Merge pull request #2085 from Tyriar/a11y_fix
Add sanity check in AccessibilityManager
2019-05-16 09:58:02 -07:00
Daniel Imms d04016d51f Merge branch 'master' into a11y_fix 2019-05-16 09:52:54 -07:00
Daniel Imms fede301f5f Merge pull request #2081 from Tyriar/xterm-tests
Support debugging integration tests
2019-05-16 09:52:42 -07:00
Daniel Imms a62ec679bd Move readFileSync out of test 2019-05-15 12:49:13 -07:00
Daniel Imms da79fec5c2 Disable failing test on Linux 2019-05-15 11:57:32 -07:00
Daniel Imms 80025804b3 Add sanity check in AccessibilityManager
Fixes #2082
2019-05-15 11:47:15 -07:00
Daniel Imms 955c45906b Merge branch 'master' into xterm-tests 2019-05-13 21:30:33 -07:00
Daniel Imms f331269ef4 Support debugging integration tests 2019-05-13 21:11:56 -07:00
Daniel Imms 9cb6706e2d Merge pull request #2080 from jerch/demo_update
apply attach changes to demo
2019-05-13 21:07:48 -07:00
Daniel Imms b9cfbbea8f xterm-addon-attach@0.1.0-beta8 2019-05-13 20:34:14 -07:00
Jörg Breitbart 58d461bb90 optimize Buffer.concat 2019-05-13 15:33:54 +02:00
Jörg Breitbart 69411916cb make linter happy 2019-05-13 01:45:21 +02:00
Jörg Breitbart 1a596f9608 default to string transport 2019-05-13 01:41:51 +02:00
Jörg Breitbart 67be8c36e7 utf8 switch in server.js 2019-05-13 01:40:54 +02:00
Jörg Breitbart 0b50c06810 Merge branch 'master' into demo_update 2019-05-13 01:25:51 +02:00
Jörg Breitbart 53167df1a8 document utf8 switch in client.ts 2019-05-13 01:24:41 +02:00
jerch eef855601b Merge pull request #1904 from jerch/utf8_input
Support for raw UTF8 input
2019-05-13 01:23:39 +02:00
Jörg Breitbart 6fd5cdd8f1 apply attach changes to demo 2019-05-13 00:58:14 +02:00
Jörg Breitbart c0e9bbe87f Revert "change demo to utf8 input"
This reverts commit e6e5ecc0f2.
2019-05-12 22:17:06 +02:00
Jörg Breitbart 06c292c11d Merge branch 'master' into utf8_input 2019-05-12 22:16:59 +02:00
Jörg Breitbart bda068c5f0 docs 2019-05-12 22:07:14 +02:00
Daniel Imms 031a30b007 Merge pull request #2065 from Tyriar/1128_addons
New addon API
2019-05-12 12:54:45 -07:00
Daniel Imms 3475764946 Types/doc polish 2019-05-12 10:59:26 -07:00
Daniel Imms f90239377b Fix possible infinite loop if addon disposes terminal 2019-05-12 10:47:35 -07:00
Daniel Imms 1502fea431 Remove unused fullscreen addon from demo 2019-05-12 10:41:01 -07:00
Daniel Imms caf8f9d35e Update search addon 2019-05-12 10:39:39 -07:00
Daniel Imms d230f93bde Remove old search addon from demo 2019-05-12 10:25:41 -07:00
Daniel Imms bae125b789 Merge branch 'master' into utf8_input 2019-05-12 10:24:39 -07:00
Daniel Imms eda04bcb23 Add new search addon, move AddonManager to public
Because addons build on top of the API it needs to live in public, the main
reason for this is because the implementation of buffer differs on
public/Terminal and src/Terminal.
2019-05-12 10:22:29 -07:00
Jörg Breitbart 523d562f73 fix missing types 2019-05-12 18:49:23 +02:00
Daniel Imms 0c588a7333 Fix missed merge conflict 2019-05-12 09:45:09 -07:00
Daniel Imms f7612a49d2 Merge remote-tracking branch 'ups/master' into 1128_addons 2019-05-12 09:44:09 -07:00
Daniel Imms 34244248bf Merge pull request #2078 from Tyriar/1443_selection_api
select and getSelectionPosition APIs
2019-05-12 09:40:03 -07:00
Daniel Imms f654044e5e Fix search addon unit tests 2019-05-12 00:17:59 -07:00
Daniel Imms a7fa58cc60 Add API test for getSelectionPosition 2019-05-11 23:59:51 -07:00
Daniel Imms 9ca9f7296e Use new APIs in selection addon 2019-05-11 23:56:34 -07:00
Daniel Imms 5bbbbf7348 Expose getSelectionPosition and select APIs instead 2019-05-11 23:52:38 -07:00
Daniel Imms da7c39e526 Add API test 2019-05-11 23:37:42 -07:00
Daniel Imms 6674f05cc8 Implement setSelection API
Fixes #1443
2019-05-11 23:35:31 -07:00
Daniel Imms 161c7f9339 Use API clearSelection in search addon 2019-05-11 23:22:46 -07:00
Daniel Imms 780e924b21 Use stable API for buffer in search addon 2019-05-11 23:15:04 -07:00
Daniel Imms 1f000054c2 Merge remote-tracking branch 'ups/master' into 1128_addons 2019-05-11 22:48:49 -07:00
Daniel Imms c13d6e5eeb Make write and writeln consistent with writeUtf8 test 2019-05-11 22:29:01 -07:00
Daniel Imms e5dfc56030 Add api test for writeUtf8 2019-05-11 22:24:33 -07:00
Daniel Imms 00423407c1 Clean up 2019-05-11 22:18:18 -07:00
Daniel Imms 2340fcd071 Fix compile and update yarn.lock with utf8 2019-05-11 21:21:36 -07:00
Daniel Imms 59a1749d44 Merge branch 'master' into utf8_input 2019-05-11 21:16:05 -07:00
Daniel Imms 0fae9bb5a8 Merge pull request #2074 from Tyriar/1994_buffer_api
Buffer API
2019-05-11 21:15:55 -07:00
Daniel Imms 70ba349a85 Fix invalid index check, add api tests 2019-05-11 20:58:51 -07:00
Daniel Imms 49574be510 Add warnings to getCell and getLine 2019-05-11 20:49:48 -07:00
Daniel Imms f41e00ed97 Return undefined if cell or line doesn't exist 2019-05-11 20:46:55 -07:00
Jörg Breitbart ce079f399c fix docstring 2019-05-12 00:07:07 +02:00
Jörg Breitbart 7a567d2717 apply time-based limit 2019-05-11 23:10:18 +02:00
Daniel Imms cd3f2609d6 Make tests use buffer API over _core 2019-05-11 12:12:53 -07:00
Daniel Imms 8a929ed142 Add API tests for loadAddon 2019-05-11 11:02:15 -07:00
Daniel Imms 46995fdbc1 Add tests for buffer.getLine 2019-05-11 10:46:00 -07:00
Daniel Imms d694eae6b5 Add some buffer tests 2019-05-11 10:32:53 -07:00
Daniel Imms bce2eae66f Update yarn.lock 2019-05-11 10:15:29 -07:00
Daniel Imms 3554d3e075 Merge branch 'master' into 1128_addons 2019-05-11 10:14:48 -07:00
Daniel Imms eb6deb67f9 Fix build issues 2019-05-11 10:10:31 -07:00
Daniel Imms 7c55e1be9e Merge remote-tracking branch 'ups/master' into 1994_buffer_api 2019-05-11 10:05:31 -07:00
Daniel Imms 7549ca59be Merge branch 'master' into utf8_input 2019-05-11 10:02:14 -07:00
Daniel Imms af81acc50e Merge pull request #2068 from Tyriar/api_tests
API integration tests
2019-05-11 10:00:36 -07:00
Jörg Breitbart f033800554 fix imports 2019-05-11 17:56:26 +02:00
Daniel Imms 623dd56190 Merge pull request #2073 from jerch/2072_remove_instanceof
remove instanceof check
2019-05-11 08:46:22 -07:00
Jörg Breitbart 740604f035 remove instanceof check 2019-05-11 17:21:16 +02:00
Daniel Imms 3f68a60e73 Merge pull request #2067 from starpit/floor
fix: don't use Math.floor in DomRenderer charWidth computation
2019-05-11 00:50:20 -07:00
Daniel Imms 556c56ff94 Merge branch 'master' into api_tests 2019-05-11 00:10:33 -07:00
Daniel Imms dfb5d8e663 Add focus, blur test 2019-05-11 00:00:57 -07:00
Daniel Imms 7562948259 Add tests for all API events 2019-05-10 23:47:28 -07:00
Daniel Imms 34ac1bc502 Fix clearSelection not firing onSelectionChange
Fixes #2070
2019-05-10 23:38:45 -07:00
Daniel Imms 97b176e701 Add selection tests 2019-05-10 23:14:16 -07:00
Daniel Imms 8a5b6b0356 Move puppeteer to devDependencies 2019-05-10 22:58:23 -07:00
Daniel Imms 55d590348c API integration tests
Part of #1247
2019-05-10 22:57:27 -07:00
Nick Mitchell 23bdb2a6c2 fix: don't use Math.floor in DomRenderer charWidth computation
Fixes #2063
2019-05-11 00:59:59 -04:00
Daniel Imms 16aaf6c58c Fix build 2019-05-10 21:08:06 -07:00
Daniel Imms 22c9ad7145 Merge remote-tracking branch 'origin/master' into 1994_buffer_api 2019-05-10 21:04:26 -07:00
Daniel Imms 41a7cabbc2 Merge branch 'master' into 1128_addons 2019-05-10 21:02:55 -07:00
Daniel Imms 724baf22f9 Merge pull request #2066 from Tyriar/lib_import
Fix bad import from lib
2019-05-10 20:52:20 -07:00
Daniel Imms c04ebe974f Fix bad import from lib
Related #1996
2019-05-10 20:51:18 -07:00
Daniel Imms fcee890819 Merge branch 'master' into 1128_addons 2019-05-10 20:47:17 -07:00
Daniel Imms d696046921 Simplify and mark new addon API as experimental 2019-05-10 20:38:08 -07:00
Daniel Imms 518e2734ba Re-introduce original attach and webLinks addons back
We could release this in v3 if we don't break addons like this
2019-05-10 20:30:47 -07:00
Daniel Imms eedcbccb15 Merge remote-tracking branch 'origin/master' into 1128_addons 2019-05-10 20:24:43 -07:00
Daniel Imms d7e6cb17a5 Merge pull request #2062 from Tyriar/windowsMode_typings
Add typings for windowsMode
2019-05-10 19:41:49 -07:00
Daniel Imms b658baf921 Add typings for windowsMode 2019-05-10 16:26:53 -07:00
Daniel Imms 10c6e900ad Merge pull request #2059 from Tyriar/buffer_core
Move BufferLine into core
2019-05-10 15:17:14 -07:00
Daniel Imms b608c9d0ef Merge branch 'master' into buffer_core 2019-05-10 14:57:32 -07:00
Daniel Imms 0e0bcde957 Merge pull request #2061 from Tyriar/fix_beta_off_patch
Make sure beta builds are always on patch version 0
2019-05-10 07:57:33 -07:00
Daniel Imms d735196a30 Make sure beta builds are always on patch version 0 2019-05-10 07:39:42 -07:00
Daniel Imms 59aec69379 Add BufferLine into core and strict null check 2019-05-09 22:19:33 -07:00
Daniel Imms 228ec7b818 Move BufferLine into core 2019-05-09 22:15:32 -07:00
Daniel Imms 7b7fc53157 Move more BufferLine dependencies into core 2019-05-09 22:10:07 -07:00
Daniel Imms f381cdfc33 Move a bunch of types to core 2019-05-09 21:57:33 -07:00
Daniel Imms ac6bced6e7 Merge pull request #2056 from xtermjs/Tyriar-patch-1
Add missing space to typings
2019-05-09 10:12:29 -07:00
Daniel Imms 1a61401cbe Merge pull request #2057 from Tyriar/fix_cd_after_release
Fix beta CD for new major/minor beta versions
2019-05-09 10:12:11 -07:00
Daniel Imms 6d55ab23fd Fix beta CD for new major/minor beta versions 2019-05-09 10:11:25 -07:00
Daniel Imms 3abc090412 Add missing space to typings 2019-05-09 10:02:42 -07:00
Daniel Imms 21f1498977 Merge pull request #2053 from xtermjs/Tyriar-patch-1
Update year in README
2019-05-09 10:00:09 -07:00
Daniel Imms 16c0550d7c Merge pull request #2051 from Tyriar/2019_prepublish
Replace prepublish
2019-05-09 09:59:58 -07:00
Daniel Imms 517d5cfd0e Merge pull request #2050 from Tyriar/2048_demo_line_height
Update terminal dimensions after line height changes
2019-05-09 09:59:49 -07:00
Daniel Imms d363416fb4 Merge pull request #2046 from NizamLZ/fix/2045
Allow + char in URI path
2019-05-09 09:59:36 -07:00
Daniel Imms b959fc8d6a Update year in README 2019-05-09 07:49:50 -07:00
Khaja Nizamuddin 48753625f3 Merge branch 'master' into fix/2045 2019-05-09 12:43:25 +05:30
Daniel Imms 71886167be Replace prepublish
On prepublishOnly we want to do a full build, on prepare we want
to only build the ts projects so the .d.ts files are avilable.

Fixes #2019
2019-05-08 23:08:39 -07:00
Daniel Imms 4b1c54d634 Update terminal dimensions after line height changes
Fixes #2048
2019-05-08 20:53:24 -07:00
Khaja Nizamuddin e831bdf1ef Allow + char in URI path 2019-05-08 21:06:22 +05:30
Daniel Imms eb10652e46 Merge branch 'master' into utf8_input 2019-04-27 18:49:46 -07:00
Daniel Imms 017a5b1218 Merge branch 'master' into utf8_input 2019-04-14 12:54:26 -07:00
Daniel Imms 5362ea195c Add first API test 2019-04-10 00:24:50 -07:00
Daniel Imms b55bedc6af Add terminal API interface to Types.ts
This is needed since the API/public buffer now differs from the TerminalCore's
2019-04-09 21:29:08 -07:00
Daniel Imms 0c388c69bc Merge branch 'master' into pr/jerch/1904 2019-04-09 19:38:39 -04:00
Daniel Imms 2d80abe801 Merge branch 'master' into 1128_addons 2019-04-09 10:57:32 -04:00
Daniel Imms 6b0f2170ea Merge branch 'master' into 1994_buffer_api 2019-04-09 10:57:22 -04:00
Daniel Imms efeca49705 Mostly implemented buffer API
Part of #1994
2019-04-07 15:29:37 -04:00
Daniel Imms 267071ead6 Add deprecation message to applyAddon 2019-04-07 15:00:27 -04:00
Daniel Imms 26a80d0d35 Convert to much simpler model 2019-04-07 14:53:09 -04:00
Daniel Imms 49f58f5d25 Merge branch 'master' into 1128_addons 2019-04-07 14:24:29 -04:00
Daniel Imms 3f993d675f Fix conflicts with new stuff 2019-04-02 20:17:33 -04:00
Daniel Imms 7ddcf1a2a2 Merge branch 'master' into 1128_addons 2019-04-02 20:16:09 -04:00
Daniel Imms 542c109b99 Merge branch 'master' into webgl2 2019-04-02 06:39:25 -07:00
Daniel Imms 4527e92333 Merge pull request #6 from juancampa/selection-simple-2
Only apply the selection hack for the WebGL renderer
2019-03-08 12:18:45 -08:00
Daniel Imms 5ebb4e82d1 Clarify comment 2019-03-08 12:18:27 -08:00
Daniel Imms 1ce75cd4e9 Encapsulate hacks inside WebglRenderer 2019-03-08 12:16:27 -08:00
Daniel Imms b0299acd9f Merge remote-tracking branch 'origin/webgl2' into pr/juancampa/6-1 2019-03-08 12:09:30 -08:00
Daniel Imms 9abe46fe34 Merge branch 'master' into webgl2 2019-03-08 11:53:48 -08:00
Daniel Imms 1ecc9dc832 Merge branch 'master' into webgl2 2019-03-04 10:38:20 -08:00
Jörg Breitbart 2de39024be Merge branch 'utf32_buffer' into utf8_input 2019-02-01 01:11:58 +01:00
Jörg Breitbart ec3a95f727 Merge branch 'utf32_buffer' into utf8_input 2019-01-31 23:32:48 +01:00
Daniel Imms f5d901944d Merge branch 'master' into webgl2 2019-01-31 14:10:35 -08:00
Daniel Imms 15ef5bee8f Merge branch 'master' into webgl2 2019-01-25 21:48:20 -08:00
Daniel Imms 1927bc899a Fix lint 2019-01-25 20:51:19 -08:00
Jörg Breitbart b587c2f30f Merge branch 'master' into utf8_input 2019-01-25 02:43:07 +01:00
Juan Campa 3077ae5311 Only apply the selection hack for the WebGL renderer 2019-01-21 18:56:54 -05:00
Jörg Breitbart e6e5ecc0f2 change demo to utf8 input 2019-01-20 23:06:51 +01:00
Jörg Breitbart 3a2076805c Merge branch 'master' into utf8_input 2019-01-20 22:44:15 +01:00
Jörg Breitbart d7ea0edfcf add utf8 input to terminal 2019-01-20 22:19:50 +01:00
Jörg Breitbart 6bdd380890 add utf8 decoder 2019-01-20 21:54:58 +01:00
Daniel Imms 62ac714d38 Merge pull request #3 from juancampa/selection-simple-webgl2
Use bg luminance to determine background color
2019-01-19 09:35:25 -08:00
Juan Campa e387b20b56 Adding missing parameter to GlyphRenderer 2019-01-18 15:25:58 -05:00
Daniel Imms c43568283c Merge remote-tracking branch 'origin/master' into webgl2 2019-01-16 11:17:07 -08:00
Daniel Imms 4181321377 Add super.dispose to WebglRenderer.dispose 2019-01-16 11:15:45 -08:00
Daniel Imms a92c0c1414 Merge pull request #4 from juancampa/no-aa-depth
Disable antialiasing and depth buffer for WebGL2 contexts
2019-01-15 15:56:45 -08:00
Juan Campa 1d7a39bcfd Disable antialiasing and depth buffer for WebGL2 contexts 2019-01-15 16:36:38 -05:00
Juan Campa 98706aa7d2 Use bg luminance to determine background color 2019-01-08 16:44:57 -05:00
Daniel Imms 7ba17ca770 Convert web links and attach to modules 2019-01-03 22:19:30 -08:00
Daniel Imms 290394b401 New addon prototype
Part of #1128
2019-01-03 20:22:53 -08:00
Daniel Imms 66735ba671 Merge branch 'master' into webgl2 2019-01-02 15:09:52 -08:00
Daniel Imms b0e51b9ec9 Fix build error 2019-01-02 15:09:38 -08:00
Daniel Imms 408388130d Merge branch 'master' into webgl2 2018-12-31 19:46:36 -08:00
Daniel Imms 1227497951 Merge branch 'master' into webgl2 2018-12-27 17:10:43 -08:00
Daniel Imms 01b37b2fef Document how GlyphRenderer.render works 2018-12-27 17:10:18 -08:00
Daniel Imms 9cf3d14d8a Clean up loop that sets cell coordinates 2018-12-27 17:01:13 -08:00
Daniel Imms 5f9144dfd7 Fix null/whitespace early exit 2018-12-27 16:56:20 -08:00
Daniel Imms 0ed0bfa5ab Merge branch 'master' into webgl2 2018-12-27 14:17:34 -08:00
Daniel Imms 26db71d296 Merge branch 'master' into webgl2 2018-12-26 11:09:24 -08:00
Daniel Imms 1b1b641670 Merge branch 'master' into webgl2 2018-12-20 16:40:03 -08:00
Daniel Imms bb9ccf40b6 Reduce diff with master 2018-12-09 09:28:04 -08:00
Daniel Imms 3d8b304af4 Reduce precision of floats in fragment shader
~0.43ms/frame -> ~0.37ms/frame
2018-12-09 08:31:49 -08:00
Daniel Imms c16d70ec06 Merge remote-tracking branch 'origin/master' into webgl2 2018-12-09 08:26:33 -08:00
Daniel Imms 6bc9b9b14d Improve constructor use in sliceFallback 2018-11-29 10:26:04 -08:00
Daniel Imms fe7941034e Merge branch 'master' into webgl2 2018-11-27 09:19:17 -08:00
Daniel Imms b8b111f4a6 Only pass a subset of the attributes buffer to GPU 2018-11-25 10:18:14 -08:00
Daniel Imms 60e3ddbfd0 Update color codes after merging the move to constants 2018-11-24 05:52:23 -08:00
Daniel Imms 186b2be4b9 Fix imports 2018-11-24 05:48:05 -08:00
Daniel Imms 569abde8c7 Merge remote-tracking branch 'ups/master' into webgl2 2018-11-24 05:46:58 -08:00
Daniel Imms 53dc2af2b7 Use polyfill for TypedArray.slice 2018-11-23 08:00:27 -08:00
Daniel Imms 128b1b0a48 Use polyfill for TypedArray.fill 2018-11-23 07:14:56 -08:00
Daniel Imms 1567b41d6e Merge branch 'master' into webgl2 2018-11-23 06:59:43 -08:00
Daniel Imms 43721160d7 Merge branch 'master' into webgl2 2018-11-22 12:46:30 -08:00
Daniel Imms 928abdb0c3 Merge branch 'master' into webgl2 2018-11-22 11:10:08 -08:00
Daniel Imms 42eda149c7 Set theme in ctor 2018-11-22 10:57:45 -08:00
Daniel Imms 5c1e5a1787 Merge branch 'master' into webgl2 2018-11-20 09:14:31 -08:00
Daniel Imms e6d339a289 Fix wide char caching in webgl renderer 2018-11-19 16:54:53 -08:00
Daniel Imms c97feab05c Initial webgl renderer implementation 2018-11-16 14:34:12 -08:00
306 changed files with 25523 additions and 16382 deletions
+9 -2
View File
@@ -8,12 +8,19 @@ RUN apt-get update \
# Verify git and process tools are installed
RUN apt-get install -y git procps
# Install yarn
# Install yarn, puppeteer deps
RUN apt-get install -y curl apt-transport-https lsb-release \
&& curl -sS https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/pubkey.gpg | apt-key add - 2>/dev/null \
&& echo "deb https://dl.yarnpkg.com/$(lsb_release -is | tr '[:upper:]' '[:lower:]')/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update \
&& apt-get -y install --no-install-recommends yarn
&& apt-get -y install --no-install-recommends \
yarn fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst ttf-freefont \
# https://github.com/Googlechrome/puppeteer/issues/290#issuecomment-322921352
gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
# Clean up
RUN apt-get autoremove -y \
+6 -5
View File
@@ -2,6 +2,8 @@ node_modules/
*.swp
.lock-wscript
lib/
out/
out-test/
Makefile.gyp
*.Makefile
*.target.gyp.mk
@@ -13,13 +15,12 @@ npm-debug.log
.env
build/
.DS_Store
fixtures/typings-test/*.js
package-lock.json
# Directories needed for code coverage
coverage/
.nyc_output/
# Keep bundled code out of Git
dist/
demo/dist/
# dont commit benchmark folders
.benchmark/
timeline/
+9 -1
View File
@@ -6,6 +6,9 @@
!*.js
!*.json
# Whitelist - css/
!css/**/*.css
# Whitelist - dist/
!dist/**/*.js
!dist/**/*.js.map
@@ -33,11 +36,14 @@
!typings/*.d.ts
# Blacklist - (normal behavior) these will override any whitelist
*.d.ts.map
*.test.ts
*.test.d.ts
*.test.js
*.test.js.map
lib/test/
tslint.json
webpack.config.js
docs/
/.idea/
@@ -45,5 +51,7 @@ docs/
bin/
build/
fixtures/
coverage/
demo/
.devcontainer/
out/
addons/
+22 -1
View File
@@ -13,7 +13,28 @@
"runtimeArgs": [
"--colors",
"--recursive",
"${workspaceRoot}/lib"
"${workspaceRoot}/out/**/*.test.js"
],
"env": {
"NODE_PATH": "${workspaceRoot}/out"
},
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/out/**/*.js" ],
"internalConsoleOptions": "openOnSessionStart"
},
{
"type": "node",
"request": "launch",
"name": "Integration Tests",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/mocha.cmd"
},
"runtimeArgs": [
"--colors",
"--recursive",
"${workspaceRoot}/out/**/*.api.js"
],
"sourceMaps": true,
"outFiles": [ "${workspaceRoot}/lib/**/*.js" ],
+28 -30
View File
@@ -1,14 +1,13 @@
# [![xterm.js logo](logo-full.png)](https://xtermjs.org)
[![Build Status](https://dev.azure.com/xtermjs/xterm.js/_apis/build/status/xtermjs.xterm.js)](https://dev.azure.com/xtermjs/xterm.js/_build/latest?definitionId=3)
[![Coverage Status](https://coveralls.io/repos/github/xtermjs/xterm.js/badge.svg?branch=master)](https://coveralls.io/github/xtermjs/xterm.js?branch=master)
Xterm.js is a front-end component written in TypeScript that lets applications bring fully-featured terminals to their users in the browser. It's used by popular projects such as VS Code, Hyper and Theia.
## Features
- **Terminal apps just work**: Xterm.js works with most terminal apps such as `bash`, `vim` and `tmux`, this includes support for curses-based apps and mouse event support.
- **Perfomant**: Xterm.js is *really* fast, it even includes a GPU-accelerated renderer.
- **Performant**: Xterm.js is *really* fast, it even includes a GPU-accelerated renderer.
- **Rich unicode support**: Supports CJK, emojis and IMEs.
- **Self-contained**: Requires zero dependencies to work.
- **Accessible**: Screen reader support can be turned on using the `screenReaderMode` option.
@@ -33,8 +32,8 @@ To start using xterm.js on your browser, add the `xterm.js` and `xterm.css` to t
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="node_modules/xterm/dist/xterm.css" />
<script src="node_modules/xterm/dist/xterm.js"></script>
<link rel="stylesheet" href="node_modules/xterm/css/xterm.css" />
<script src="node_modules/xterm/lib/xterm.js"></script>
</head>
<body>
<div id="terminal"></div>
@@ -57,43 +56,38 @@ import { Terminal } from 'xterm';
### Addons
Addons are JavaScript modules that extend the `Terminal` prototype with new methods and attributes to provide additional functionality. There are a handful available in the main repository in the `src/addons` directory and you can even write your own by using the [public API](https://github.com/xtermjs/xterm.js/blob/master/typings/xterm.d.ts).
⚠️ *This section describes the new addon format introduced in v3.14.0, see [here](https://github.com/xtermjs/xterm.js/blob/3.14.2/README.md#addons) for the instructions on the old format*
To use an addon, just import the JavaScript module and pass it to `Terminal`'s `applyAddon` method:
Addons are separate modules that extend the `Terminal` by building on the [xterm.js API](https://github.com/xtermjs/xterm.js/blob/master/typings/xterm.d.ts). To use an addon you first need to install it in your project:
```javascript
import { Terminal } from 'xterm';
import * as fit from 'xterm/lib/addons/fit/fit';
Terminal.applyAddon(fit);
var xterm = new Terminal(); // Instantiate the terminal
xterm.fit(); // Use the `fit` method, provided by the `fit` addon
```bash
npm i -S xterm-addon-web-links
```
You will also need to include the addon's CSS file if it has one in the folder.
Then import the addon, instantiate it and call `Terminal.loadAddon`:
#### Importing Addons in TypeScript
There are currently no typings for addons if they are accessed via extending Terminal prototype, so you will need to upcast if using TypeScript, eg. `(xterm as any).fit()`. Alternatively, you can import the addon function and enhance the terminal on demand. This has better typing support and is friendly to treeshaking.
```typescript
```ts
import { Terminal } from 'xterm';
import { fit } from 'xterm/lib/addons/fit/fit';
const xterm = new Terminal();
import { WebLinksAddon } from 'xterm-addon-web-links';
fit(xterm); // Fit the terminal when necessary
const terminal = new Terminal();
// Load WebLinksAddon on terminal, this is all that's needed to get web links
// working in the terminal.
terminal.loadAddon(new WebLinksAddon());
```
The xterm.js team maintains the following addons but they can be built by anyone:
- [`xterm-addon-attach`](https://github.com/xtermjs/xterm.js/tree/master/addons/xterm-addon-attach): Attaches to a server running a process via a websocket
- [`xterm-addon-fit`](https://github.com/xtermjs/xterm.js/tree/master/addons/xterm-addon-fit): Fits the terminal to the containing element
- [`xterm-addon-search`](https://github.com/xtermjs/xterm.js/tree/master/addons/xterm-addon-search): Adds search functionality
- [`xterm-addon-web-links`](https://github.com/xtermjs/xterm.js/tree/master/addons/xterm-addon-web-links): Adds web link detection and interaction
## Browser Support
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Here is a list of the versions we aim to support:
Since xterm.js is typically implemented as a developer tool, only modern browsers are supported officially. Specifically the latest versions of *Chrome*, *Edge*, *Firefox* and *Safari*.
- Chrome latest
- Edge latest
- Firefox latest
- Safari latest
- IE11
We also partially support *Intenet Explorer 11*, meaning xterm.js should work for the most part, but we reserve the right to not provide workarounds specifically for it unless it's absolutely necessary to get the basic input/output flow working.
Xterm.js works seamlessly in [Electron](https://electronjs.org/) apps and may even work on earlier versions of the browsers, these are the versions we strive to keep working.
@@ -158,6 +152,10 @@ Xterm.js is used in several world-class applications to provide great terminal e
- [**CodeInterview.io**](https://codeinterview.io): A coding interview platform in 25+ languages and many web frameworks. Uses xterm.js to provide shell access.
- [**Bastillion**](https://www.bastillion.io): Bastillion is an open-source web-based SSH console that centrally manages administrative access to systems.
- [**PHP App Server**](https://github.com/cubiclesoft/php-app-server/): Create lightweight, installable almost-native applications for desktop OSes. ExecTerminal (nicely wraps the xterm.js Terminal), TerminalManager, and RunProcessSDK are self-contained, reusable ES5+ compliant Javascript components.
- [**NgTerminal**](https://github.com/qwefgh90/ng-terminal): NgTerminal is a web terminal that leverages xterm.js on Angular 7+. You can easily add it into your application by adding `<ng-terminal></ng-terminal>` into your component.
- [**tty-share**](https://tty-share.com): Extremely simple terminal sharing over the Internet.
- [**Ten Hands**](https://github.com/saisandeepvaddi/ten-hands): One place to run your command-line tasks.
- [**WebAssembly.sh**](https://webassembly.sh): A WebAssembly WASI browser terminal
[And much more...](https://github.com/xtermjs/xterm.js/network/dependents)
@@ -187,6 +185,6 @@ You can read the [guide on the wiki](https://github.com/xtermjs/xterm.js/wiki/Co
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.
Copyright (c) 2017-2018, [The xterm.js authors](https://github.com/xtermjs/xterm.js/graphs/contributors) (MIT License)<br>
Copyright (c) 2017-2019, [The xterm.js authors](https://github.com/xtermjs/xterm.js/graphs/contributors) (MIT License)<br>
Copyright (c) 2014-2017, SourceLair, Private Company ([www.sourcelair.com](https://www.sourcelair.com/home)) (MIT License)<br>
Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
+2
View File
@@ -0,0 +1,2 @@
lib
node_modules
+5
View File
@@ -0,0 +1,5 @@
**/*.api.js
**/*.api.ts
tsconfig.json
.yarnrc
webpack.config.js
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)
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.
+22
View File
@@ -0,0 +1,22 @@
## xterm-addon-attach
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables attaching to a web socket. This addon requires xterm.js v4+.
### Install
```bash
npm install --save xterm-addon-attach
```
### Usage
```ts
import { Terminal } from 'xterm';
import { AttachAddon } from 'xterm-addon-attach';
const terminal = new Terminal();
const attachAddon = new AttachAddon(webSocket);
terminal.loadAddon(attachAddon);
```
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-attach/typings/xterm-addon-attach.d.ts) for more advanced usage.
+21
View File
@@ -0,0 +1,21 @@
{
"name": "xterm-addon-attach",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-attach.js",
"types": "typings/xterm-addon-attach.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"scripts": {
"build": "../../node_modules/.bin/tsc -p src",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^4.0.0"
}
}
@@ -0,0 +1,71 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import * as puppeteer from 'puppeteer';
import { assert } from 'chai';
import { ITerminalOptions } from 'xterm';
import WebSocket = require('ws');
const APP = 'http://127.0.0.1:3000/test';
let browser: puppeteer.Browser;
let page: puppeteer.Page;
const width = 800;
const height = 600;
describe('AttachAddon', () => {
before(async function(): Promise<any> {
this.timeout(20000);
browser = await puppeteer.launch({
headless: process.argv.indexOf('--headless') !== -1,
slowMo: 80,
args: [`--window-size=${width},${height}`, `--no-sandbox`]
});
page = (await browser.pages())[0];
await page.setViewport({ width, height });
});
after(async () => {
await browser.close();
});
beforeEach(async function(): Promise<any> {
this.timeout(20000);
await page.goto(APP);
});
it('string', async function(): Promise<any> {
this.timeout(20000);
await openTerminal({ rendererType: 'dom' });
const port = 8080;
const server = new WebSocket.Server({ port });
server.on('connection', socket => socket.send('foo'));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
assert.equal(await page.evaluate(`window.term.buffer.getLine(0).translateToString(true)`), 'foo');
server.close();
});
it('utf8', async function(): Promise<any> {
this.timeout(20000);
await openTerminal({ rendererType: 'dom' });
const port = 8080;
const server = new WebSocket.Server({ port });
const data = new Uint8Array([102, 111, 111]);
server.on('connection', socket => socket.send(data));
await page.evaluate(`window.term.loadAddon(new window.AttachAddon(new WebSocket('ws://localhost:${port}')))`);
assert.equal(await page.evaluate(`window.term.buffer.getLine(0).translateToString(true)`), 'foo');
server.close();
});
});
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
if (options.rendererType === 'dom') {
await page.waitForSelector('.xterm-rows');
} else {
await page.waitForSelector('.xterm-text-layer');
}
}
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2014, 2019 The xterm.js authors. All rights reserved.
* @license MIT
*
* Implements the attach method, that attaches the terminal to a WebSocket stream.
*/
import { Terminal, IDisposable, ITerminalAddon } from 'xterm';
interface IAttachOptions {
bidirectional?: boolean;
}
export class AttachAddon implements ITerminalAddon {
private _socket: WebSocket;
private _bidirectional: boolean;
private _disposables: IDisposable[] = [];
constructor(socket: WebSocket, options?: IAttachOptions) {
this._socket = socket;
// always set binary type to arraybuffer, we do not handle blobs
this._socket.binaryType = 'arraybuffer';
this._bidirectional = (options && options.bidirectional === false) ? false : true;
}
public activate(terminal: Terminal): void {
this._disposables.push(
addSocketListener(this._socket, 'message', ev => {
const data: ArrayBuffer | string = ev.data;
terminal.write(typeof data === 'string' ? data : new Uint8Array(data));
})
);
if (this._bidirectional) {
this._disposables.push(terminal.onData(data => this._sendData(data)));
}
this._disposables.push(addSocketListener(this._socket, 'close', () => this.dispose()));
this._disposables.push(addSocketListener(this._socket, 'error', () => this.dispose()));
}
public dispose(): void {
this._disposables.forEach(d => d.dispose());
}
private _sendData(data: string): void {
// TODO: do something better than just swallowing
// the data if the socket is not in a working condition
if (this._socket.readyState !== 1) {
return;
}
this._socket.send(data);
}
}
function addSocketListener<K extends keyof WebSocketEventMap>(socket: WebSocket, type: K, handler: (this: WebSocket, ev: WebSocketEventMap[K]) => any): IDisposable {
socket.addEventListener(type, handler);
return {
dispose: () => {
if (!handler) {
// Already disposed
return;
}
socket.removeEventListener(type, handler);
}
};
}
@@ -1,22 +1,19 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"target": "es2015",
"lib": [
"dom",
"es5",
"es2015"
],
"rootDir": ".",
"outDir": "../../../lib/addons/webLinks/",
"outDir": "../out",
"sourceMap": true,
"removeComments": true,
"declaration": true,
"types": [
"../../node_modules/@types/mocha"
]
"strict": true
},
"include": [
"**/*.ts",
"./**/*",
"../../../typings/xterm.d.ts"
]
}
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ILinkMatcherOptions, ITerminalAddon } from 'xterm';
declare module 'xterm-addon-attach' {
export interface IAttachOptions {
/**
* Whether input should be written to the backend. Defaults to `true`.
*/
bidirectional?: boolean;
}
export class AttachAddon implements ITerminalAddon {
constructor(socket: WebSocket, options?: IAttachOptions);
public activate(terminal: Terminal): void;
public dispose(): void;
}
}
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const path = require('path');
const addonName = 'AttachAddon';
const mainFile = 'xterm-addon-attach.js';
module.exports = {
entry: `./out/${addonName}.js`,
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: /node_modules/
}
]
},
output: {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
},
mode: 'production'
};
+2
View File
@@ -0,0 +1,2 @@
lib
node_modules
+5
View File
@@ -0,0 +1,5 @@
**/*.api.js
**/*.api.ts
tsconfig.json
.yarnrc
webpack.config.js
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2019, The xterm.js authors (https://github.com/xtermjs/xterm.js)
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.
+24
View File
@@ -0,0 +1,24 @@
## xterm-addon-fit
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables fitting the terminal's dimensions to a containing element. This addon requires xterm.js v4+.
### Install
```bash
npm install --save xterm-addon-fit
```
### Usage
```ts
import { Terminal } from 'xterm';
import { FitAddon } from 'xterm-addon-fit';
const terminal = new Terminal();
const fitAddon = new FitAddon();
terminal.loadAddon(fitAddon);
terminal.open(containerElement);
fitAddon.fit();
```
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-fit/typings/xterm-addon-fit.d.ts) for more advanced usage.
+21
View File
@@ -0,0 +1,21 @@
{
"name": "xterm-addon-fit",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-fit.js",
"types": "typings/xterm-addon-fit.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"scripts": {
"build": "../../node_modules/.bin/tsc -p src",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^4.0.0"
}
}
+119
View File
@@ -0,0 +1,119 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import * as puppeteer from 'puppeteer';
import { assert } from 'chai';
import { ITerminalOptions } from 'xterm';
const APP = 'http://127.0.0.1:3000/test';
let browser: puppeteer.Browser;
let page: puppeteer.Page;
const width = 1024;
const height = 768;
describe('FitAddon', () => {
before(async function(): Promise<any> {
this.timeout(20000);
browser = await puppeteer.launch({
headless: process.argv.indexOf('--headless') !== -1,
slowMo: 80,
args: [`--window-size=${width},${height}`, `--no-sandbox`]
});
page = (await browser.pages())[0];
await page.setViewport({ width, height });
await page.goto(APP);
await openTerminal();
});
after(async () => {
await browser.close();
});
it('no terminal', async function(): Promise<any> {
await page.evaluate(`window.fit = new FitAddon();`);
assert.equal(await page.evaluate(`window.fit.proposeDimensions()`), undefined);
});
describe('proposeDimensions', () => {
afterEach(async () => {
return unloadFit();
});
it('default', async function(): Promise<any> {
await loadFit();
assert.deepEqual(await page.evaluate(`window.fit.proposeDimensions()`), {
cols: 87,
rows: 26
});
});
it('width', async function(): Promise<any> {
await loadFit(1008);
assert.deepEqual(await page.evaluate(`window.fit.proposeDimensions()`), {
cols: 110,
rows: 26
});
});
it('small', async function(): Promise<any> {
await loadFit(1, 1);
assert.deepEqual(await page.evaluate(`window.fit.proposeDimensions()`), {
cols: 2,
rows: 1
});
});
});
describe('fit', () => {
afterEach(async () => {
return unloadFit();
});
it('default', async function(): Promise<any> {
await loadFit();
await page.evaluate(`window.fit.fit()`);
assert.equal(await page.evaluate(`window.term.cols`), 87);
assert.equal(await page.evaluate(`window.term.rows`), 26);
});
it('width', async function(): Promise<any> {
await loadFit(1008);
await page.evaluate(`window.fit.fit()`);
assert.equal(await page.evaluate(`window.term.cols`), 110);
assert.equal(await page.evaluate(`window.term.rows`), 26);
});
it('small', async function(): Promise<any> {
await loadFit(1, 1);
await page.evaluate(`window.fit.fit()`);
assert.equal(await page.evaluate(`window.term.cols`), 2);
assert.equal(await page.evaluate(`window.term.rows`), 1);
});
});
});
async function loadFit(width: number = 800, height: number = 450): Promise<void> {
await page.evaluate(`
window.fit = new FitAddon();
window.term.loadAddon(window.fit);
document.querySelector('#terminal-container').style.width='${width}px';
document.querySelector('#terminal-container').style.height='${height}px';
`);
}
async function unloadFit(): Promise<void> {
await page.evaluate(`window.fit.dispose();`);
}
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
if (options.rendererType === 'dom') {
await page.waitForSelector('.xterm-rows');
} else {
await page.waitForSelector('.xterm-text-layer');
}
}
+82
View File
@@ -0,0 +1,82 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ITerminalAddon } from 'xterm';
interface ITerminalDimensions {
/**
* The number of rows in the terminal.
*/
rows: number;
/**
* The number of columns in the terminal.
*/
cols: number;
}
const MINIMUM_COLS = 2;
const MINIMUM_ROWS = 1;
export class FitAddon implements ITerminalAddon {
private _terminal: Terminal | undefined;
constructor() {}
public activate(terminal: Terminal): void {
this._terminal = terminal;
}
public dispose(): void {}
public fit(): void {
const dims = this.proposeDimensions();
if (!dims || !this._terminal) {
return;
}
// TODO: Remove reliance on private API
const core = (<any>this._terminal)._core;
// Force a full render
if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) {
core._renderService.clear();
this._terminal.resize(dims.cols, dims.rows);
}
}
public proposeDimensions(): ITerminalDimensions | undefined {
if (!this._terminal) {
return undefined;
}
if (!this._terminal.element || !this._terminal.element.parentElement) {
return undefined;
}
// TODO: Remove reliance on private API
const core = (<any>this._terminal)._core;
const parentElementStyle = window.getComputedStyle(this._terminal.element.parentElement);
const parentElementHeight = parseInt(parentElementStyle.getPropertyValue('height'));
const parentElementWidth = Math.max(0, parseInt(parentElementStyle.getPropertyValue('width')));
const elementStyle = window.getComputedStyle(this._terminal.element);
const elementPadding = {
top: parseInt(elementStyle.getPropertyValue('padding-top')),
bottom: parseInt(elementStyle.getPropertyValue('padding-bottom')),
right: parseInt(elementStyle.getPropertyValue('padding-right')),
left: parseInt(elementStyle.getPropertyValue('padding-left'))
};
const elementPaddingVer = elementPadding.top + elementPadding.bottom;
const elementPaddingHor = elementPadding.right + elementPadding.left;
const availableHeight = parentElementHeight - elementPaddingVer;
const availableWidth = parentElementWidth - elementPaddingHor - core.viewport.scrollBarWidth;
const geometry = {
cols: Math.max(MINIMUM_COLS, Math.floor(availableWidth / core._renderService.dimensions.actualCellWidth)),
rows: Math.max(MINIMUM_ROWS, Math.floor(availableHeight / core._renderService.dimensions.actualCellHeight))
};
return geometry;
}
}
@@ -4,19 +4,16 @@
"target": "es5",
"lib": [
"dom",
"es5"
"es2015"
],
"rootDir": ".",
"outDir": "../../../lib/addons/fit/",
"outDir": "../out",
"sourceMap": true,
"removeComments": true,
"declaration": true,
"types": [
"../../node_modules/@types/mocha"
]
"strict": true
},
"include": [
"**/*.ts",
"./**/*",
"../../../typings/xterm.d.ts"
]
}
+55
View File
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ITerminalAddon } from 'xterm';
declare module 'xterm-addon-fit' {
/**
* An xterm.js addon that enables resizing the terminal to the dimensions of
* its containing element.
*/
export class FitAddon implements ITerminalAddon {
/**
* Creates a new fit addon.
*/
constructor();
/**
* Activates the addon
* @param terminal The terminal the addon is being loaded in.
*/
public activate(terminal: Terminal): void;
/**
* Disposes the addon.
*/
public dispose(): void;
/**
* Resizes the terminal to the dimensions of its containing element.
*/
public fit(): void;
/**
* Gets the proposed dimensions that will be used for a fit.
*/
public proposeDimensions(): ITerminalDimensions;
}
/**
* Reprepresents the dimensions of a terminal.
*/
export interface ITerminalDimensions {
/**
* The number of rows in the terminal.
*/
rows: number;
/**
* The number of columns in the terminal.
*/
cols: number;
}
}
+31
View File
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const path = require('path');
const addonName = 'FitAddon';
const mainFile = 'xterm-addon-fit.js';
module.exports = {
entry: `./out/${addonName}.js`,
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: /node_modules/
}
]
},
output: {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
},
mode: 'production'
};
+2
View File
@@ -0,0 +1,2 @@
lib
node_modules
+5
View File
@@ -0,0 +1,5 @@
**/*.api.js
**/*.api.ts
tsconfig.json
.yarnrc
webpack.config.js
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)
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.
+23
View File
@@ -0,0 +1,23 @@
## xterm-addon-search
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables searching the buffer. This addon requires xterm.js v4+.
### Install
```bash
npm install --save xterm-addon-search
```
### Usage
```ts
import { Terminal } from 'xterm';
import { SearchAddon } from 'xterm-addon-search';
const terminal = new Terminal();
const searchAddon = new SearchAddon();
terminal.loadAddon(searchAddon);
searchAddon.findNext('foo');
```
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-search/typings/xterm-addon-search.d.ts) for more advanced usage.
+21
View File
@@ -0,0 +1,21 @@
{
"name": "xterm-addon-search",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-search.js",
"types": "typings/xterm-addon-search.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"scripts": {
"build": "../../node_modules/.bin/tsc -p src",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^4.0.0"
}
}
@@ -0,0 +1,132 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import * as puppeteer from 'puppeteer';
import { assert } from 'chai';
import { ITerminalOptions } from 'xterm';
const APP = 'http://127.0.0.1:3000/test';
let browser: puppeteer.Browser;
let page: puppeteer.Page;
const width = 800;
const height = 600;
describe('Search Tests', function (): void {
this.timeout(20000);
before(async function (): Promise<any> {
browser = await puppeteer.launch({
headless: process.argv.indexOf('--headless') !== -1,
slowMo: 80,
args: [`--window-size=${width},${height}`, `--no-sandbox`]
});
page = (await browser.pages())[0];
await page.setViewport({ width, height });
await page.goto(APP);
await openTerminal();
await page.evaluate(`window.search = new SearchAddon();`);
await page.evaluate(`window.term.loadAddon(window.search);`);
});
after(() => {
browser.close();
});
beforeEach(async () => {
await page.evaluate(`window.term.reset()`);
});
it('Simple Search', async () => {
await writeSync('dafhdjfldshafhldsahfkjhldhjkftestlhfdsakjfhdjhlfdsjkafhjdlk');
assert.deepEqual(await page.evaluate(`window.search.findNext('test')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'test');
});
it('Scrolling Search', async () => {
let dataString = '';
for (let i = 0; i < 100; i++) {
if (i === 52) {
dataString += '$^1_3{}test$#';
}
dataString += makeData(50);
}
await writeSync(dataString);
assert.deepEqual(await page.evaluate(`window.search.findNext('$^1_3{}test$#')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), '$^1_3{}test$#');
});
it ('Incremental Find Previous', async () => {
await page.evaluate(`window.term.writeln('package.jsonc\\n')`);
await writeSync('package.json pack package.lock');
await page.evaluate(`window.search.findPrevious('pack', {incremental: true})`);
let line: string = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let selectionPosition: {startColumn: number, startRow: number, endColumn: number, endRow: number} = await page.evaluate(`window.term.getSelectionPosition()`);
// We look further ahead in the line to ensure that pack was selected from package.lock
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 8), 'package.lock');
await page.evaluate(`window.search.findPrevious('package.j', {incremental: true})`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 3), 'package.json');
await page.evaluate(`window.search.findPrevious('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
line = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn), 'package.jsonc');
});
it ('Incremental Find Next', async () => {
await page.evaluate(`window.term.writeln('package.lock pack package.json package.ups\\n')`);
await writeSync('package.jsonc');
await page.evaluate(`window.search.findNext('pack', {incremental: true})`);
let line: string = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
let selectionPosition: {startColumn: number, startRow: number, endColumn: number, endRow: number} = await page.evaluate(`window.term.getSelectionPosition()`);
// We look further ahead in the line to ensure that pack was selected from package.lock
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 8), 'package.lock');
await page.evaluate(`window.search.findNext('package.j', {incremental: true})`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn + 3), 'package.json');
await page.evaluate(`window.search.findNext('package.jsonc', {incremental: true})`);
// We have to reevaluate line because it should have switched starting rows at this point
line = await page.evaluate(`window.term.buffer.getLine(window.term.getSelectionPosition().startRow).translateToString()`);
selectionPosition = await page.evaluate(`window.term.getSelectionPosition()`);
assert.deepEqual(line.substring(selectionPosition.startColumn, selectionPosition.endColumn), 'package.jsonc');
});
it ('Simple Regex', async () => {
await writeSync('abc123defABCD');
await page.evaluate(`window.search.findNext('[a-z]+', {regex: true})`);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc');
await page.evaluate(`window.search.findNext('[A-Z]+', {regex: true, caseSensitive: true})`);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'ABCD');
});
it('Search for single result twice should not unselect it', async () => {
await writeSync('abc def');
assert.deepEqual(await page.evaluate(`window.search.findNext('abc')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc');
assert.deepEqual(await page.evaluate(`window.search.findNext('abc')`), true);
assert.deepEqual(await page.evaluate(`window.term.getSelection()`), 'abc');
});
});
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
if (options.rendererType === 'dom') {
await page.waitForSelector('.xterm-rows');
} else {
await page.waitForSelector('.xterm-text-layer');
}
}
async function writeSync(data: string): Promise<void> {
return page.evaluate(`new Promise(resolve => window.term.write('${data}', resolve))`);
}
function makeData(length: number): string {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
@@ -3,30 +3,43 @@
* @license MIT
*/
import { ISearchHelper, ISearchAddonTerminal, ISearchOptions, ISearchResult } from './Interfaces';
import { IDisposable } from 'xterm';
import { Terminal, IDisposable, ITerminalAddon, ISelectionPosition } from 'xterm';
export interface ISearchOptions {
regex?: boolean;
wholeWord?: boolean;
caseSensitive?: boolean;
incremental?: boolean;
}
export interface ISearchResult {
term: string;
col: number;
row: number;
}
const NON_WORD_CHARACTERS = ' ~!@#$%^&*()+`-=[]{}|\;:"\',./<>?';
const LINES_CACHE_TIME_TO_LIVE = 15 * 1000; // 15 secs
/**
* A class that knows how to search the terminal and how to display the results.
*/
export class SearchHelper implements ISearchHelper {
export class SearchAddon implements ITerminalAddon {
private _terminal: Terminal | undefined;
/**
* translateBufferLineToStringWithWrap is a fairly expensive call.
* We memoize the calls into an array that has a time based ttl.
* _linesCache is also invalidated when the terminal cursor moves.
*/
private _linesCache: string[] = null;
private _linesCache: string[] | undefined;
private _linesCacheTimeoutId = 0;
private _cursorMoveListener: IDisposable | undefined;
private _resizeListener: IDisposable | undefined;
constructor(private _terminal: ISearchAddonTerminal) {
this._destroyLinesCache = this._destroyLinesCache.bind(this);
public activate(terminal: Terminal): void {
this._terminal = terminal;
}
public dispose(): void { }
/**
* Find the next instance of the term, then scroll to and select it. If it
* doesn't exist, do nothing.
@@ -35,47 +48,36 @@ export class SearchHelper implements ISearchHelper {
* @return Whether a result was found.
*/
public findNext(term: string, searchOptions?: ISearchOptions): boolean {
const selectionManager = this._terminal._core.selectionManager;
const {incremental} = searchOptions;
let result: ISearchResult;
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
if (!term || term.length === 0) {
selectionManager.clearSelection();
this._terminal.clearSelection();
return false;
}
let startCol: number = 0;
let startRow = this._terminal._core.buffer.ydisp;
if (selectionManager.selectionEnd) {
let startCol = 0;
let startRow = 0;
let currentSelection: ISelectionPosition | undefined;
if (this._terminal.hasSelection()) {
const incremental = searchOptions ? searchOptions.incremental : false;
// Start from the selection end if there is a selection
// For incremental search, use existing row
if (this._terminal.getSelection().length !== 0) {
startRow = incremental ? selectionManager.selectionStart[1] : selectionManager.selectionEnd[1];
startCol = incremental ? selectionManager.selectionStart[0] : selectionManager.selectionEnd[0];
}
currentSelection = this._terminal.getSelectionPosition()!;
startRow = incremental ? currentSelection.startRow : currentSelection.endRow;
startCol = incremental ? currentSelection.startColumn : currentSelection.endColumn;
}
this._initLinesCache();
// A row that has isWrapped = false
let findingRow = startRow;
// index of beginning column that _findInLine need to scan.
let cumulativeCols = startCol;
// If startRow is wrapped row, scan for unwrapped row above.
// So we can start matching on wrapped line from long unwrapped line.
while (this._terminal._core.buffer.lines.get(findingRow).isWrapped) {
findingRow--;
cumulativeCols += this._terminal.cols;
}
// Search startRow
result = this._findInLine(term, findingRow, cumulativeCols, searchOptions);
let result = this._findInLine(term, startRow, startCol, searchOptions);
// Search from startRow + 1 to end
if (!result) {
for (let y = startRow + 1; y < this._terminal._core.buffer.ybase + this._terminal.rows; y++) {
for (let y = startRow + 1; y < this._terminal.buffer.baseY + this._terminal.rows; y++) {
// If the current line is wrapped line, increase index of column to ignore the previous scan
// Otherwise, reset beginning column index to zero with set new unwrapped line index
@@ -85,11 +87,9 @@ export class SearchHelper implements ISearchHelper {
}
}
}
// Search from the top to the startRow (search the whole startRow again in
// case startCol > 0)
if (!result) {
for (let y = 0; y < findingRow; y++) {
// If we hit the bottom and didn't search from the very top wrap back up
if (!result && startRow !== 0) {
for (let y = 0; y < startRow; y++) {
result = this._findInLine(term, y, 0, searchOptions);
if (result) {
break;
@@ -97,6 +97,9 @@ export class SearchHelper implements ISearchHelper {
}
}
// If there is only one result, return true.
if (!result && currentSelection) return true;
// Set selection and scroll if a result was found
return this._selectResult(result);
}
@@ -109,71 +112,61 @@ export class SearchHelper implements ISearchHelper {
* @return Whether a result was found.
*/
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean {
const selectionManager = this._terminal._core.selectionManager;
let result: ISearchResult;
if (!this._terminal) {
throw new Error('Cannot use addon until it has been loaded');
}
if (!term || term.length === 0) {
selectionManager.clearSelection();
this._terminal.clearSelection();
return false;
}
const isReverseSearch = true;
let startRow = this._terminal._core.buffer.ydisp + this._terminal.rows - 1;
let startRow = this._terminal.buffer.baseY + this._terminal.rows;
let startCol = this._terminal.cols;
if (selectionManager.selectionStart) {
// Start from the selection start if there is a selection
if (this._terminal.getSelection().length !== 0) {
startRow = selectionManager.selectionStart[1];
startCol = selectionManager.selectionStart[0];
}
let result: ISearchResult | undefined;
const incremental = searchOptions ? searchOptions.incremental : false;
let currentSelection: ISelectionPosition | undefined;
if (this._terminal.hasSelection()) {
currentSelection = this._terminal.getSelectionPosition()!;
// Start from selection start if there is a selection
startRow = currentSelection.startRow;
startCol = currentSelection.startColumn;
}
this._initLinesCache();
// Search startRow
result = this._findInLine(term, startRow, startCol, searchOptions, isReverseSearch);
if (incremental) {
result = this._findInLine(term, startRow, startCol, searchOptions, false);
if (!(result && result.row === startRow && result.col === startCol)) {
result = this._findInLine(term, startRow, startCol, searchOptions, true);
}
} else {
result = this._findInLine(term, startRow, startCol, searchOptions, isReverseSearch);
}
// Search from startRow - 1 to top
if (!result) {
// If the line is wrapped line, increase number of columns that is needed to be scanned
// Se we can scan on wrapped line from unwrapped line
let cumulativeCols = this._terminal.cols;
if (this._terminal._core.buffer.lines.get(startRow).isWrapped) {
cumulativeCols += startCol;
}
startCol = this._terminal.cols;
for (let y = startRow - 1; y >= 0; y--) {
result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch);
result = this._findInLine(term, y, startCol, searchOptions, isReverseSearch);
if (result) {
break;
}
// If the current line is wrapped line, increase scanning range,
// preparing for scanning on unwrapped line
if (this._terminal._core.buffer.lines.get(y).isWrapped) {
cumulativeCols += this._terminal.cols;
} else {
cumulativeCols = this._terminal.cols;
}
}
// If we hit the top and didn't search from the very bottom wrap back down
if (!result && startRow !== (this._terminal.buffer.baseY + this._terminal.rows)) {
for (let y = (this._terminal.buffer.baseY + this._terminal.rows); y > startRow; y--) {
result = this._findInLine(term, y, startCol, searchOptions, isReverseSearch);
if (result) {
break;
}
}
}
// Search from the bottom to startRow (search the whole startRow again in
// case startCol > 0)
if (!result) {
const searchFrom = this._terminal._core.buffer.ybase + this._terminal.rows - 1;
let cumulativeCols = this._terminal.cols;
for (let y = searchFrom; y >= startRow; y--) {
result = this._findInLine(term, y, cumulativeCols, searchOptions, isReverseSearch);
if (result) {
break;
}
if (this._terminal._core.buffer.lines.get(y).isWrapped) {
cumulativeCols += this._terminal.cols;
} else {
cumulativeCols = this._terminal.cols;
}
}
}
// If there is only one result, return true.
if (!result && currentSelection) return true;
// Set selection and scroll if a result was found
return this._selectResult(result);
@@ -183,10 +176,11 @@ export class SearchHelper implements ISearchHelper {
* Sets up a line cache with a ttl
*/
private _initLinesCache(): void {
const terminal = this._terminal!;
if (!this._linesCache) {
this._linesCache = new Array(this._terminal._core.buffer.length);
this._cursorMoveListener = this._terminal.onCursorMove(() => this._destroyLinesCache());
this._resizeListener = this._terminal.onResize(() => this._destroyLinesCache());
this._linesCache = new Array(terminal.buffer.length);
this._cursorMoveListener = terminal.onCursorMove(() => this._destroyLinesCache());
this._resizeListener = terminal.onResize(() => this._destroyLinesCache());
}
window.clearTimeout(this._linesCacheTimeoutId);
@@ -194,7 +188,7 @@ export class SearchHelper implements ISearchHelper {
}
private _destroyLinesCache(): void {
this._linesCache = null;
this._linesCache = undefined;
if (this._cursorMoveListener) {
this._cursorMoveListener.dispose();
this._cursorMoveListener = undefined;
@@ -217,7 +211,7 @@ export class SearchHelper implements ISearchHelper {
*/
private _isWholeWord(searchIndex: number, line: string, term: string): boolean {
return (((searchIndex === 0) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex - 1]) !== -1)) &&
(((searchIndex + term.length) === line.length) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex + term.length]) !== -1)));
(((searchIndex + term.length) === line.length) || (NON_WORD_CHARACTERS.indexOf(line[searchIndex + term.length]) !== -1)));
}
/**
@@ -231,15 +225,17 @@ export class SearchHelper implements ISearchHelper {
* @param searchOptions Search options.
* @return The search result if it was found.
*/
protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult {
protected _findInLine(term: string, row: number, col: number, searchOptions: ISearchOptions = {}, isReverseSearch: boolean = false): ISearchResult | undefined {
const terminal = this._terminal!;
// Ignore wrapped lines, only consider on unwrapped line (first row of command string).
if (this._terminal._core.buffer.lines.get(row).isWrapped) {
const firstLine = terminal.buffer.getLine(row);
if (firstLine && firstLine.isWrapped) {
return;
}
let stringLine = this._linesCache ? this._linesCache[row] : void 0;
if (stringLine === void 0) {
stringLine = this.translateBufferLineToStringWithWrap(row, true);
stringLine = this._translateBufferLineToStringWithWrap(row, true);
if (this._linesCache) {
this._linesCache[row] = stringLine;
}
@@ -251,7 +247,7 @@ export class SearchHelper implements ISearchHelper {
let resultIndex = -1;
if (searchOptions.regex) {
const searchRegex = RegExp(searchTerm, 'g');
let foundTerm: RegExpExecArray;
let foundTerm: RegExpExecArray | null;
if (isReverseSearch) {
// This loop will get the resultIndex of the _last_ regex match in the range 0..col
while (foundTerm = searchRegex.exec(searchStringLine.slice(0, col))) {
@@ -278,28 +274,33 @@ export class SearchHelper implements ISearchHelper {
if (resultIndex >= 0) {
// Adjust the row number and search index if needed since a "line" of text can span multiple rows
if (resultIndex >= this._terminal.cols) {
row += Math.floor(resultIndex / this._terminal.cols);
resultIndex = resultIndex % this._terminal.cols;
if (resultIndex >= terminal.cols) {
row += Math.floor(resultIndex / terminal.cols);
resultIndex = resultIndex % terminal.cols;
}
if (searchOptions.wholeWord && !this._isWholeWord(resultIndex, searchStringLine, term)) {
return;
}
const line = this._terminal._core.buffer.lines.get(row);
const line = terminal.buffer.getLine(row);
for (let i = 0; i < resultIndex; i++) {
const charData = line.get(i);
// Adjust the searchIndex to normalize emoji into single chars
const char = charData[1/*CHAR_DATA_CHAR_INDEX*/];
if (char.length > 1) {
resultIndex -= char.length - 1;
}
// Adjust the searchIndex for empty characters following wide unicode
// chars (eg. CJK)
const charWidth = charData[2/*CHAR_DATA_WIDTH_INDEX*/];
if (charWidth === 0) {
resultIndex++;
if (line) {
for (let i = 0; i < resultIndex; i++) {
const cell = line.getCell(i);
if (!cell) {
break;
}
// Adjust the searchIndex to normalize emoji into single chars
const char = cell.char;
if (char.length > 1) {
resultIndex -= char.length - 1;
}
// Adjust the searchIndex for empty characters following wide unicode
// chars (eg. CJK)
const charWidth = cell.width;
if (charWidth === 0) {
resultIndex++;
}
}
}
return {
@@ -309,6 +310,7 @@ export class SearchHelper implements ISearchHelper {
};
}
}
/**
* Translates a buffer line to a string, including subsequent lines if they are wraps.
* Wide characters will count as two columns in the resulting string. This
@@ -317,14 +319,19 @@ export class SearchHelper implements ISearchHelper {
* @param line The line being translated.
* @param trimRight Whether to trim whitespace to the right.
*/
public translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean): string {
private _translateBufferLineToStringWithWrap(lineIndex: number, trimRight: boolean): string {
const terminal = this._terminal!;
let lineString = '';
let lineWrapsToNext: boolean;
do {
const nextLine = this._terminal._core.buffer.lines.get(lineIndex + 1);
const nextLine = terminal.buffer.getLine(lineIndex + 1);
lineWrapsToNext = nextLine ? nextLine.isWrapped : false;
lineString += this._terminal._core.buffer.translateBufferLineToString(lineIndex, !lineWrapsToNext && trimRight).substring(0, this._terminal.cols);
const line = terminal.buffer.getLine(lineIndex);
if (!line) {
break;
}
lineString += line.translateToString(!lineWrapsToNext && trimRight).substring(0, terminal.cols);
lineIndex++;
} while (lineWrapsToNext);
@@ -336,13 +343,19 @@ export class SearchHelper implements ISearchHelper {
* @param result The result to select.
* @return Whethera result was selected.
*/
private _selectResult(result: ISearchResult): boolean {
private _selectResult(result: ISearchResult | undefined): boolean {
const terminal = this._terminal!;
if (!result) {
this._terminal.clearSelection();
terminal.clearSelection();
return false;
}
this._terminal._core.selectionManager.setSelection(result.col, result.row, result.term.length);
this._terminal.scrollLines(result.row - this._terminal._core.buffer.ydisp);
terminal.select(result.col, result.row, result.term.length);
// If it is not in the viewport then we scroll else it just gets selected
if (result.row >= (terminal.buffer.viewportY + terminal.rows) || result.row < terminal.buffer.viewportY) {
let scroll = result.row - terminal.buffer.viewportY;
scroll = scroll - Math.floor(terminal.rows / 2);
terminal.scrollLines(scroll);
}
return true;
}
}
@@ -7,13 +7,13 @@
"es6",
],
"rootDir": ".",
"outDir": "../../../lib/addons/attach/",
"outDir": "../out",
"sourceMap": true,
"removeComments": true,
"declaration": true
"strict": true
},
"include": [
"**/*.ts",
"./**/*",
"../../../typings/xterm.d.ts"
]
}
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ILinkMatcherOptions, IDisposable, ITerminalAddon } from 'xterm';
declare module 'xterm-addon-search' {
/**
* Options for a search.
*/
export interface ISearchOptions {
/**
* Whether the search term is a regex.
*/
regex?: boolean;
/**
* Whether to search for a whole word, the result is only valid if it's
* suppounded in "non-word" characters such as `_`, `(`, `)` or space.
*/
wholeWord?: boolean;
/**
* Whether the search is case sensitive.
*/
caseSensitive?: boolean;
/**
* Whether to do an indcremental search, this will expand the selection if it
* still matches the term the user typed. Note that this only affects
* `findNext`, not `findPrevious`.
*/
incremental?: boolean;
}
/**
* An xterm.js addon that provides search functionality.
*/
export class SearchAddon implements ITerminalAddon {
/**
* Activates the addon
* @param terminal The terminal the addon is being loaded in.
*/
public activate(terminal: Terminal): void;
/**
* Disposes the addon.
*/
public dispose(): void;
/**
* Search forwards for the next result that matches the search term and
* options.
* @param term The search term.
* @param searchOptions The options for the search.
*/
public findNext(term: string, searchOptions?: ISearchOptions): boolean;
/**
* Search backwards for the previous result that matches the search term and
* options.
* @param term The search term.
* @param searchOptions The options for the search.
*/
public findPrevious(term: string, searchOptions?: ISearchOptions): boolean;
}
}
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const path = require('path');
const addonName = 'SearchAddon';
const mainFile = 'xterm-addon-search.js';
module.exports = {
entry: `./out/${addonName}.js`,
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: /node_modules/
}
]
},
output: {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
},
mode: 'production'
};
+2
View File
@@ -0,0 +1,2 @@
lib
node_modules
+5
View File
@@ -0,0 +1,5 @@
**/*.api.js
**/*.api.ts
tsconfig.json
.yarnrc
webpack.config.js
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)
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.
+21
View File
@@ -0,0 +1,21 @@
## xterm-addon-web-links
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables web links. This addon requires xterm.js v4+.
### Install
```bash
npm install --save xterm-addon-web-links
```
### Usage
```ts
import { Terminal } from 'xterm';
import { WebLinksAddon } from 'xterm-addon-web-links';
const terminal = new Terminal();
terminal.loadAddon(new WebLinksAddon());
```
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-web-links/typings/xterm-addon-web-links.d.ts) for more advanced usage.
+21
View File
@@ -0,0 +1,21 @@
{
"name": "xterm-addon-web-links",
"version": "0.2.1",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-web-links.js",
"types": "typings/xterm-addon-web-links.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"scripts": {
"build": "../../node_modules/.bin/tsc -p src",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^4.0.0"
}
}
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import * as puppeteer from 'puppeteer';
import { assert } from 'chai';
import { ITerminalOptions } from 'xterm';
const APP = 'http://127.0.0.1:3000/test';
let browser: puppeteer.Browser;
let page: puppeteer.Page;
const width = 800;
const height = 600;
describe('WebLinksAddon', () => {
before(async function(): Promise<any> {
this.timeout(10000);
browser = await puppeteer.launch({
headless: process.argv.indexOf('--headless') !== -1,
slowMo: 80,
args: [`--window-size=${width},${height}`, `--no-sandbox`]
});
page = (await browser.pages())[0];
await page.setViewport({ width, height });
});
after(async () => {
await browser.close();
});
beforeEach(async function(): Promise<any> {
this.timeout(5000);
await page.goto(APP);
});
it('.com', async function(): Promise<any> {
this.timeout(20000);
await testHostName('foo.com');
});
it('.com.au', async function(): Promise<any> {
this.timeout(20000);
await testHostName('foo.com.au');
});
it('.io', async function(): Promise<any> {
this.timeout(20000);
await testHostName('foo.io');
});
});
async function testHostName(hostname: string): Promise<void> {
await openTerminal({ rendererType: 'dom' });
await page.evaluate(`window.term.loadAddon(new window.WebLinksAddon())`);
await page.evaluate(`
window.term.writeln(' http://${hostname} ');
window.term.writeln(' http://${hostname}/a~b#c~d?e~f ');
window.term.writeln(' http://${hostname}/colon:test ');
window.term.writeln(' http://${hostname}/colon:test: ');
window.term.writeln('"http://${hostname}/"');
window.term.writeln('\\'http://${hostname}/\\'');
window.term.writeln('http://${hostname}/subpath/+/id');
`);
assert.equal(await getLinkAtCell(3, 1), `http://${hostname}`);
assert.equal(await getLinkAtCell(3, 2), `http://${hostname}/a~b#c~d?e~f`);
assert.equal(await getLinkAtCell(3, 3), `http://${hostname}/colon:test`);
assert.equal(await getLinkAtCell(3, 4), `http://${hostname}/colon:test`);
assert.equal(await getLinkAtCell(2, 5), `http://${hostname}/`);
assert.equal(await getLinkAtCell(2, 6), `http://${hostname}/`);
assert.equal(await getLinkAtCell(1, 7), `http://${hostname}/subpath/+/id`);
}
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
if (options.rendererType === 'dom') {
await page.waitForSelector('.xterm-rows');
} else {
await page.waitForSelector('.xterm-text-layer');
}
}
async function getLinkAtCell(col: number, row: number): Promise<string> {
const rowSelector = `.xterm-rows > :nth-child(${row})`;
await page.hover(`${rowSelector} > :nth-child(${col})`);
return await page.evaluate(`Array.prototype.reduce.call(document.querySelectorAll('${rowSelector} > span[style]'), (a, b) => a + b.textContent, '');`);
}
@@ -3,7 +3,7 @@
* @license MIT
*/
import { Terminal, ILinkMatcherOptions } from 'xterm';
import { Terminal, ILinkMatcherOptions, ITerminalAddon } from 'xterm';
const protocolClause = '(https?:\\/\\/)';
const domainCharacterSet = '[\\da-z\\.-]+';
@@ -14,7 +14,7 @@ const ipClause = '((\\d{1,3}\\.){3}\\d{1,3})';
const localHostClause = '(localhost)';
const portClause = '(:\\d{1,5})';
const hostClause = '((' + domainBodyClause + '\\.' + tldClause + ')|' + ipClause + '|' + localHostClause + ')' + portClause + '?';
const pathCharacterSet = '(\\/[\\/\\w\\.\\-%~:]*)*([^:"\'\\s])';
const pathCharacterSet = '(\\/[\\/\\w\\.\\-%~:+]*)*([^:"\'\\s])';
const pathClause = '(' + pathCharacterSet + ')?';
const queryStringHashFragmentCharacterSet = '[0-9\\w\\[\\]\\(\\)\\/\\?\\!#@$%&\'*+,:;~\\=\\.\\-]*';
const queryStringClause = '(\\?' + queryStringHashFragmentCharacterSet + ')?';
@@ -29,19 +29,25 @@ function handleLink(event: MouseEvent, uri: string): void {
window.open(uri, '_blank');
}
/**
* Initialize the web links addon, registering the link matcher.
* @param term The terminal to use web links within.
* @param handler A custom handler to use.
* @param options Custom options to use, matchIndex will always be ignored.
*/
export function webLinksInit(term: Terminal, handler: (event: MouseEvent, uri: string) => void = handleLink, options: ILinkMatcherOptions = {}): void {
options.matchIndex = 1;
term.registerLinkMatcher(strictUrlRegex, handler, options);
}
export class WebLinksAddon implements ITerminalAddon {
private _linkMatcherId: number | undefined;
private _terminal: Terminal | undefined;
export function apply(terminalConstructor: typeof Terminal): void {
(<any>terminalConstructor.prototype).webLinksInit = function (handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void {
webLinksInit(this, handler, options);
};
constructor(
private _handler: (event: MouseEvent, uri: string) => void = handleLink,
private _options: ILinkMatcherOptions = {}
) {
this._options.matchIndex = 1;
}
public activate(terminal: Terminal): void {
this._terminal = terminal;
this._linkMatcherId = this._terminal.registerLinkMatcher(strictUrlRegex, this._handler, this._options);
}
public dispose(): void {
if (this._linkMatcherId !== undefined && this._terminal !== undefined) {
this._terminal.deregisterLinkMatcher(this._linkMatcherId);
}
}
}
@@ -4,19 +4,16 @@
"target": "es5",
"lib": [
"dom",
"es5"
"es2015"
],
"rootDir": ".",
"outDir": "../../../lib/addons/search/",
"outDir": "../out",
"sourceMap": true,
"removeComments": true,
"declaration": true,
"types": [
"../../node_modules/@types/mocha"
]
"strict": true
},
"include": [
"**/*.ts",
"./**/*",
"../../../typings/xterm.d.ts"
]
}
@@ -0,0 +1,32 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ILinkMatcherOptions, ITerminalAddon } from 'xterm';
declare module 'xterm-addon-web-links' {
/**
* An xterm.js addon that enables web links.
*/
export class WebLinksAddon implements ITerminalAddon {
/**
* Creates a new web links addon.
* @param handler The callback when the link is called.
* @param options Options for the link matcher.
*/
constructor(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions);
/**
* Activates the addon
* @param terminal The terminal the addon is being loaded in.
*/
public activate(terminal: Terminal): void;
/**
* Disposes the addon.
*/
public dispose(): void;
}
}
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const path = require('path');
const addonName = 'WebLinksAddon';
const mainFile = 'xterm-addon-web-links.js';
module.exports = {
entry: `./out/${addonName}.js`,
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: /node_modules/
}
]
},
output: {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
},
mode: 'production'
};
+2
View File
@@ -0,0 +1,2 @@
lib
node_modules
+5
View File
@@ -0,0 +1,5 @@
**/*.api.js
**/*.api.ts
tsconfig.json
.yarnrc
webpack.config.js
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) 2018, The xterm.js authors (https://github.com/xtermjs/xterm.js)
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.
+23
View File
@@ -0,0 +1,23 @@
## xterm-addon-webgl
An addon for [xterm.js](https://github.com/xtermjs/xterm.js) that enables a WebGL-based renderer. This addon requires xterm.js v4+.
⚠️ This is an experimental addon that is [missing some features and may be unstable](https://github.com/xtermjs/xterm.js/issues?q=is%3Aopen+is%3Aissue+label%3Aarea%2Faddon%2Fwebgl) ⚠️
### Install
```bash
npm install --save xterm-addon-webgl
```
### Usage
```ts
import { Terminal } from 'xterm';
import { WebglAddon } from 'xterm-addon-webgl';
const terminal = new Terminal();
terminal.loadAddon(new WebglAddon());
```
See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts) for more advanced usage.
+21
View File
@@ -0,0 +1,21 @@
{
"name": "xterm-addon-webgl",
"version": "0.3.0",
"author": {
"name": "The xterm.js authors",
"url": "https://xtermjs.org/"
},
"main": "lib/xterm-addon-webgl.js",
"types": "typings/xterm-addon-webgl.d.ts",
"repository": "https://github.com/xtermjs/xterm.js",
"license": "MIT",
"scripts": {
"build": "../../node_modules/.bin/tsc -p src",
"prepackage": "npm run build",
"package": "../../node_modules/.bin/webpack",
"prepublishOnly": "npm run package"
},
"peerDependencies": {
"xterm": "^4.0.0"
}
}
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { CellData } from 'common/buffer/CellData';
import { FLAGS } from './Constants';
import { IBufferLine } from 'common/Types';
export function getCompatAttr(bufferLine: IBufferLine, index: number): number {
// TODO: Need to move WebGL over to the new system and remove this block
const cell = new CellData();
bufferLine.loadCell(index, cell);
const oldBg = cell.getBgColor() === -1 ? 256 : cell.getBgColor();
const oldFg = cell.getFgColor() === -1 ? 256 : cell.getFgColor();
const oldAttr =
(cell.isBold() ? FLAGS.BOLD : 0) |
(cell.isUnderline() ? FLAGS.UNDERLINE : 0) |
(cell.isBlink() ? FLAGS.BLINK : 0) |
(cell.isInverse() ? FLAGS.INVERSE : 0) |
(cell.isDim() ? FLAGS.DIM : 0) |
(cell.isItalic() ? FLAGS.ITALIC : 0);
const attrCompat =
oldBg |
(oldFg << 9) |
(oldAttr << 18);
return attrCompat;
}
@@ -0,0 +1,14 @@
/**
* @license MIT
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
*/
import { IColor } from 'browser/Types';
export function getLuminance(color: IColor): number {
// Coefficients taken from: https://www.w3.org/TR/AERT/#color-contrast
const r = color.rgba >> 24 & 0xff;
const g = color.rgba >> 16 & 0xff;
const b = color.rgba >> 8 & 0xff;
return (0.299 * r + 0.587 * g + 0.114 * b) / 255;
}
+15
View File
@@ -0,0 +1,15 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
// TODO: Should be removed after chardata workaround is fixed
export const enum FLAGS {
BOLD = 1,
UNDERLINE = 2,
BLINK = 4,
INVERSE = 8,
INVISIBLE = 16,
DIM = 32,
ITALIC = 64
}
@@ -0,0 +1,371 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { createProgram, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils';
import { WebglCharAtlas } from './atlas/WebglCharAtlas';
import { IWebGL2RenderingContext, IWebGLVertexArrayObject, IRenderModel, IRasterizedGlyph } from './Types';
import { INDICIES_PER_CELL } from './WebglRenderer';
import { COMBINED_CHAR_BIT_MASK } from './RenderModel';
import { fill } from 'common/TypedArrayUtils';
import { slice } from './TypedArray';
import { NULL_CELL_CODE, WHITESPACE_CELL_CODE } from 'common/buffer/Constants';
import { getLuminance } from './ColorUtils';
import { Terminal, IBufferLine } from 'xterm';
import { IColorSet } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
interface IVertices {
attributes: Float32Array;
/**
* These buffers are the ones used to bind to WebGL, the reason there are
* multiple is to allow double buffering to work as you cannot modify the
* buffer while it's being used by the GPU. Having multiple lets us start
* working on the next frame.
*/
attributesBuffers: Float32Array[];
selectionAttributes: Float32Array;
count: number;
}
const enum VertexAttribLocations {
UNIT_QUAD = 0,
CELL_POSITION = 1,
OFFSET = 2,
SIZE = 3,
TEXCOORD = 4,
TEXSIZE = 5
}
const vertexShaderSource = `#version 300 es
layout (location = ${VertexAttribLocations.UNIT_QUAD}) in vec2 a_unitquad;
layout (location = ${VertexAttribLocations.CELL_POSITION}) in vec2 a_cellpos;
layout (location = ${VertexAttribLocations.OFFSET}) in vec2 a_offset;
layout (location = ${VertexAttribLocations.SIZE}) in vec2 a_size;
layout (location = ${VertexAttribLocations.TEXCOORD}) in vec2 a_texcoord;
layout (location = ${VertexAttribLocations.TEXSIZE}) in vec2 a_texsize;
uniform mat4 u_projection;
uniform vec2 u_resolution;
out vec2 v_texcoord;
void main() {
vec2 zeroToOne = (a_offset / u_resolution) + a_cellpos + (a_unitquad * a_size);
gl_Position = u_projection * vec4(zeroToOne, 0.0, 1.0);
v_texcoord = a_texcoord + a_unitquad * a_texsize;
}`;
const fragmentShaderSource = `#version 300 es
precision lowp float;
in vec2 v_texcoord;
uniform sampler2D u_texture;
out vec4 outColor;
void main() {
outColor = texture(u_texture, v_texcoord);
}`;
const INDICES_PER_CELL = 10;
const BYTES_PER_CELL = INDICES_PER_CELL * Float32Array.BYTES_PER_ELEMENT;
const CELL_POSITION_INDICES = 2;
export class GlyphRenderer {
private _atlas: WebglCharAtlas | undefined;
private _program: WebGLProgram;
private _vertexArrayObject: IWebGLVertexArrayObject;
private _projectionLocation: WebGLUniformLocation;
private _resolutionLocation: WebGLUniformLocation;
private _textureLocation: WebGLUniformLocation;
private _atlasTexture: WebGLTexture;
private _attributesBuffer: WebGLBuffer;
private _activeBuffer: number = 0;
private _vertices: IVertices = {
count: 0,
attributes: new Float32Array(0),
attributesBuffers: [
new Float32Array(0),
new Float32Array(0)
],
selectionAttributes: new Float32Array(0)
};
constructor(
private _terminal: Terminal,
private _colors: IColorSet,
private _gl: IWebGL2RenderingContext,
private _dimensions: IRenderDimensions
) {
const gl = this._gl;
const program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource));
this._program = program;
// Uniform locations
this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection'));
this._resolutionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_resolution'));
this._textureLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_texture'));
// Create and set the vertex array object
this._vertexArrayObject = gl.createVertexArray();
gl.bindVertexArray(this._vertexArrayObject);
// Setup a_unitquad, this defines the 4 vertices of a rectangle
const unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
const unitQuadVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, unitQuadVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, unitQuadVertices, gl.STATIC_DRAW);
gl.enableVertexAttribArray(VertexAttribLocations.UNIT_QUAD);
gl.vertexAttribPointer(VertexAttribLocations.UNIT_QUAD, 2, this._gl.FLOAT, false, 0, 0);
// Setup the unit quad element array buffer, this points to indices in
// unitQuadVertuces to allow is to draw 2 triangles from the vertices
const unitQuadElementIndices = new Uint8Array([0, 1, 3, 0, 2, 3]);
const elementIndicesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementIndicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW);
// Setup attributes
this._attributesBuffer = throwIfFalsy(gl.createBuffer());
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.enableVertexAttribArray(VertexAttribLocations.OFFSET);
gl.vertexAttribPointer(VertexAttribLocations.OFFSET, 2, gl.FLOAT, false, BYTES_PER_CELL, 0);
gl.vertexAttribDivisor(VertexAttribLocations.OFFSET, 1);
gl.enableVertexAttribArray(VertexAttribLocations.SIZE);
gl.vertexAttribPointer(VertexAttribLocations.SIZE, 2, gl.FLOAT, false, BYTES_PER_CELL, 2 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.SIZE, 1);
gl.enableVertexAttribArray(VertexAttribLocations.TEXCOORD);
gl.vertexAttribPointer(VertexAttribLocations.TEXCOORD, 2, gl.FLOAT, false, BYTES_PER_CELL, 4 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.TEXCOORD, 1);
gl.enableVertexAttribArray(VertexAttribLocations.TEXSIZE);
gl.vertexAttribPointer(VertexAttribLocations.TEXSIZE, 2, gl.FLOAT, false, BYTES_PER_CELL, 6 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.TEXSIZE, 1);
gl.enableVertexAttribArray(VertexAttribLocations.CELL_POSITION);
gl.vertexAttribPointer(VertexAttribLocations.CELL_POSITION, 2, gl.FLOAT, false, BYTES_PER_CELL, 8 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.CELL_POSITION, 1);
// Setup empty texture atlas
this._atlasTexture = throwIfFalsy(gl.createTexture());
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
// Allow drawing of transparent texture
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
// Set viewport
this.onResize();
}
public beginFrame(): boolean {
return this._atlas ? this._atlas.beginFrame() : true;
}
public updateCell(x: number, y: number, code: number, attr: number, bg: number, fg: number, chars: string): void {
this._updateCell(this._vertices.attributes, x, y, code, attr, bg, fg, chars);
}
private _updateCell(array: Float32Array, x: number, y: number, code: number | undefined, attr: number, bg: number, fg: number, chars?: string): void {
const terminal = this._terminal;
const i = (y * terminal.cols + x) * INDICES_PER_CELL;
// Exit early if this is a null/space character
if (code === NULL_CELL_CODE || code === WHITESPACE_CELL_CODE || code === undefined/* This is used for the right side of wide chars */) {
fill(array, 0, i, i + INDICES_PER_CELL - 1 - CELL_POSITION_INDICES);
return;
}
let rasterizedGlyph: IRasterizedGlyph;
if (!this._atlas) {
throw new Error('atlas must be set before updating cell');
}
if (chars && chars.length > 1) {
rasterizedGlyph = this._atlas.getRasterizedGlyphCombinedChar(chars, attr, bg, fg);
} else {
rasterizedGlyph = this._atlas.getRasterizedGlyph(code, attr, bg, fg);
}
// Fill empty if no glyph was found
if (!rasterizedGlyph) {
fill(array, 0, i, i + INDICES_PER_CELL - 1 - CELL_POSITION_INDICES);
return;
}
// a_origin
array[i ] = -rasterizedGlyph.offset.x + this._dimensions.scaledCharLeft;
array[i + 1] = -rasterizedGlyph.offset.y + this._dimensions.scaledCharTop;
// a_size
array[i + 2] = rasterizedGlyph.size.x / this._dimensions.scaledCanvasWidth;
array[i + 3] = rasterizedGlyph.size.y / this._dimensions.scaledCanvasHeight;
// a_texcoord
array[i + 4] = rasterizedGlyph.texturePositionClipSpace.x;
array[i + 5] = rasterizedGlyph.texturePositionClipSpace.y;
// a_texsize
array[i + 6] = rasterizedGlyph.sizeClipSpace.x;
array[i + 7] = rasterizedGlyph.sizeClipSpace.y;
// a_cellpos only changes on resize
}
public updateSelection(model: IRenderModel, columnSelectMode: boolean): void {
const terminal = this._terminal;
this._vertices.selectionAttributes = slice(this._vertices.attributes, 0);
// TODO: Make fg and bg configurable, currently since the buffer doesn't
// support truecolor the char atlas cannot store it.
const lumi = getLuminance(this._colors.background);
const fg = lumi > 0.5 ? 7 : 0;
const bg = lumi > 0.5 ? 0 : 7;
if (columnSelectMode) {
const startCol = model.selection.startCol;
const width = model.selection.endCol - startCol;
const height = model.selection.viewportCappedEndRow - model.selection.viewportCappedStartRow + 1;
for (let y = model.selection.viewportCappedStartRow; y < model.selection.viewportCappedStartRow + height; y++) {
this._updateSelectionRange(startCol, startCol + width, y, model, bg, fg);
}
} else {
// Draw first row
const startCol = model.selection.viewportStartRow === model.selection.viewportCappedStartRow ? model.selection.startCol : 0;
const startRowEndCol = model.selection.viewportCappedStartRow === model.selection.viewportCappedEndRow ? model.selection.endCol : terminal.cols;
this._updateSelectionRange(startCol, startRowEndCol, model.selection.viewportCappedStartRow, model, bg, fg);
// Draw middle rows
const middleRowsCount = Math.max(model.selection.viewportCappedEndRow - model.selection.viewportCappedStartRow - 1, 0);
for (let y = model.selection.viewportCappedStartRow + 1; y <= model.selection.viewportCappedStartRow + middleRowsCount; y++) {
this._updateSelectionRange(0, startRowEndCol, y, model, bg, fg);
}
// Draw final row
if (model.selection.viewportCappedStartRow !== model.selection.viewportCappedEndRow) {
// Only draw viewportEndRow if it's not the same as viewportStartRow
const endCol = model.selection.viewportEndRow === model.selection.viewportCappedEndRow ? model.selection.endCol : terminal.cols;
this._updateSelectionRange(0, endCol, model.selection.viewportCappedEndRow, model, bg, fg);
}
}
}
private _updateSelectionRange(startCol: number, endCol: number, y: number, model: IRenderModel, bg: number, fg: number): void {
const terminal = this._terminal;
const row = y + terminal.buffer.viewportY;
let line: IBufferLine | undefined;
for (let x = startCol; x < endCol; x++) {
const offset = (y * this._terminal.cols + x) * INDICIES_PER_CELL;
// Because the cache uses attr as a lookup key it needs to contain the selection colors as well
let attr = model.cells[offset + 1];
attr = attr & ~0x3ffff | bg << 9 | fg;
const code = model.cells[offset];
if (code & COMBINED_CHAR_BIT_MASK) {
if (!line) {
line = terminal.buffer.getLine(row);
}
const chars = line!.getCell(x)!.char;
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg, chars);
} else {
this._updateCell(this._vertices.selectionAttributes, x, y, model.cells[offset], attr, bg, fg);
}
}
}
public onResize(): void {
const terminal = this._terminal;
const gl = this._gl;
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Update vertices
const newCount = terminal.cols * terminal.rows * INDICES_PER_CELL;
if (this._vertices.count !== newCount) {
this._vertices.count = newCount;
this._vertices.attributes = new Float32Array(newCount);
for (let i = 0; i < this._vertices.attributesBuffers.length; i++) {
this._vertices.attributesBuffers[i] = new Float32Array(newCount);
}
let i = 0;
for (let y = 0; y < terminal.rows; y++) {
for (let x = 0; x < terminal.cols; x++) {
this._vertices.attributes[i + 8] = x / terminal.cols;
this._vertices.attributes[i + 9] = y / terminal.rows;
i += INDICES_PER_CELL;
}
}
}
}
public setColors(): void {
}
public render(renderModel: IRenderModel, isSelectionVisible: boolean): void {
if (!this._atlas) {
return;
}
const gl = this._gl;
gl.useProgram(this._program);
gl.bindVertexArray(this._vertexArrayObject);
// Alternate buffers each frame as the active buffer gets locked while it's in use by the GPU
this._activeBuffer = (this._activeBuffer + 1) % 2;
const activeBuffer = this._vertices.attributesBuffers[this._activeBuffer];
// Copy data for each cell of each line up to its line length (the last non-whitespace cell)
// from the attributes buffer into activeBuffer, which is the one that gets bound to the GPU.
// The reasons for this are as follows:
// - So the active buffer can be alternated so we don't get blocked on rendering finishing
// - To copy either the normal attributes buffer or the selection attributes buffer when there
// is a selection
// - So we don't send vertices for all the line-ending whitespace to the GPU
let bufferLength = 0;
for (let y = 0; y < renderModel.lineLengths.length; y++) {
const si = y * this._terminal.cols * INDICES_PER_CELL;
const sub = (isSelectionVisible ? this._vertices.selectionAttributes : this._vertices.attributes).subarray(si, si + renderModel.lineLengths[y] * INDICES_PER_CELL);
activeBuffer.set(sub, bufferLength);
bufferLength += sub.length;
}
// Bind the attributes buffer
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, activeBuffer.subarray(0, bufferLength), gl.STREAM_DRAW);
// Bind the texture atlas if it's changed
if (this._atlas.hasCanvasChanged) {
this._atlas.hasCanvasChanged = false;
gl.uniform1i(this._textureLocation, 0);
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this._atlas.cacheCanvas);
gl.generateMipmap(gl.TEXTURE_2D);
}
// Set uniforms
gl.uniformMatrix4fv(this._projectionLocation, false, PROJECTION_MATRIX);
gl.uniform2f(this._resolutionLocation, gl.canvas.width, gl.canvas.height);
// Draw the viewport
gl.drawElementsInstanced(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, bufferLength / INDICES_PER_CELL);
}
public setAtlas(atlas: WebglCharAtlas): void {
const gl = this._gl;
this._atlas = atlas;
gl.bindTexture(gl.TEXTURE_2D, this._atlasTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, atlas.cacheCanvas);
gl.generateMipmap(gl.TEXTURE_2D);
}
public setDimensions(dimensions: IRenderDimensions): void {
this._dimensions = dimensions;
}
}
@@ -0,0 +1,325 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { createProgram, expandFloat32Array, PROJECTION_MATRIX, throwIfFalsy } from './WebglUtils';
import { IRenderModel, IWebGLVertexArrayObject, IWebGL2RenderingContext, ISelectionRenderModel } from './Types';
import { fill } from 'common/TypedArrayUtils';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { is256Color } from './atlas/CharAtlasUtils';
import { DEFAULT_COLOR } from 'common/buffer/Constants';
import { Terminal } from 'xterm';
import { IColorSet, IColor } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
const enum VertexAttribLocations {
POSITION = 0,
SIZE = 1,
COLOR = 2,
UNIT_QUAD = 3
}
const vertexShaderSource = `#version 300 es
layout (location = ${VertexAttribLocations.POSITION}) in vec2 a_position;
layout (location = ${VertexAttribLocations.SIZE}) in vec2 a_size;
layout (location = ${VertexAttribLocations.COLOR}) in vec3 a_color;
layout (location = ${VertexAttribLocations.UNIT_QUAD}) in vec2 a_unitquad;
uniform mat4 u_projection;
uniform vec2 u_resolution;
out vec3 v_color;
void main() {
vec2 zeroToOne = (a_position + (a_unitquad * a_size)) / u_resolution;
gl_Position = u_projection * vec4(zeroToOne, 0.0, 1.0);
v_color = a_color;
}`;
const fragmentShaderSource = `#version 300 es
precision lowp float;
in vec3 v_color;
out vec4 outColor;
void main() {
outColor = vec4(v_color, 1);
}`;
interface IVertices {
attributes: Float32Array;
selection: Float32Array;
count: number;
}
const INDICES_PER_RECTANGLE = 8;
const BYTES_PER_RECTANGLE = INDICES_PER_RECTANGLE * Float32Array.BYTES_PER_ELEMENT;
const INITIAL_BUFFER_RECTANGLE_CAPACITY = 20 * INDICES_PER_RECTANGLE;
export class RectangleRenderer {
private _program: WebGLProgram;
private _vertexArrayObject: IWebGLVertexArrayObject;
private _resolutionLocation: WebGLUniformLocation;
private _attributesBuffer: WebGLBuffer;
private _projectionLocation: WebGLUniformLocation;
private _bgFloat!: Float32Array;
private _selectionFloat!: Float32Array;
private _vertices: IVertices = {
count: 0,
attributes: new Float32Array(INITIAL_BUFFER_RECTANGLE_CAPACITY),
selection: new Float32Array(3 * INDICES_PER_RECTANGLE)
};
constructor(
private _terminal: Terminal,
private _colors: IColorSet,
private _gl: IWebGL2RenderingContext,
private _dimensions: IRenderDimensions
) {
const gl = this._gl;
this._program = throwIfFalsy(createProgram(gl, vertexShaderSource, fragmentShaderSource));
// Uniform locations
this._resolutionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_resolution'));
this._projectionLocation = throwIfFalsy(gl.getUniformLocation(this._program, 'u_projection'));
// Create and set the vertex array object
this._vertexArrayObject = gl.createVertexArray();
gl.bindVertexArray(this._vertexArrayObject);
// Setup a_unitquad, this defines the 4 vertices of a rectangle
const unitQuadVertices = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
const unitQuadVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, unitQuadVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, unitQuadVertices, gl.STATIC_DRAW);
gl.enableVertexAttribArray(VertexAttribLocations.UNIT_QUAD);
gl.vertexAttribPointer(VertexAttribLocations.UNIT_QUAD, 2, this._gl.FLOAT, false, 0, 0);
// Setup the unit quad element array buffer, this points to indices in
// unitQuadVertuces to allow is to draw 2 triangles from the vertices
const unitQuadElementIndices = new Uint8Array([0, 1, 3, 0, 2, 3]);
const elementIndicesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elementIndicesBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, unitQuadElementIndices, gl.STATIC_DRAW);
// Setup attributes
this._attributesBuffer = throwIfFalsy(gl.createBuffer());
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.enableVertexAttribArray(VertexAttribLocations.POSITION);
gl.vertexAttribPointer(VertexAttribLocations.POSITION, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 0);
gl.vertexAttribDivisor(VertexAttribLocations.POSITION, 1);
gl.enableVertexAttribArray(VertexAttribLocations.SIZE);
gl.vertexAttribPointer(VertexAttribLocations.SIZE, 2, gl.FLOAT, false, BYTES_PER_RECTANGLE, 2 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.SIZE, 1);
gl.enableVertexAttribArray(VertexAttribLocations.COLOR);
gl.vertexAttribPointer(VertexAttribLocations.COLOR, 4, gl.FLOAT, false, BYTES_PER_RECTANGLE, 4 * Float32Array.BYTES_PER_ELEMENT);
gl.vertexAttribDivisor(VertexAttribLocations.COLOR, 1);
this._updateCachedColors();
}
public render(): void {
const gl = this._gl;
gl.useProgram(this._program);
gl.bindVertexArray(this._vertexArrayObject);
gl.uniformMatrix4fv(this._projectionLocation, false, PROJECTION_MATRIX);
gl.uniform2f(this._resolutionLocation, gl.canvas.width, gl.canvas.height);
// Bind attributes buffer and draw
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this._vertices.attributes, gl.DYNAMIC_DRAW);
gl.drawElementsInstanced(this._gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, this._vertices.count);
// Bind selection buffer and draw
gl.bindBuffer(gl.ARRAY_BUFFER, this._attributesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, this._vertices.selection, gl.DYNAMIC_DRAW);
gl.drawElementsInstanced(this._gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0, 3);
}
public onResize(): void {
this._updateViewportRectangle();
}
public setColors(): void {
this._updateCachedColors();
this._updateViewportRectangle();
}
private _updateCachedColors(): void {
this._bgFloat = this._colorToFloat32Array(this._colors.background);
this._selectionFloat = this._colorToFloat32Array(this._colors.selection);
}
private _updateViewportRectangle(): void {
// Set first rectangle that clears the screen
this._addRectangleFloat(
this._vertices.attributes,
0,
0,
0,
this._terminal.cols * this._dimensions.scaledCellWidth,
this._terminal.rows * this._dimensions.scaledCellHeight,
this._bgFloat
);
}
public updateSelection(model: ISelectionRenderModel, columnSelectMode: boolean): void {
const terminal = this._terminal;
if (!model.hasSelection) {
fill(this._vertices.selection, 0, 0);
return;
}
if (columnSelectMode) {
const startCol = model.startCol;
const width = model.endCol - startCol;
const height = model.viewportCappedEndRow - model.viewportCappedStartRow + 1;
this._addRectangleFloat(
this._vertices.selection,
0,
startCol * this._dimensions.scaledCellWidth,
model.viewportCappedStartRow * this._dimensions.scaledCellHeight,
width * this._dimensions.scaledCellWidth,
height * this._dimensions.scaledCellHeight,
this._selectionFloat
);
fill(this._vertices.selection, 0, INDICES_PER_RECTANGLE);
} else {
// Draw first row
const startCol = model.viewportStartRow === model.viewportCappedStartRow ? model.startCol : 0;
const startRowEndCol = model.viewportCappedStartRow === model.viewportCappedEndRow ? model.endCol : terminal.cols;
this._addRectangleFloat(
this._vertices.selection,
0,
startCol * this._dimensions.scaledCellWidth,
model.viewportCappedStartRow * this._dimensions.scaledCellHeight,
(startRowEndCol - startCol) * this._dimensions.scaledCellWidth,
this._dimensions.scaledCellHeight,
this._selectionFloat
);
// Draw middle rows
const middleRowsCount = Math.max(model.viewportCappedEndRow - model.viewportCappedStartRow - 1, 0);
this._addRectangleFloat(
this._vertices.selection,
INDICES_PER_RECTANGLE,
0,
(model.viewportCappedStartRow + 1) * this._dimensions.scaledCellHeight,
terminal.cols * this._dimensions.scaledCellWidth,
middleRowsCount * this._dimensions.scaledCellHeight,
this._selectionFloat
);
// Draw final row
if (model.viewportCappedStartRow !== model.viewportCappedEndRow) {
// Only draw viewportEndRow if it's not the same as viewportStartRow
const endCol = model.viewportEndRow === model.viewportCappedEndRow ? model.endCol : terminal.cols;
this._addRectangleFloat(
this._vertices.selection,
INDICES_PER_RECTANGLE * 2,
0,
model.viewportCappedEndRow * this._dimensions.scaledCellHeight,
endCol * this._dimensions.scaledCellWidth,
this._dimensions.scaledCellHeight,
this._selectionFloat
);
} else {
fill(this._vertices.selection, 0, INDICES_PER_RECTANGLE * 2);
}
}
}
public updateBackgrounds(model: IRenderModel): void {
const terminal = this._terminal;
const vertices = this._vertices;
let rectangleCount = 1;
for (let y = 0; y < terminal.rows; y++) {
let currentStartX = -1;
let currentBg = DEFAULT_COLOR;
for (let x = 0; x < terminal.cols; x++) {
const modelIndex = ((y * terminal.cols) + x) * 4;
const bg = model.cells[modelIndex + 2];
if (bg !== currentBg) {
// A rectangle needs to be drawn if going from non-default to another color
if (currentBg !== DEFAULT_COLOR) {
const offset = rectangleCount++ * INDICES_PER_RECTANGLE;
this._updateRectangle(vertices, offset, currentBg, currentStartX, x, y);
}
currentStartX = x;
currentBg = bg;
}
}
// Finish rectangle if it's still going
if (currentBg !== DEFAULT_COLOR) {
const offset = rectangleCount++ * INDICES_PER_RECTANGLE;
this._updateRectangle(vertices, offset, currentBg, currentStartX, terminal.cols, y);
}
}
vertices.count = rectangleCount;
}
private _updateRectangle(vertices: IVertices, offset: number, bg: number, startX: number, endX: number, y: number): void {
let color: IColor | null = null;
if (bg === INVERTED_DEFAULT_COLOR) {
color = this._colors.foreground;
} else if (is256Color(bg)) {
color = this._colors.ansi[bg];
} else {
// TODO: Add support for true color
color = this._colors.foreground;
}
if (vertices.attributes.length < offset + 4) {
vertices.attributes = expandFloat32Array(vertices.attributes, this._terminal.rows * this._terminal.cols * INDICES_PER_RECTANGLE);
}
const x1 = startX * this._dimensions.scaledCellWidth;
const y1 = y * this._dimensions.scaledCellHeight;
const r = ((color.rgba >> 24) & 0xFF) / 255;
const g = ((color.rgba >> 16) & 0xFF) / 255;
const b = ((color.rgba >> 8 ) & 0xFF) / 255;
this._addRectangle(vertices.attributes, offset, x1, y1, (endX - startX) * this._dimensions.scaledCellWidth, this._dimensions.scaledCellHeight, r, g, b, 1);
}
private _addRectangle(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, r: number, g: number, b: number, a: number): void {
array[offset ] = x1;
array[offset + 1] = y1;
array[offset + 2] = width;
array[offset + 3] = height;
array[offset + 4] = r;
array[offset + 5] = g;
array[offset + 6] = b;
array[offset + 7] = a;
}
private _addRectangleFloat(array: Float32Array, offset: number, x1: number, y1: number, width: number, height: number, color: Float32Array): void {
array[offset ] = x1;
array[offset + 1] = y1;
array[offset + 2] = width;
array[offset + 3] = height;
array[offset + 4] = color[0];
array[offset + 5] = color[1];
array[offset + 6] = color[2];
array[offset + 7] = color[3];
}
private _colorToFloat32Array(color: IColor): Float32Array {
return new Float32Array([
((color.rgba >> 24) & 0xFF) / 255,
((color.rgba >> 16) & 0xFF) / 255,
((color.rgba >> 8 ) & 0xFF) / 255,
((color.rgba ) & 0xFF) / 255
]);
}
}
@@ -0,0 +1,55 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IRenderModel, ISelectionRenderModel } from './Types';
import { fill } from 'common/TypedArrayUtils';
export const RENDER_MODEL_INDICIES_PER_CELL = 4;
export const COMBINED_CHAR_BIT_MASK = 0x80000000;
export class RenderModel implements IRenderModel {
public cells: Uint32Array;
public lineLengths: Uint32Array;
public selection: ISelectionRenderModel;
constructor() {
this.cells = new Uint32Array(0);
this.lineLengths = new Uint32Array(0);
this.selection = {
hasSelection: false,
viewportStartRow: 0,
viewportEndRow: 0,
viewportCappedStartRow: 0,
viewportCappedEndRow: 0,
startCol: 0,
endCol: 0
};
}
public resize(cols: number, rows: number): void {
const indexCount = cols * rows * RENDER_MODEL_INDICIES_PER_CELL;
if (indexCount !== this.cells.length) {
this.cells = new Uint32Array(indexCount);
this.lineLengths = new Uint32Array(rows);
}
}
public clear(): void {
fill(this.cells, 0, 0);
fill(this.lineLengths, 0, 0);
this.clearSelection();
}
public clearSelection(): void {
this.selection.hasSelection = false;
this.selection.viewportStartRow = 0;
this.selection.viewportEndRow = 0;
this.selection.viewportCappedStartRow = 0;
this.selection.viewportCappedEndRow = 0;
this.selection.startCol = 0;
this.selection.endCol = 0;
}
}
@@ -0,0 +1,122 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { sliceFallback } from './TypedArray';
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
| Int8Array | Int16Array | Int32Array
| Float32Array | Float64Array;
function deepEquals(a: TypedArray, b: TypedArray): void {
assert.equal(a.length, b.length);
for (let i = 0; i < a.length; ++i) {
assert.equal(a[i], b[i]);
}
}
describe('polyfill conformance tests', function(): void {
describe('TypedArray.slice', () => {
describe('should work with all typed array types', () => {
it('Uint8Array', () => {
const a = new Uint8Array(5);
deepEquals(sliceFallback(a, 2), a.slice(2));
deepEquals(sliceFallback(a, 65535), a.slice(65535));
deepEquals(sliceFallback(a, -1), a.slice(-1));
});
it('Uint16Array', () => {
const u161 = new Uint16Array(5);
const u162 = new Uint16Array(5);
deepEquals(sliceFallback(u161, 2), u162.slice(2));
deepEquals(sliceFallback(u161, 65535), u162.slice(65535));
deepEquals(sliceFallback(u161, -1), u162.slice(-1));
});
it('Uint32Array', () => {
const u321 = new Uint32Array(5);
const u322 = new Uint32Array(5);
deepEquals(sliceFallback(u321, 2), u322.slice(2));
deepEquals(sliceFallback(u321, 65537), u322.slice(65537));
deepEquals(sliceFallback(u321, -1), u322.slice(-1));
});
it('Int8Array', () => {
const i81 = new Int8Array(5);
const i82 = new Int8Array(5);
deepEquals(sliceFallback(i81, 2), i82.slice(2));
deepEquals(sliceFallback(i81, 65537), i82.slice(65537));
deepEquals(sliceFallback(i81, -1), i82.slice(-1));
});
it('Int16Array', () => {
const i161 = new Int16Array(5);
const i162 = new Int16Array(5);
deepEquals(sliceFallback(i161, 2), i162.slice(2));
deepEquals(sliceFallback(i161, 65535), i162.slice(65535));
deepEquals(sliceFallback(i161, -1), i162.slice(-1));
});
it('Int32Array', () => {
const i321 = new Int32Array(5);
const i322 = new Int32Array(5);
deepEquals(sliceFallback(i321, 2), i322.slice(2));
deepEquals(sliceFallback(i321, 65537), i322.slice(65537));
deepEquals(sliceFallback(i321, -1), i322.slice(-1));
});
it('Float32Array', () => {
const f321 = new Float32Array(5);
const f322 = new Float32Array(5);
deepEquals(sliceFallback(f321, 2), f322.slice(2));
deepEquals(sliceFallback(f321, 65537), f322.slice(65537));
deepEquals(sliceFallback(f321, -1), f322.slice(-1));
});
it('Float64Array', () => {
const f641 = new Float64Array(5);
const f642 = new Float64Array(5);
deepEquals(sliceFallback(f641, 2), f642.slice(2));
deepEquals(sliceFallback(f641, 65537), f642.slice(65537));
deepEquals(sliceFallback(f641, -1), f642.slice(-1));
});
it('Uint8ClampedArray', () => {
const u8Clamped1 = new Uint8ClampedArray(5);
const u8Clamped2 = new Uint8ClampedArray(5);
deepEquals(sliceFallback(u8Clamped1, 2), u8Clamped2.slice(2));
deepEquals(sliceFallback(u8Clamped1, 65537), u8Clamped2.slice(65537));
deepEquals(sliceFallback(u8Clamped1, -1), u8Clamped2.slice(-1));
});
});
it('start', () => {
const arr = new Uint32Array([1, 2, 3, 4, 5]);
deepEquals(sliceFallback(arr, -1), arr.slice(-1));
deepEquals(sliceFallback(arr, 0), arr.slice(0));
deepEquals(sliceFallback(arr, 1), arr.slice(1));
deepEquals(sliceFallback(arr, 2), arr.slice(2));
deepEquals(sliceFallback(arr, 3), arr.slice(3));
deepEquals(sliceFallback(arr, 4), arr.slice(4));
deepEquals(sliceFallback(arr, 5), arr.slice(5));
});
it('end', () => {
const arr = new Uint32Array([1, 2, 3, 4, 5]);
deepEquals(sliceFallback(arr, -1, -2), arr.slice(-1, -2));
deepEquals(sliceFallback(arr, 0, -2), arr.slice(0, -2));
deepEquals(sliceFallback(arr, 1, -2), arr.slice(1, -2));
deepEquals(sliceFallback(arr, 2, -2), arr.slice(2, -2));
deepEquals(sliceFallback(arr, 3, -2), arr.slice(3, -2));
deepEquals(sliceFallback(arr, 4, -2), arr.slice(4, -2));
deepEquals(sliceFallback(arr, 5, -2), arr.slice(5, -2));
deepEquals(sliceFallback(arr, -1, 3), arr.slice(-1, 3));
deepEquals(sliceFallback(arr, 0, 3), arr.slice(0, 3));
deepEquals(sliceFallback(arr, 1, 3), arr.slice(1, 3));
deepEquals(sliceFallback(arr, 2, 3), arr.slice(2, 3));
deepEquals(sliceFallback(arr, 3, 3), arr.slice(3, 3));
deepEquals(sliceFallback(arr, 4, 3), arr.slice(4, 3));
deepEquals(sliceFallback(arr, 5, 3), arr.slice(5, 3));
deepEquals(sliceFallback(arr, -1, 8), arr.slice(-1, 8));
deepEquals(sliceFallback(arr, 0, 8), arr.slice(0, 8));
deepEquals(sliceFallback(arr, 1, 8), arr.slice(1, 8));
deepEquals(sliceFallback(arr, 2, 8), arr.slice(2, 8));
deepEquals(sliceFallback(arr, 3, 8), arr.slice(3, 8));
deepEquals(sliceFallback(arr, 4, 8), arr.slice(4, 8));
deepEquals(sliceFallback(arr, 5, 8), arr.slice(5, 8));
});
});
});
@@ -0,0 +1,34 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
export type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
| Int8Array | Int16Array | Int32Array
| Float32Array | Float64Array;
export function slice<T extends TypedArray>(array: T, start?: number, end?: number): T {
// all modern engines that support .slice
if (array.slice) {
return array.slice(start, end) as T;
}
return sliceFallback(array, start, end);
}
export function sliceFallback<T extends TypedArray>(array: T, start: number = 0, end: number = array.length): T {
if (start < 0) {
start = (array.length + start) % array.length;
}
if (end >= array.length) {
end = array.length;
} else {
end = (array.length + end) % array.length;
}
start = Math.min(start, end);
const result: T = new (array.constructor as any)(end - start);
for (let i = 0; i < end - start; ++i) {
result[i] = array[i + start];
}
return result;
}
+75
View File
@@ -0,0 +1,75 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
export interface IRasterizedGlyphSet {
[flags: number]: IRasterizedGlyph;
}
/**
* Represents a rasterized glyph within a texture atlas. Some numbers are
* tracked in CSS pixels as well in order to reduce calculations during the
* render loop.
*/
export interface IRasterizedGlyph {
/**
* The x and y offset between the glyph's top/left and the top/left of a cell
* in pixels.
*/
offset: IVector;
/**
* the x and y position of the glyph in the texture in pixels.
*/
texturePosition: IVector;
/**
* the x and y position of the glyph in the texture in clip space coordinates.
*/
texturePositionClipSpace: IVector;
/**
* The width and height of the glyph in the texture in pixels.
*/
size: IVector;
/**
* The width and height of the glyph in the texture in clip space coordinates.
*/
sizeClipSpace: IVector;
}
export interface IVector {
x: number;
y: number;
}
export interface IBoundingBox {
top: number;
left: number;
right: number;
bottom: number;
}
export interface IRenderModel {
cells: Uint32Array;
lineLengths: Uint32Array;
selection: ISelectionRenderModel;
}
export interface ISelectionRenderModel {
hasSelection: boolean;
viewportStartRow: number;
viewportEndRow: number;
viewportCappedStartRow: number;
viewportCappedEndRow: number;
startCol: number;
endCol: number;
}
export interface IWebGL2RenderingContext extends WebGLRenderingContext {
vertexAttribDivisor(index: number, divisor: number): void;
createVertexArray(): IWebGLVertexArrayObject;
bindVertexArray(vao: IWebGLVertexArrayObject): void;
drawElementsInstanced(mode: number, count: number, type: number, offset: number, instanceCount: number): void;
}
export interface IWebGLVertexArrayObject {
}
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, ITerminalAddon } from 'xterm';
import { WebglRenderer } from './WebglRenderer';
import { IRenderService } from 'browser/services/Services';
import { IColorSet } from 'browser/Types';
export class WebglAddon implements ITerminalAddon {
constructor(
private _preserveDrawingBuffer?: boolean
) {}
public activate(terminal: Terminal): void {
if (!terminal.element) {
throw new Error('Cannot activate WebglRendererAddon before Terminal.open');
}
const renderService: IRenderService = (<any>terminal)._core._renderService;
const colors: IColorSet = (<any>terminal)._core._colorManager.colors;
renderService.setRenderer(new WebglRenderer(terminal, colors, this._preserveDrawingBuffer));
}
public dispose(): void {
throw new Error('WebglRendererAddon.dispose Not yet implemented');
}
}
@@ -0,0 +1,163 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
import * as puppeteer from 'puppeteer';
import { assert } from 'chai';
import { ITerminalOptions } from '../../../src/Types';
import { ITheme } from 'xterm';
const APP = 'http://127.0.0.1:3000/test';
let browser: puppeteer.Browser;
let page: puppeteer.Page;
const width = 800;
const height = 600;
describe('WebGL Renderer Integration Tests', function(): void {
this.timeout(20000);
before(async function(): Promise<any> {
browser = await puppeteer.launch({
headless: process.argv.indexOf('--headless') !== -1,
slowMo: 80,
args: [`--window-size=${width},${height}`, `--no-sandbox`]
});
page = (await browser.pages())[0];
await page.setViewport({ width, height });
await page.goto(APP);
await openTerminal();
await page.evaluate(`window.term.loadAddon(new WebglAddon(true));`);
});
after(() => {
browser.close();
});
beforeEach(async () => {
await page.evaluate(`window.term.reset()`);
});
describe('WebGL Renderer', () => {
it('foreground colors normal', async function(): Promise<any> {
const theme: ITheme = {
black: '#010203',
red: '#040506',
green: '#070809',
yellow: '#0a0b0c',
blue: '#0d0e0f',
magenta: '#101112',
cyan: '#131415',
white: '#161718'
};
await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`);
await writeSync(`\\x1b[30m█\\x1b[31m█\\x1b[32m█\\x1b[33m█\\x1b[34m█\\x1b[35m█\\x1b[36m█\\x1b[37m█`);
assert.deepEqual(await getCellColor(1, 1), [1, 2, 3, 255]);
assert.deepEqual(await getCellColor(2, 1), [4, 5, 6, 255]);
assert.deepEqual(await getCellColor(3, 1), [7, 8, 9, 255]);
assert.deepEqual(await getCellColor(4, 1), [10, 11, 12, 255]);
assert.deepEqual(await getCellColor(5, 1), [13, 14, 15, 255]);
assert.deepEqual(await getCellColor(6, 1), [16, 17, 18, 255]);
assert.deepEqual(await getCellColor(7, 1), [19, 20, 21, 255]);
assert.deepEqual(await getCellColor(8, 1), [22, 23, 24, 255]);
});
it('foreground colors bright', async function(): Promise<any> {
const theme: ITheme = {
brightBlack: '#010203',
brightRed: '#040506',
brightGreen: '#070809',
brightYellow: '#0a0b0c',
brightBlue: '#0d0e0f',
brightMagenta: '#101112',
brightCyan: '#131415',
brightWhite: '#161718'
};
await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`);
await writeSync(`\\x1b[90m█\\x1b[91m█\\x1b[92m█\\x1b[93m█\\x1b[94m█\\x1b[95m█\\x1b[96m█\\x1b[97m█`);
assert.deepEqual(await getCellColor(1, 1), [1, 2, 3, 255]);
assert.deepEqual(await getCellColor(2, 1), [4, 5, 6, 255]);
assert.deepEqual(await getCellColor(3, 1), [7, 8, 9, 255]);
assert.deepEqual(await getCellColor(4, 1), [10, 11, 12, 255]);
assert.deepEqual(await getCellColor(5, 1), [13, 14, 15, 255]);
assert.deepEqual(await getCellColor(6, 1), [16, 17, 18, 255]);
assert.deepEqual(await getCellColor(7, 1), [19, 20, 21, 255]);
assert.deepEqual(await getCellColor(8, 1), [22, 23, 24, 255]);
});
it('background colors normal', async function(): Promise<any> {
const theme: ITheme = {
black: '#010203',
red: '#040506',
green: '#070809',
yellow: '#0a0b0c',
blue: '#0d0e0f',
magenta: '#101112',
cyan: '#131415',
white: '#161718'
};
await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`);
await writeSync(`\\x1b[40m \\x1b[41m \\x1b[42m \\x1b[43m \\x1b[44m \\x1b[45m \\x1b[46m \\x1b[47m `);
assert.deepEqual(await getCellColor(1, 1), [1, 2, 3, 255]);
assert.deepEqual(await getCellColor(2, 1), [4, 5, 6, 255]);
assert.deepEqual(await getCellColor(3, 1), [7, 8, 9, 255]);
assert.deepEqual(await getCellColor(4, 1), [10, 11, 12, 255]);
assert.deepEqual(await getCellColor(5, 1), [13, 14, 15, 255]);
assert.deepEqual(await getCellColor(6, 1), [16, 17, 18, 255]);
assert.deepEqual(await getCellColor(7, 1), [19, 20, 21, 255]);
assert.deepEqual(await getCellColor(8, 1), [22, 23, 24, 255]);
});
it('background colors bright', async function(): Promise<any> {
const theme: ITheme = {
brightBlack: '#010203',
brightRed: '#040506',
brightGreen: '#070809',
brightYellow: '#0a0b0c',
brightBlue: '#0d0e0f',
brightMagenta: '#101112',
brightCyan: '#131415',
brightWhite: '#161718'
};
await page.evaluate(`window.term.setOption('theme', ${JSON.stringify(theme)});`);
await writeSync(`\\x1b[100m \\x1b[101m \\x1b[102m \\x1b[103m \\x1b[104m \\x1b[105m \\x1b[106m \\x1b[107m `);
assert.deepEqual(await getCellColor(1, 1), [1, 2, 3, 255]);
assert.deepEqual(await getCellColor(2, 1), [4, 5, 6, 255]);
assert.deepEqual(await getCellColor(3, 1), [7, 8, 9, 255]);
assert.deepEqual(await getCellColor(4, 1), [10, 11, 12, 255]);
assert.deepEqual(await getCellColor(5, 1), [13, 14, 15, 255]);
assert.deepEqual(await getCellColor(6, 1), [16, 17, 18, 255]);
assert.deepEqual(await getCellColor(7, 1), [19, 20, 21, 255]);
assert.deepEqual(await getCellColor(8, 1), [22, 23, 24, 255]);
});
});
});
async function openTerminal(options: ITerminalOptions = {}): Promise<void> {
await page.evaluate(`window.term = new Terminal(${JSON.stringify(options)})`);
await page.evaluate(`window.term.open(document.querySelector('#terminal-container'))`);
if (options.rendererType === 'dom') {
await page.waitForSelector('.xterm-rows');
} else {
await page.waitForSelector('.xterm-text-layer');
}
}
async function writeSync(data: string): Promise<void> {
return page.evaluate(`new Promise(resolve => window.term.write('${data}', resolve))`);
}
async function getCellColor(col: number, row: number): Promise<number[]> {
await page.evaluate(`
window.gl = window.term._core._renderService._renderer._gl;
window.result = new Uint8Array(4);
window.d = window.term._core._renderService.dimensions;
window.gl.readPixels(
Math.floor((${col - 0.5}) * window.d.scaledCellWidth),
Math.floor(window.gl.drawingBufferHeight - 1 - (${row - 0.5}) * window.d.scaledCellHeight),
1, 1, window.gl.RGBA, window.gl.UNSIGNED_BYTE, window.result
);
`);
return await page.evaluate(`Array.from(window.result)`);
}
@@ -0,0 +1,410 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { ITerminal } from '../../../src/Types';
import { GlyphRenderer } from './GlyphRenderer';
import { LinkRenderLayer } from './renderLayer/LinkRenderLayer';
import { CursorRenderLayer } from './renderLayer/CursorRenderLayer';
import { acquireCharAtlas } from './atlas/CharAtlasCache';
import { WebglCharAtlas } from './atlas/WebglCharAtlas';
import { RectangleRenderer } from './RectangleRenderer';
import { IWebGL2RenderingContext } from './Types';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { RenderModel, COMBINED_CHAR_BIT_MASK } from './RenderModel';
import { Disposable } from 'common/Lifecycle';
import { DEFAULT_COLOR, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX, NULL_CELL_CODE } from 'common/buffer/Constants';
import { Terminal } from 'xterm';
import { getLuminance } from './ColorUtils';
import { IRenderLayer } from './renderLayer/Types';
import { IRenderDimensions, IRenderer } from 'browser/renderer/Types';
import { IColorSet } from 'browser/Types';
import { FLAGS } from './Constants';
import { getCompatAttr } from './CharDataCompat';
export const INDICIES_PER_CELL = 4;
export class WebglRenderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
private _charAtlas: WebglCharAtlas | undefined;
private _devicePixelRatio: number;
private _model: RenderModel = new RenderModel();
private _canvas: HTMLCanvasElement;
private _gl: IWebGL2RenderingContext;
private _rectangleRenderer: RectangleRenderer;
private _glyphRenderer: GlyphRenderer;
public dimensions: IRenderDimensions;
private _core: ITerminal;
constructor(
private _terminal: Terminal,
private _colors: IColorSet,
preserveDrawingBuffer?: boolean
) {
super();
this._core = (<any>this._terminal)._core;
this._applyBgLuminanceBasedSelection();
this._renderLayers = [
new LinkRenderLayer(this._core.screenElement, 2, this._colors, this._core),
new CursorRenderLayer(this._core.screenElement, 3, this._colors)
];
this.dimensions = {
scaledCharWidth: 0,
scaledCharHeight: 0,
scaledCellWidth: 0,
scaledCellHeight: 0,
scaledCharLeft: 0,
scaledCharTop: 0,
scaledCanvasWidth: 0,
scaledCanvasHeight: 0,
canvasWidth: 0,
canvasHeight: 0,
actualCellWidth: 0,
actualCellHeight: 0
};
this._devicePixelRatio = window.devicePixelRatio;
this._updateDimensions();
this._canvas = document.createElement('canvas');
const contextAttributes = {
antialias: false,
depth: false,
preserveDrawingBuffer
};
this._gl = this._canvas.getContext('webgl2', contextAttributes) as IWebGL2RenderingContext;
if (!this._gl) {
throw new Error('WebGL2 not supported');
}
this._core.screenElement.appendChild(this._canvas);
this._rectangleRenderer = new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions);
this._glyphRenderer = new GlyphRenderer(this._terminal, this._colors, this._gl, this.dimensions);
// Update dimensions and acquire char atlas
this.onCharSizeChanged();
}
public dispose(): void {
this._renderLayers.forEach(l => l.dispose());
this._core.screenElement.removeChild(this._canvas);
super.dispose();
}
private _applyBgLuminanceBasedSelection(): void {
// HACK: This is needed until webgl renderer adds support for selection colors
if (getLuminance(this._colors.background) > 0.5) {
this._colors.selection = { css: '#000', rgba: 255 };
} else {
this._colors.selection = { css: '#fff', rgba: 4294967295 };
}
}
public setColors(colors: IColorSet): void {
this._colors = colors;
this._applyBgLuminanceBasedSelection();
// Clear layers and force a full render
this._renderLayers.forEach(l => {
l.setColors(this._terminal, this._colors);
l.reset(this._terminal);
});
this._rectangleRenderer.setColors();
this._glyphRenderer.setColors();
this._refreshCharAtlas();
// Force a full refresh
this._model.clear();
}
public onDevicePixelRatioChange(): void {
// If the device pixel ratio changed, the char atlas needs to be regenerated
// and the terminal needs to refreshed
if (this._devicePixelRatio !== window.devicePixelRatio) {
this._devicePixelRatio = window.devicePixelRatio;
this.onResize(this._terminal.cols, this._terminal.rows);
}
}
public onResize(cols: number, rows: number): void {
// Update character and canvas dimensions
this._updateDimensions();
this._model.resize(this._terminal.cols, this._terminal.rows);
this._rectangleRenderer.onResize();
// Resize all render layers
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions));
// Resize the canvas
this._canvas.width = this.dimensions.scaledCanvasWidth;
this._canvas.height = this.dimensions.scaledCanvasHeight;
this._canvas.style.width = `${this.dimensions.canvasWidth}px`;
this._canvas.style.height = `${this.dimensions.canvasHeight}px`;
// Resize the screen
this._core.screenElement.style.width = `${this.dimensions.canvasWidth}px`;
this._core.screenElement.style.height = `${this.dimensions.canvasHeight}px`;
this._glyphRenderer.setDimensions(this.dimensions);
this._glyphRenderer.onResize();
this._refreshCharAtlas();
// Force a full refresh
this._model.clear();
}
public onCharSizeChanged(): void {
this.onResize(this._terminal.cols, this._terminal.rows);
}
public onBlur(): void {
this._renderLayers.forEach(l => l.onBlur(this._terminal));
}
public onFocus(): void {
this._renderLayers.forEach(l => l.onFocus(this._terminal));
}
public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void {
this._renderLayers.forEach(l => l.onSelectionChanged(this._terminal, start, end, columnSelectMode));
this._updateSelectionModel(start, end);
this._rectangleRenderer.updateSelection(this._model.selection, columnSelectMode);
this._glyphRenderer.updateSelection(this._model, columnSelectMode);
// TODO: #2102 Should this move to RenderCoordinator?
this._core.refresh(0, this._terminal.rows - 1);
}
public onCursorMove(): void {
this._renderLayers.forEach(l => l.onCursorMove(this._terminal));
}
public onOptionsChanged(): void {
this._renderLayers.forEach(l => l.onOptionsChanged(this._terminal));
this._updateDimensions();
this._refreshCharAtlas();
}
/**
* Refreshes the char atlas, aquiring a new one if necessary.
* @param terminal The terminal.
* @param colorSet The color set to use for the char atlas.
*/
private _refreshCharAtlas(): void {
if (this.dimensions.scaledCharWidth <= 0 && this.dimensions.scaledCharHeight <= 0) {
return;
}
const atlas = acquireCharAtlas(this._terminal, this._colors, this.dimensions.scaledCharWidth, this.dimensions.scaledCharHeight);
if (!('getRasterizedGlyph' in atlas)) {
throw new Error('The webgl renderer only works with the webgl char atlas');
}
this._charAtlas = atlas as WebglCharAtlas;
this._charAtlas.warmUp();
this._glyphRenderer.setAtlas(this._charAtlas);
}
public clear(): void {
this._renderLayers.forEach(l => l.reset(this._terminal));
}
public registerCharacterJoiner(handler: (text: string) => [number, number][]): number {
return -1;
}
public deregisterCharacterJoiner(joinerId: number): boolean {
return false;
}
public renderRows(start: number, end: number): void {
// Update render layers
this._renderLayers.forEach(l => l.onGridChanged(this._terminal, start, end));
// Tell renderer the frame is beginning
if (this._glyphRenderer.beginFrame()) {
this._model.clear();
}
// Update model to reflect what's drawn
this._updateModel(start, end);
// Render
this._rectangleRenderer.render();
this._glyphRenderer.render(this._model, this._model.selection.hasSelection);
}
private _updateModel(start: number, end: number): void {
const terminal = this._core;
for (let y = start; y <= end; y++) {
const row = y + terminal.buffer.ydisp;
const line = terminal.buffer.lines.get(row)!;
this._model.lineLengths[y] = 0;
for (let x = 0; x < terminal.cols; x++) {
const charData = line.get(x);
const chars = charData[CHAR_DATA_CHAR_INDEX];
let code = charData[CHAR_DATA_CODE_INDEX];
const attr = getCompatAttr(line, x); // charData[CHAR_DATA_ATTR_INDEX];
const i = ((y * terminal.cols) + x) * INDICIES_PER_CELL;
if (code !== NULL_CELL_CODE) {
this._model.lineLengths[y] = x + 1;
}
// Nothing has changed, no updates needed
if (this._model.cells[i] === code && this._model.cells[i + 1] === attr) {
continue;
}
// Resolve bg and fg and cache in the model
const flags = attr >> 18;
let bg = attr & 0x1ff;
let fg = (attr >> 9) & 0x1ff;
// If inverse flag is on, the foreground should become the background.
if (flags & FLAGS.INVERSE) {
const temp = bg;
bg = fg;
fg = temp;
if (fg === DEFAULT_COLOR) {
fg = INVERTED_DEFAULT_COLOR;
}
if (bg === DEFAULT_COLOR) {
bg = INVERTED_DEFAULT_COLOR;
}
}
const drawInBrightColor = terminal.options.drawBoldTextInBrightColors && !!(flags & FLAGS.BOLD) && fg < 8 && fg !== INVERTED_DEFAULT_COLOR;
fg += drawInBrightColor ? 8 : 0;
// Flag combined chars with a bit mask so they're easily identifiable
if (chars.length > 1) {
code = code | COMBINED_CHAR_BIT_MASK;
}
this._model.cells[i ] = code;
this._model.cells[i + 1] = attr;
this._model.cells[i + 2] = bg;
this._model.cells[i + 3] = fg;
this._glyphRenderer.updateCell(x, y, code, attr, bg, fg, chars);
}
}
this._rectangleRenderer.updateBackgrounds(this._model);
}
private _updateSelectionModel(start: [number, number], end: [number, number]): void {
const terminal = this._terminal;
// Selection does not exist
if (!start || !end || (start[0] === end[0] && start[1] === end[1])) {
this._model.clearSelection();
return;
}
// Translate from buffer position to viewport position
const viewportStartRow = start[1] - terminal.buffer.viewportY;
const viewportEndRow = end[1] - terminal.buffer.viewportY;
const viewportCappedStartRow = Math.max(viewportStartRow, 0);
const viewportCappedEndRow = Math.min(viewportEndRow, terminal.rows - 1);
// No need to draw the selection
if (viewportCappedStartRow >= terminal.rows || viewportCappedEndRow < 0) {
this._model.clearSelection();
return;
}
this._model.selection.hasSelection = true;
this._model.selection.viewportStartRow = viewportStartRow;
this._model.selection.viewportEndRow = viewportEndRow;
this._model.selection.viewportCappedStartRow = viewportCappedStartRow;
this._model.selection.viewportCappedEndRow = viewportCappedEndRow;
this._model.selection.startCol = start[0];
this._model.selection.endCol = end[0];
}
/**
* Recalculates the character and canvas dimensions.
*/
private _updateDimensions(): void {
// TODO: Acquire CharSizeService properly
// Perform a new measure if the CharMeasure dimensions are not yet available
if (!(<any>this._core)._charSizeService.width || !(<any>this._core)._charSizeService.height) {
return;
}
// Calculate the scaled character width. Width is floored as it must be
// drawn to an integer grid in order for the CharAtlas "stamps" to not be
// blurry. When text is drawn to the grid not using the CharAtlas, it is
// clipped to ensure there is no overlap with the next cell.
// NOTE: ceil fixes sometime, floor does others :s
this.dimensions.scaledCharWidth = Math.floor((<any>this._core)._charSizeService.width * this._devicePixelRatio);
// Calculate the scaled character height. Height is ceiled in case
// devicePixelRatio is a floating point number in order to ensure there is
// enough space to draw the character to the cell.
this.dimensions.scaledCharHeight = Math.ceil((<any>this._core)._charSizeService.height * this._devicePixelRatio);
// Calculate the scaled cell height, if lineHeight is not 1 then the value
// will be floored because since lineHeight can never be lower then 1, there
// is a guarentee that the scaled line height will always be larger than
// scaled char height.
this.dimensions.scaledCellHeight = Math.floor(this.dimensions.scaledCharHeight * this._terminal.getOption('lineHeight'));
// Calculate the y coordinate within a cell that text should draw from in
// order to draw in the center of a cell.
this.dimensions.scaledCharTop = this._terminal.getOption('lineHeight') === 1 ? 0 : Math.round((this.dimensions.scaledCellHeight - this.dimensions.scaledCharHeight) / 2);
// Calculate the scaled cell width, taking the letterSpacing into account.
this.dimensions.scaledCellWidth = this.dimensions.scaledCharWidth + Math.round(this._terminal.getOption('letterSpacing'));
// Calculate the x coordinate with a cell that text should draw from in
// order to draw in the center of a cell.
this.dimensions.scaledCharLeft = Math.floor(this._terminal.getOption('letterSpacing') / 2);
// Recalculate the canvas dimensions; scaled* define the actual number of
// pixel in the canvas
this.dimensions.scaledCanvasHeight = this._terminal.rows * this.dimensions.scaledCellHeight;
this.dimensions.scaledCanvasWidth = this._terminal.cols * this.dimensions.scaledCellWidth;
// The the size of the canvas on the page. It's very important that this
// rounds to nearest integer and not ceils as browsers often set
// window.devicePixelRatio as something like 1.100000023841858, when it's
// actually 1.1. Ceiling causes blurriness as the backing canvas image is 1
// pixel too large for the canvas element size.
this.dimensions.canvasHeight = Math.round(this.dimensions.scaledCanvasHeight / this._devicePixelRatio);
this.dimensions.canvasWidth = Math.round(this.dimensions.scaledCanvasWidth / this._devicePixelRatio);
// this.dimensions.scaledCanvasHeight = this.dimensions.canvasHeight * devicePixelRatio;
// this.dimensions.scaledCanvasWidth = this.dimensions.canvasWidth * devicePixelRatio;
// Get the _actual_ dimensions of an individual cell. This needs to be
// derived from the canvasWidth/Height calculated above which takes into
// account window.devicePixelRatio. CharMeasure.width/height by itself is
// insufficient when the page is not at 100% zoom level as CharMeasure is
// measured in CSS pixels, but the actual char size on the canvas can
// differ.
// this.dimensions.actualCellHeight = this.dimensions.canvasHeight / this._terminal.rows;
// this.dimensions.actualCellWidth = this.dimensions.canvasWidth / this._terminal.cols;
// This fixes 110% and 125%, not 150% or 175% though
this.dimensions.actualCellHeight = this.dimensions.scaledCellHeight / this._devicePixelRatio;
this.dimensions.actualCellWidth = this.dimensions.scaledCellWidth / this._devicePixelRatio;
}
}
@@ -0,0 +1,58 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
/**
* A matrix that when multiplies will translate 0-1 coordinates (left to right,
* top to bottom) to clip space.
*/
export const PROJECTION_MATRIX = new Float32Array([
2, 0, 0, 0,
0, -2, 0, 0,
0, 0, 1, 0,
-1, 1, 0, 1
]);
export function createProgram(gl: WebGLRenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram | undefined {
const program = throwIfFalsy(gl.createProgram());
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.VERTEX_SHADER, vertexSource)));
gl.attachShader(program, throwIfFalsy(createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)));
gl.linkProgram(program);
const success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
export function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | undefined {
const shader = throwIfFalsy(gl.createShader(type));
gl.shaderSource(shader, source);
gl.compileShader(shader);
const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
export function expandFloat32Array(source: Float32Array, max: number): Float32Array {
const newLength = Math.min(source.length * 2, max);
const newArray = new Float32Array(newLength);
for (let i = 0; i < source.length; i++) {
newArray[i] = source[i];
}
return newArray;
}
export function throwIfFalsy<T>(value: T | undefined | null): T {
if (!value) {
throw new Error('value must not be falsy');
}
return value;
}
@@ -3,27 +3,18 @@
* @license MIT
*/
import { ITerminal } from '../../Types';
import { IColorSet } from '../Types';
import { generateConfig, configEquals } from './CharAtlasUtils';
import BaseCharAtlas from './BaseCharAtlas';
import DynamicCharAtlas from './DynamicCharAtlas';
import NoneCharAtlas from './NoneCharAtlas';
import StaticCharAtlas from './StaticCharAtlas';
import { WebglCharAtlas } from './WebglCharAtlas';
import { ICharAtlasConfig } from './Types';
const charAtlasImplementations = {
'none': NoneCharAtlas,
'static': StaticCharAtlas,
'dynamic': DynamicCharAtlas
};
import { Terminal } from 'xterm';
import { IColorSet } from 'browser/Types';
interface ICharAtlasCacheEntry {
atlas: BaseCharAtlas;
atlas: WebglCharAtlas;
config: ICharAtlasConfig;
// N.B. This implementation potentially holds onto copies of the terminal forever, so
// this may cause memory leaks.
ownedBy: ITerminal[];
ownedBy: Terminal[];
}
const charAtlasCache: ICharAtlasCacheEntry[] = [];
@@ -35,11 +26,11 @@ const charAtlasCache: ICharAtlasCacheEntry[] = [];
* @param colors The colors to use.
*/
export function acquireCharAtlas(
terminal: ITerminal,
terminal: Terminal,
colors: IColorSet,
scaledCharWidth: number,
scaledCharHeight: number
): BaseCharAtlas {
): WebglCharAtlas {
const newConfig = generateConfig(scaledCharWidth, scaledCharHeight, terminal, colors);
// Check to see if the terminal already owns this config
@@ -72,10 +63,7 @@ export function acquireCharAtlas(
}
const newEntry: ICharAtlasCacheEntry = {
atlas: new charAtlasImplementations[terminal.options.experimentalCharAtlas](
document,
newConfig
),
atlas: new WebglCharAtlas(document, newConfig),
config: newConfig,
ownedBy: [terminal]
};
@@ -87,7 +75,7 @@ export function acquireCharAtlas(
* Removes a terminal reference from the cache, allowing its memory to be freed.
* @param terminal The terminal to remove.
*/
export function removeTerminalFromCache(terminal: ITerminal): void {
export function removeTerminalFromCache(terminal: Terminal): void {
for (let i = 0; i < charAtlasCache.length; i++) {
const index = charAtlasCache[i].ownedBy.indexOf(terminal);
if (index !== -1) {
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { ICharAtlasConfig } from './Types';
import { DEFAULT_COLOR } from 'common/buffer/Constants';
import { Terminal, FontWeight } from 'xterm';
import { IColorSet, IColor } from 'browser/Types';
const NULL_COLOR: IColor = {
css: '',
rgba: 0
};
export function generateConfig(scaledCharWidth: number, scaledCharHeight: number, terminal: Terminal, colors: IColorSet): ICharAtlasConfig {
// null out some fields that don't matter
const clonedColors: IColorSet = {
foreground: colors.foreground,
background: colors.background,
cursor: NULL_COLOR,
cursorAccent: NULL_COLOR,
selection: NULL_COLOR,
// For the static char atlas, we only use the first 16 colors, but we need all 256 for the
// dynamic character atlas.
ansi: colors.ansi.slice()
};
return {
devicePixelRatio: window.devicePixelRatio,
scaledCharWidth,
scaledCharHeight,
fontFamily: terminal.getOption('fontFamily'),
fontSize: terminal.getOption('fontSize'),
fontWeight: terminal.getOption('fontWeight') as FontWeight,
fontWeightBold: terminal.getOption('fontWeightBold') as FontWeight,
allowTransparency: terminal.getOption('allowTransparency'),
colors: clonedColors
};
}
export function configEquals(a: ICharAtlasConfig, b: ICharAtlasConfig): boolean {
for (let i = 0; i < a.colors.ansi.length; i++) {
if (a.colors.ansi[i].rgba !== b.colors.ansi[i].rgba) {
return false;
}
}
return a.devicePixelRatio === b.devicePixelRatio &&
a.fontFamily === b.fontFamily &&
a.fontSize === b.fontSize &&
a.fontWeight === b.fontWeight &&
a.fontWeightBold === b.fontWeightBold &&
a.allowTransparency === b.allowTransparency &&
a.scaledCharWidth === b.scaledCharWidth &&
a.scaledCharHeight === b.scaledCharHeight &&
a.colors.foreground === b.colors.foreground &&
a.colors.background === b.colors.background;
}
export function is256Color(colorCode: number): boolean {
return colorCode < DEFAULT_COLOR;
}
@@ -4,13 +4,7 @@
*/
import { FontWeight } from 'xterm';
import { IColorSet } from '../Types';
export const DEFAULT_COLOR = 256;
export const INVERTED_DEFAULT_COLOR = 257;
export const DIM_OPACITY = 0.5;
export const CHAR_ATLAS_CELL_SPACING = 1;
import { IColorSet } from 'browser/Types';
export interface IGlyphIdentifier {
chars: string;
@@ -23,7 +17,6 @@ export interface IGlyphIdentifier {
}
export interface ICharAtlasConfig {
type: 'none' | 'static' | 'dynamic';
devicePixelRatio: number;
fontSize: number;
fontFamily: string;
@@ -0,0 +1,400 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { ICharAtlasConfig } from './Types';
import { DIM_OPACITY, INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { IRasterizedGlyph, IBoundingBox, IRasterizedGlyphSet } from '../Types';
import { DEFAULT_COLOR, DEFAULT_ATTR } from 'common/buffer/Constants';
import { is256Color } from './CharAtlasUtils';
import { throwIfFalsy } from '../WebglUtils';
import { IColor } from 'browser/Types';
import { FLAGS } from '../Constants';
import { IDisposable } from 'xterm';
// In practice we're probably never going to exhaust a texture this large. For debugging purposes,
// however, it can be useful to set this to a really tiny value, to verify that LRU eviction works.
const TEXTURE_WIDTH = 1024;
const TEXTURE_HEIGHT = 1024;
/**
* The amount of the texture to be filled before throwing it away and starting
* again. Since the throw away and individual glyph draws don't cost too much,
* this prevent juggling multiple textures in the GL context.
*/
const TEXTURE_CAPACITY = Math.floor(TEXTURE_HEIGHT * 0.8);
const TRANSPARENT_COLOR = {
css: 'rgba(0, 0, 0, 0)',
rgba: 0
};
/**
* A shared object which is used to draw nothing for a particular cell.
*/
const NULL_RASTERIZED_GLYPH: IRasterizedGlyph = {
offset: { x: 0, y: 0 },
texturePosition: { x: 0, y: 0 },
texturePositionClipSpace: { x: 0, y: 0 },
size: { x: 0, y: 0 },
sizeClipSpace: { x: 0, y: 0 }
};
const TMP_CANVAS_GLYPH_PADDING = 2;
export class WebglCharAtlas implements IDisposable {
private _didWarmUp: boolean = false;
private _cacheMap: { [code: number]: IRasterizedGlyphSet } = {};
private _cacheMapCombined: { [chars: string]: IRasterizedGlyphSet } = {};
// The texture that the atlas is drawn to
public cacheCanvas: HTMLCanvasElement;
private _cacheCtx: CanvasRenderingContext2D;
private _tmpCanvas: HTMLCanvasElement;
// A temporary context that glyphs are drawn to before being transfered to the atlas.
private _tmpCtx: CanvasRenderingContext2D;
// Since glyphs are expected to be around the same height, the packing
// strategy used it to fill a row with glyphs while keeping track of the
// tallest glyph in the row. Once the row is full a new row is started at
// (0,lastRow+lastRowTallestGlyph).
private _currentRowY: number = 0;
private _currentRowX: number = 0;
private _currentRowHeight: number = 0;
public hasCanvasChanged = false;
private _workBoundingBox: IBoundingBox = { top: 0, left: 0, bottom: 0, right: 0 };
constructor(document: Document, private _config: ICharAtlasConfig) {
this.cacheCanvas = document.createElement('canvas');
this.cacheCanvas.width = TEXTURE_WIDTH;
this.cacheCanvas.height = TEXTURE_HEIGHT;
// The canvas needs alpha because we use clearColor to convert the background color to alpha.
// It might also contain some characters with transparent backgrounds if allowTransparency is
// set.
this._cacheCtx = throwIfFalsy(this.cacheCanvas.getContext('2d', {alpha: true}));
this._tmpCanvas = document.createElement('canvas');
this._tmpCanvas.width = this._config.scaledCharWidth * 2 + TMP_CANVAS_GLYPH_PADDING * 2;
this._tmpCanvas.height = this._config.scaledCharHeight + TMP_CANVAS_GLYPH_PADDING * 2;
this._tmpCtx = throwIfFalsy(this._tmpCanvas.getContext('2d', {alpha: this._config.allowTransparency}));
// This is useful for debugging
document.body.appendChild(this.cacheCanvas);
}
public dispose(): void {
if (this.cacheCanvas.parentElement) {
this.cacheCanvas.parentElement.removeChild(this.cacheCanvas);
}
}
public warmUp(): void {
if (!this._didWarmUp) {
this._doWarmUp();
this._didWarmUp = true;
}
}
protected _doWarmUp(): void {
// Pre-fill with ASCII 33-126
for (let i = 33; i < 126; i++) {
const rasterizedGlyph = this._drawToCache(i, DEFAULT_ATTR, DEFAULT_COLOR, DEFAULT_COLOR);
this._cacheMap[i] = {
[DEFAULT_ATTR]: rasterizedGlyph
};
}
}
public beginFrame(): boolean {
if (this._currentRowY > TEXTURE_CAPACITY) {
this._cacheCtx.clearRect(0, 0, TEXTURE_WIDTH, TEXTURE_HEIGHT);
this._cacheMap = {};
this._currentRowHeight = 0;
this._currentRowX = 0;
this._currentRowY = 0;
this._doWarmUp();
return true;
}
return false;
}
public getRasterizedGlyphCombinedChar(chars: string, attr: number, bg: number, fg: number): IRasterizedGlyph {
let rasterizedGlyphSet = this._cacheMapCombined[chars];
if (!rasterizedGlyphSet) {
rasterizedGlyphSet = {};
this._cacheMapCombined[chars] = rasterizedGlyphSet;
}
let rasterizedGlyph = rasterizedGlyphSet[attr];
if (!rasterizedGlyph) {
rasterizedGlyph = this._drawToCache(chars, attr, bg, fg);
rasterizedGlyphSet[attr] = rasterizedGlyph;
}
return rasterizedGlyph;
}
/**
* Gets the glyphs texture coords, drawing the texture if it's not already
*/
public getRasterizedGlyph(code: number, attr: number, bg: number, fg: number): IRasterizedGlyph {
let rasterizedGlyphSet = this._cacheMap[code];
if (!rasterizedGlyphSet) {
rasterizedGlyphSet = {};
this._cacheMap[code] = rasterizedGlyphSet;
}
let rasterizedGlyph = rasterizedGlyphSet[attr];
if (!rasterizedGlyph) {
rasterizedGlyph = this._drawToCache(code, attr, bg, fg);
rasterizedGlyphSet[attr] = rasterizedGlyph;
}
return rasterizedGlyph;
}
private _getColorFromAnsiIndex(idx: number): IColor {
if (idx >= this._config.colors.ansi.length) {
throw new Error('No color found for idx ' + idx);
}
return this._config.colors.ansi[idx];
}
private _getBackgroundColor(bg: number): IColor {
if (this._config.allowTransparency) {
// The background color might have some transparency, so we need to render it as fully
// transparent in the atlas. Otherwise we'd end up drawing the transparent background twice
// around the anti-aliased edges of the glyph, and it would look too dark.
return TRANSPARENT_COLOR;
} else if (bg === INVERTED_DEFAULT_COLOR) {
return this._config.colors.foreground;
} else if (is256Color(bg)) {
return this._getColorFromAnsiIndex(bg);
}
// TODO: Support true color
return this._config.colors.background;
}
private _getForegroundColor(fg: number): IColor {
if (fg === INVERTED_DEFAULT_COLOR) {
return this._config.colors.background;
} else if (is256Color(fg)) {
return this._getColorFromAnsiIndex(fg);
}
// TODO: Support true color
return this._config.colors.foreground;
}
private _drawToCache(code: number, attr: number, bg: number, fg: number): IRasterizedGlyph;
private _drawToCache(chars: string, attr: number, bg: number, fg: number): IRasterizedGlyph;
private _drawToCache(codeOrChars: number | string, attr: number, bg: number, fg: number): IRasterizedGlyph {
const chars = typeof codeOrChars === 'number' ? String.fromCharCode(codeOrChars) : codeOrChars;
this.hasCanvasChanged = true;
const flags = attr >> 18;
const bold = !!(flags & FLAGS.BOLD);
const dim = !!(flags & FLAGS.DIM);
const italic = !!(flags & FLAGS.ITALIC);
this._tmpCtx.save();
// draw the background
const backgroundColor = this._getBackgroundColor(bg);
// Use a 'copy' composite operation to clear any existing glyph out of _tmpCtxWithAlpha, regardless of
// transparency in backgroundColor
this._tmpCtx.globalCompositeOperation = 'copy';
this._tmpCtx.fillStyle = backgroundColor.css;
this._tmpCtx.fillRect(0, 0, this._tmpCanvas.width, this._tmpCanvas.height);
this._tmpCtx.globalCompositeOperation = 'source-over';
// draw the foreground/glyph
const fontWeight = bold ? this._config.fontWeightBold : this._config.fontWeight;
const fontStyle = italic ? 'italic' : '';
this._tmpCtx.font =
`${fontStyle} ${fontWeight} ${this._config.fontSize * this._config.devicePixelRatio}px ${this._config.fontFamily}`;
this._tmpCtx.textBaseline = 'top';
this._tmpCtx.fillStyle = this._getForegroundColor(fg).css;
// Apply alpha to dim the character
if (dim) {
this._tmpCtx.globalAlpha = DIM_OPACITY;
}
// Draw the character
this._tmpCtx.fillText(chars, TMP_CANVAS_GLYPH_PADDING, TMP_CANVAS_GLYPH_PADDING);
this._tmpCtx.restore();
// clear the background from the character to avoid issues with drawing over the previous
// character if it extends past it's bounds
const imageData = this._tmpCtx.getImageData(
0, 0, this._tmpCanvas.width, this._tmpCanvas.height
);
// TODO: Support transparency
// let isEmpty = false;
// if (!this._config.allowTransparency) {
// isEmpty = clearColor(imageData, backgroundColor);
// }
// Clear out the background color and determine if the glyph is empty.
const isEmpty = clearColor(imageData, backgroundColor);
// Handle empty glyphs
if (isEmpty) {
return NULL_RASTERIZED_GLYPH;
}
const rasterizedGlyph = this._findGlyphBoundingBox(imageData, this._workBoundingBox);
const clippedImageData = this._clipImageData(imageData, this._workBoundingBox);
// Check if there is enough room in the current row and go to next if needed
if (this._currentRowX + this._config.scaledCharWidth > TEXTURE_WIDTH) {
this._currentRowX = 0;
this._currentRowY += this._currentRowHeight;
this._currentRowHeight = 0;
}
// Record texture position
rasterizedGlyph.texturePosition.x = this._currentRowX;
rasterizedGlyph.texturePosition.y = this._currentRowY;
rasterizedGlyph.texturePositionClipSpace.x = this._currentRowX / TEXTURE_WIDTH;
rasterizedGlyph.texturePositionClipSpace.y = this._currentRowY / TEXTURE_HEIGHT;
// Update atlas current row
this._currentRowHeight = Math.max(this._currentRowHeight, rasterizedGlyph.size.y);
this._currentRowX += rasterizedGlyph.size.x;
// putImageData doesn't do any blending, so it will overwrite any existing cache entry for us
this._cacheCtx.putImageData(clippedImageData, rasterizedGlyph.texturePosition.x, rasterizedGlyph.texturePosition.y);
return rasterizedGlyph;
}
/**
* Given an ImageData object, find the bounding box of the non-transparent
* portion of the texture and return an IRasterizedGlyph with these
* dimensions.
* @param imageData The image data to read.
* @param boundingBox An IBoundingBox to put the clipped bounding box values.
*/
private _findGlyphBoundingBox(imageData: ImageData, boundingBox: IBoundingBox): IRasterizedGlyph {
boundingBox.top = 0;
let found = false;
for (let y = 0; y < this._tmpCanvas.height; y++) {
for (let x = 0; x < this._tmpCanvas.width; x++) {
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3;
if (imageData.data[alphaOffset] !== 0) {
boundingBox.top = y;
found = true;
break;
}
}
if (found) {
break;
}
}
boundingBox.left = 0;
found = false;
for (let x = 0; x < this._tmpCanvas.width; x++) {
for (let y = 0; y < this._tmpCanvas.height; y++) {
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3;
if (imageData.data[alphaOffset] !== 0) {
boundingBox.left = x;
found = true;
break;
}
}
if (found) {
break;
}
}
boundingBox.right = this._tmpCanvas.width;
found = false;
for (let x = this._tmpCanvas.width - 1; x >= 0; x--) {
for (let y = 0; y < this._tmpCanvas.height; y++) {
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3;
if (imageData.data[alphaOffset] !== 0) {
boundingBox.right = x;
found = true;
break;
}
}
if (found) {
break;
}
}
boundingBox.bottom = this._tmpCanvas.height;
found = false;
for (let y = this._tmpCanvas.height - 1; y >= 0; y--) {
for (let x = 0; x < this._tmpCanvas.width; x++) {
const alphaOffset = y * this._tmpCanvas.width * 4 + x * 4 + 3;
if (imageData.data[alphaOffset] !== 0) {
boundingBox.bottom = y;
found = true;
break;
}
}
if (found) {
break;
}
}
return {
texturePosition: { x: 0, y: 0 },
texturePositionClipSpace: { x: 0, y: 0 },
size: {
x: boundingBox.right - boundingBox.left + 1,
y: boundingBox.bottom - boundingBox.top + 1
},
sizeClipSpace: {
x: (boundingBox.right - boundingBox.left + 1) / TEXTURE_WIDTH,
y: (boundingBox.bottom - boundingBox.top + 1) / TEXTURE_HEIGHT
},
offset: {
x: -boundingBox.left + TMP_CANVAS_GLYPH_PADDING,
y: -boundingBox.top + TMP_CANVAS_GLYPH_PADDING
}
};
}
private _clipImageData(imageData: ImageData, boundingBox: IBoundingBox): ImageData {
const width = boundingBox.right - boundingBox.left + 1;
const height = boundingBox.bottom - boundingBox.top + 1;
const clippedData = new Uint8ClampedArray(width * height * 4);
for (let y = boundingBox.top; y <= boundingBox.bottom; y++) {
for (let x = boundingBox.left; x <= boundingBox.right; x++) {
const oldOffset = y * this._tmpCanvas.width * 4 + x * 4;
const newOffset = (y - boundingBox.top) * width * 4 + (x - boundingBox.left) * 4;
clippedData[newOffset] = imageData.data[oldOffset];
clippedData[newOffset + 1] = imageData.data[oldOffset + 1];
clippedData[newOffset + 2] = imageData.data[oldOffset + 2];
clippedData[newOffset + 3] = imageData.data[oldOffset + 3];
}
}
return new ImageData(clippedData, width, height);
}
}
/**
* Makes a partiicular rgb color in an ImageData completely transparent.
* @returns True if the result is "empty", meaning all pixels are fully transparent.
*/
function clearColor(imageData: ImageData, color: IColor): boolean {
let isEmpty = true;
const r = color.rgba >>> 24;
const g = color.rgba >>> 16 & 0xFF;
const b = color.rgba >>> 8 & 0xFF;
for (let offset = 0; offset < imageData.data.length; offset += 4) {
if (imageData.data[offset] === r &&
imageData.data[offset + 1] === g &&
imageData.data[offset + 2] === b) {
imageData.data[offset + 3] = 0;
} else {
isEmpty = false;
}
}
return isEmpty;
}
@@ -0,0 +1,276 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IRenderLayer } from './Types';
import { IGlyphIdentifier } from '../atlas/Types';
import { acquireCharAtlas } from '../atlas/CharAtlasCache';
import { Terminal } from 'xterm';
import { IColorSet } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
import { CellData } from 'common/buffer/CellData';
import { WebglCharAtlas } from 'atlas/WebglCharAtlas';
import { throwIfFalsy } from '../WebglUtils';
export abstract class BaseRenderLayer implements IRenderLayer {
private _canvas: HTMLCanvasElement;
protected _ctx!: CanvasRenderingContext2D;
private _scaledCharWidth: number = 0;
private _scaledCharHeight: number = 0;
private _scaledCellWidth: number = 0;
private _scaledCellHeight: number = 0;
private _scaledCharLeft: number = 0;
private _scaledCharTop: number = 0;
protected _charAtlas: WebglCharAtlas | undefined;
/**
* An object that's reused when drawing glyphs in order to reduce GC.
*/
private _currentGlyphIdentifier: IGlyphIdentifier = {
chars: '',
code: 0,
bg: 0,
fg: 0,
bold: false,
dim: false,
italic: false
};
constructor(
private _container: HTMLElement,
id: string,
zIndex: number,
private _alpha: boolean,
protected _colors: IColorSet
) {
this._canvas = document.createElement('canvas');
this._canvas.classList.add(`xterm-${id}-layer`);
this._canvas.style.zIndex = zIndex.toString();
this._initCanvas();
this._container.appendChild(this._canvas);
}
public dispose(): void {
this._container.removeChild(this._canvas);
if (this._charAtlas) {
this._charAtlas.dispose();
}
}
private _initCanvas(): void {
this._ctx = throwIfFalsy(this._canvas.getContext('2d', {alpha: this._alpha}));
// Draw the background if this is an opaque layer
if (!this._alpha) {
this._clearAll();
}
}
public onOptionsChanged(terminal: Terminal): void {}
public onBlur(terminal: Terminal): void {}
public onFocus(terminal: Terminal): void {}
public onCursorMove(terminal: Terminal): void {}
public onGridChanged(terminal: Terminal, startRow: number, endRow: number): void {}
public onSelectionChanged(terminal: Terminal, start: [number, number], end: [number, number], columnSelectMode: boolean = false): void {}
public setColors(terminal: Terminal, colorSet: IColorSet): void {
this._refreshCharAtlas(terminal, colorSet);
}
protected _setTransparency(terminal: Terminal, alpha: boolean): void {
// Do nothing when alpha doesn't change
if (alpha === this._alpha) {
return;
}
// Create new canvas and replace old one
const oldCanvas = this._canvas;
this._alpha = alpha;
// Cloning preserves properties
this._canvas = <HTMLCanvasElement>this._canvas.cloneNode();
this._initCanvas();
this._container.replaceChild(this._canvas, oldCanvas);
// Regenerate char atlas and force a full redraw
this._refreshCharAtlas(terminal, this._colors);
this.onGridChanged(terminal, 0, terminal.rows - 1);
}
/**
* Refreshes the char atlas, aquiring a new one if necessary.
* @param terminal The terminal.
* @param colorSet The color set to use for the char atlas.
*/
private _refreshCharAtlas(terminal: Terminal, colorSet: IColorSet): void {
if (this._scaledCharWidth <= 0 && this._scaledCharHeight <= 0) {
return;
}
this._charAtlas = acquireCharAtlas(terminal, colorSet, this._scaledCharWidth, this._scaledCharHeight);
this._charAtlas.warmUp();
}
public resize(terminal: Terminal, dim: IRenderDimensions): void {
this._scaledCellWidth = dim.scaledCellWidth;
this._scaledCellHeight = dim.scaledCellHeight;
this._scaledCharWidth = dim.scaledCharWidth;
this._scaledCharHeight = dim.scaledCharHeight;
this._scaledCharLeft = dim.scaledCharLeft;
this._scaledCharTop = dim.scaledCharTop;
this._canvas.width = dim.scaledCanvasWidth;
this._canvas.height = dim.scaledCanvasHeight;
this._canvas.style.width = `${dim.canvasWidth}px`;
this._canvas.style.height = `${dim.canvasHeight}px`;
// Draw the background if this is an opaque layer
if (!this._alpha) {
this._clearAll();
}
this._refreshCharAtlas(terminal, this._colors);
}
public abstract reset(terminal: Terminal): void;
/**
* Fills 1+ cells completely. This uses the existing fillStyle on the context.
* @param x The column to start at.
* @param y The row to start at
* @param width The number of columns to fill.
* @param height The number of rows to fill.
*/
protected _fillCells(x: number, y: number, width: number, height: number): void {
this._ctx.fillRect(
x * this._scaledCellWidth,
y * this._scaledCellHeight,
width * this._scaledCellWidth,
height * this._scaledCellHeight);
}
/**
* Fills a 1px line (2px on HDPI) at the bottom of the cell. This uses the
* existing fillStyle on the context.
* @param x The column to fill.
* @param y The row to fill.
*/
protected _fillBottomLineAtCells(x: number, y: number, width: number = 1): void {
this._ctx.fillRect(
x * this._scaledCellWidth,
(y + 1) * this._scaledCellHeight - window.devicePixelRatio - 1 /* Ensure it's drawn within the cell */,
width * this._scaledCellWidth,
window.devicePixelRatio);
}
/**
* Fills a 1px line (2px on HDPI) at the left of the cell. This uses the
* existing fillStyle on the context.
* @param x The column to fill.
* @param y The row to fill.
*/
protected _fillLeftLineAtCell(x: number, y: number): void {
this._ctx.fillRect(
x * this._scaledCellWidth,
y * this._scaledCellHeight,
window.devicePixelRatio,
this._scaledCellHeight);
}
/**
* Strokes a 1px rectangle (2px on HDPI) around a cell. This uses the existing
* strokeStyle on the context.
* @param x The column to fill.
* @param y The row to fill.
*/
protected _strokeRectAtCell(x: number, y: number, width: number, height: number): void {
this._ctx.lineWidth = window.devicePixelRatio;
this._ctx.strokeRect(
x * this._scaledCellWidth + window.devicePixelRatio / 2,
y * this._scaledCellHeight + (window.devicePixelRatio / 2),
width * this._scaledCellWidth - window.devicePixelRatio,
(height * this._scaledCellHeight) - window.devicePixelRatio);
}
/**
* Clears the entire canvas.
*/
protected _clearAll(): void {
if (this._alpha) {
this._ctx.clearRect(0, 0, this._canvas.width, this._canvas.height);
} else {
this._ctx.fillStyle = this._colors.background.css;
this._ctx.fillRect(0, 0, this._canvas.width, this._canvas.height);
}
}
/**
* Clears 1+ cells completely.
* @param x The column to start at.
* @param y The row to start at.
* @param width The number of columns to clear.
* @param height The number of rows to clear.
*/
protected _clearCells(x: number, y: number, width: number, height: number): void {
if (this._alpha) {
this._ctx.clearRect(
x * this._scaledCellWidth,
y * this._scaledCellHeight,
width * this._scaledCellWidth,
height * this._scaledCellHeight);
} else {
this._ctx.fillStyle = this._colors.background.css;
this._ctx.fillRect(
x * this._scaledCellWidth,
y * this._scaledCellHeight,
width * this._scaledCellWidth,
height * this._scaledCellHeight);
}
}
/**
* Draws a truecolor character at the cell. The character will be clipped to
* ensure that it fits with the cell, including the cell to the right if it's
* a wide character. This uses the existing fillStyle on the context.
* @param terminal The terminal.
* @param cell The cell data for the character to draw.
* @param x The column to draw at.
* @param y The row to draw at.
* @param color The color of the character.
*/
protected _fillCharTrueColor(terminal: Terminal, cell: CellData, x: number, y: number): void {
this._ctx.font = this._getFont(terminal, false, false);
this._ctx.textBaseline = 'middle';
this._clipRow(terminal, y);
this._ctx.fillText(
cell.getChars(),
x * this._scaledCellWidth + this._scaledCharLeft,
y * this._scaledCellHeight + this._scaledCharTop + this._scaledCharHeight / 2);
}
/**
* Clips a row to ensure no pixels will be drawn outside the cells in the row.
* @param terminal The terminal.
* @param y The row to clip.
*/
private _clipRow(terminal: Terminal, y: number): void {
this._ctx.beginPath();
this._ctx.rect(
0,
y * this._scaledCellHeight,
terminal.cols * this._scaledCellWidth,
this._scaledCellHeight);
this._ctx.clip();
}
/**
* Gets the current font.
* @param terminal The terminal.
* @param isBold If we should use the bold fontWeight.
*/
protected _getFont(terminal: Terminal, isBold: boolean, isItalic: boolean): string {
const fontWeight = isBold ? terminal.getOption('fontWeightBold') : terminal.getOption('fontWeight');
const fontStyle = isItalic ? 'italic' : '';
return `${fontStyle} ${fontWeight} ${terminal.getOption('fontSize') * window.devicePixelRatio}px ${terminal.getOption('fontFamily')}`;
}
}
@@ -0,0 +1,363 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal } from 'xterm';
import { BaseRenderLayer } from './BaseRenderLayer';
import { ICellData } from 'common/Types';
import { CellData } from 'common/buffer/CellData';
import { IColorSet } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
interface ICursorState {
x: number;
y: number;
isFocused: boolean;
style: string;
width: number;
}
/**
* The time between cursor blinks.
*/
const BLINK_INTERVAL = 600;
export class CursorRenderLayer extends BaseRenderLayer {
private _state: ICursorState;
private _cursorRenderers: {[key: string]: (terminal: Terminal, x: number, y: number, cell: ICellData) => void};
private _cursorBlinkStateManager: CursorBlinkStateManager | undefined;
private _cell: ICellData = new CellData();
constructor(container: HTMLElement, zIndex: number, colors: IColorSet) {
super(container, 'cursor', zIndex, true, colors);
this._state = {
x: 0,
y: 0,
isFocused: false,
style: '',
width: 0
};
this._cursorRenderers = {
'bar': this._renderBarCursor.bind(this),
'block': this._renderBlockCursor.bind(this),
'underline': this._renderUnderlineCursor.bind(this)
};
// TODO: Consider initial options? Maybe onOptionsChanged should be called at the end of open?
}
public resize(terminal: Terminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
// Resizing the canvas discards the contents of the canvas so clear state
this._state = {
x: 0,
y: 0,
isFocused: false,
style: '',
width: 0
};
}
public reset(terminal: Terminal): void {
this._clearCursor();
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.dispose();
this.onOptionsChanged(terminal);
}
}
public onBlur(terminal: Terminal): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.pause();
}
terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY);
}
public onFocus(terminal: Terminal): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.resume(terminal);
} else {
terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY);
}
}
public onOptionsChanged(terminal: Terminal): void {
if (terminal.getOption('cursorBlink')) {
if (!this._cursorBlinkStateManager) {
this._cursorBlinkStateManager = new CursorBlinkStateManager(terminal, () => {
this._render(terminal, true);
});
}
} else {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.dispose();
}
}
// Request a refresh from the terminal as management of rendering is being
// moved back to the terminal
terminal.refresh(terminal.buffer.cursorY, terminal.buffer.cursorY);
}
public onCursorMove(terminal: Terminal): void {
if (this._cursorBlinkStateManager) {
this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
}
}
public onGridChanged(terminal: Terminal, startRow: number, endRow: number): void {
if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isPaused) {
this._render(terminal, false);
} else {
this._cursorBlinkStateManager.restartBlinkAnimation(terminal);
}
}
private _render(terminal: Terminal, triggeredByAnimationFrame: boolean): void {
// Don't draw the cursor if it's hidden
// TODO: Need to expose API for this
if (!(terminal as any)._core.cursorState || (terminal as any)._core.cursorHidden) {
this._clearCursor();
return;
}
const cursorY = terminal.buffer.baseY + terminal.buffer.cursorY;
const viewportRelativeCursorY = cursorY - terminal.buffer.viewportY;
// Don't draw the cursor if it's off-screen
if (viewportRelativeCursorY < 0 || viewportRelativeCursorY >= terminal.rows) {
this._clearCursor();
return;
}
// TODO: Need fast buffer API for loading cell
(terminal as any)._core.buffer.lines.get(cursorY).loadCell(terminal.buffer.cursorX, this._cell);
if (this._cell.content === undefined) {
return;
}
if (!isTerminalFocused(terminal)) {
this._clearCursor();
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
const cursorStyle = terminal.getOption('cursorStyle');
if (cursorStyle && cursorStyle !== 'block') {
this._cursorRenderers[cursorStyle](terminal, terminal.buffer.cursorX, viewportRelativeCursorY, this._cell);
} else {
this._renderBlurCursor(terminal, terminal.buffer.cursorX, viewportRelativeCursorY, this._cell);
}
this._ctx.restore();
this._state.x = terminal.buffer.cursorX;
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = cursorStyle;
this._state.width = this._cell.getWidth();
return;
}
// Don't draw the cursor if it's blinking
if (this._cursorBlinkStateManager && !this._cursorBlinkStateManager.isCursorVisible) {
this._clearCursor();
return;
}
if (this._state) {
// The cursor is already in the correct spot, don't redraw
if (this._state.x === terminal.buffer.cursorX &&
this._state.y === viewportRelativeCursorY &&
this._state.isFocused === isTerminalFocused(terminal) &&
this._state.style === terminal.getOption('cursorStyle') &&
this._state.width === this._cell.getWidth()) {
return;
}
this._clearCursor();
}
this._ctx.save();
this._cursorRenderers[terminal.getOption('cursorStyle') || 'block'](terminal, terminal.buffer.cursorX, viewportRelativeCursorY, this._cell);
this._ctx.restore();
this._state.x = terminal.buffer.cursorX;
this._state.y = viewportRelativeCursorY;
this._state.isFocused = false;
this._state.style = terminal.getOption('cursorStyle');
this._state.width = this._cell.getWidth();
}
private _clearCursor(): void {
if (this._state) {
this._clearCells(this._state.x, this._state.y, this._state.width, 1);
this._state = {
x: 0,
y: 0,
isFocused: false,
style: '',
width: 0
};
}
}
private _renderBarCursor(terminal: Terminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillLeftLineAtCell(x, y);
this._ctx.restore();
}
private _renderBlockCursor(terminal: Terminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillCells(x, y, cell.getWidth(), 1);
this._ctx.fillStyle = this._colors.cursorAccent.css;
this._fillCharTrueColor(terminal, cell, x, y);
this._ctx.restore();
}
private _renderUnderlineCursor(terminal: Terminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.fillStyle = this._colors.cursor.css;
this._fillBottomLineAtCells(x, y);
this._ctx.restore();
}
private _renderBlurCursor(terminal: Terminal, x: number, y: number, cell: ICellData): void {
this._ctx.save();
this._ctx.strokeStyle = this._colors.cursor.css;
this._strokeRectAtCell(x, y, cell.getWidth(), 1);
this._ctx.restore();
}
}
class CursorBlinkStateManager {
public isCursorVisible: boolean;
private _animationFrame: number | undefined;
private _blinkStartTimeout: number | undefined;
private _blinkInterval: number | undefined;
/**
* The time at which the animation frame was restarted, this is used on the
* next render to restart the timers so they don't need to restart the timers
* multiple times over a short period.
*/
private _animationTimeRestarted: number | undefined;
constructor(
terminal: Terminal,
private _renderCallback: () => void
) {
this.isCursorVisible = true;
if (isTerminalFocused(terminal)) {
this._restartInterval();
}
}
public get isPaused(): boolean { return !(this._blinkStartTimeout || this._blinkInterval); }
public dispose(): void {
if (this._blinkInterval) {
window.clearInterval(this._blinkInterval);
this._blinkInterval = undefined;
}
if (this._blinkStartTimeout) {
window.clearTimeout(this._blinkStartTimeout);
this._blinkStartTimeout = undefined;
}
if (this._animationFrame) {
window.cancelAnimationFrame(this._animationFrame);
this._animationFrame = undefined;
}
}
public restartBlinkAnimation(terminal: Terminal): void {
if (this.isPaused) {
return;
}
// Save a timestamp so that the restart can be done on the next interval
this._animationTimeRestarted = Date.now();
// Force a cursor render to ensure it's visible and in the correct position
this.isCursorVisible = true;
if (!this._animationFrame) {
this._animationFrame = window.requestAnimationFrame(() => {
this._renderCallback();
this._animationFrame = undefined;
});
}
}
private _restartInterval(timeToStart: number = BLINK_INTERVAL): void {
// Clear any existing interval
if (this._blinkInterval) {
window.clearInterval(this._blinkInterval);
}
// Setup the initial timeout which will hide the cursor, this is done before
// the regular interval is setup in order to support restarting the blink
// animation in a lightweight way (without thrashing clearInterval and
// setInterval).
this._blinkStartTimeout = <number><any>setTimeout(() => {
// Check if another animation restart was requested while this was being
// started
if (this._animationTimeRestarted) {
const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
this._animationTimeRestarted = undefined;
if (time > 0) {
this._restartInterval(time);
return;
}
}
// Hide the cursor
this.isCursorVisible = false;
this._animationFrame = window.requestAnimationFrame(() => {
this._renderCallback();
this._animationFrame = undefined;
});
// Setup the blink interval
this._blinkInterval = <number><any>setInterval(() => {
// Adjust the animation time if it was restarted
if (this._animationTimeRestarted) {
// calc time diff
// Make restart interval do a setTimeout initially?
const time = BLINK_INTERVAL - (Date.now() - this._animationTimeRestarted);
this._animationTimeRestarted = undefined;
this._restartInterval(time);
return;
}
// Invert visibility and render
this.isCursorVisible = !this.isCursorVisible;
this._animationFrame = window.requestAnimationFrame(() => {
this._renderCallback();
this._animationFrame = undefined;
});
}, BLINK_INTERVAL);
}, timeToStart);
}
public pause(): void {
this.isCursorVisible = true;
if (this._blinkInterval) {
window.clearInterval(this._blinkInterval);
this._blinkInterval = undefined;
}
if (this._blinkStartTimeout) {
window.clearTimeout(this._blinkStartTimeout);
this._blinkStartTimeout = undefined;
}
if (this._animationFrame) {
window.cancelAnimationFrame(this._animationFrame);
this._animationFrame = undefined;
}
}
public resume(terminal: Terminal): void {
this._animationTimeRestarted = undefined;
this._restartInterval();
this.restartBlinkAnimation(terminal);
}
}
function isTerminalFocused(terminal: Terminal): boolean {
return document.activeElement === terminal.textarea && document.hasFocus();
}
@@ -3,14 +3,16 @@
* @license MIT
*/
import { ILinkifierEvent, ITerminal, ILinkifierAccessor } from '../Types';
import { IColorSet, IRenderDimensions } from './Types';
import { ILinkifierAccessor } from '../../../../src/Types';
import { Terminal } from 'xterm';
import { BaseRenderLayer } from './BaseRenderLayer';
import { INVERTED_DEFAULT_COLOR } from './atlas/Types';
import { is256Color } from './atlas/CharAtlasUtils';
import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/atlas/Constants';
import { is256Color } from '../atlas/CharAtlasUtils';
import { IColorSet, ILinkifierEvent } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
export class LinkRenderLayer extends BaseRenderLayer {
private _state: ILinkifierEvent = null;
private _state: ILinkifierEvent | undefined;
constructor(container: HTMLElement, zIndex: number, colors: IColorSet, terminal: ILinkifierAccessor) {
super(container, 'link', zIndex, true, colors);
@@ -18,48 +20,48 @@ export class LinkRenderLayer extends BaseRenderLayer {
terminal.linkifier.onLinkLeave(e => this._onLinkLeave(e));
}
public resize(terminal: ITerminal, dim: IRenderDimensions): void {
public resize(terminal: Terminal, dim: IRenderDimensions): void {
super.resize(terminal, dim);
// Resizing the canvas discards the contents of the canvas so clear state
this._state = null;
this._state = undefined;
}
public reset(terminal: ITerminal): void {
public reset(terminal: Terminal): void {
this._clearCurrentLink();
}
private _clearCurrentLink(): void {
if (this._state) {
this.clearCells(this._state.x1, this._state.y1, this._state.cols - this._state.x1, 1);
this._clearCells(this._state.x1, this._state.y1, this._state.cols - this._state.x1, 1);
const middleRowCount = this._state.y2 - this._state.y1 - 1;
if (middleRowCount > 0) {
this.clearCells(0, this._state.y1 + 1, this._state.cols, middleRowCount);
this._clearCells(0, this._state.y1 + 1, this._state.cols, middleRowCount);
}
this.clearCells(0, this._state.y2, this._state.x2, 1);
this._state = null;
this._clearCells(0, this._state.y2, this._state.x2, 1);
this._state = undefined;
}
}
private _onLinkHover(e: ILinkifierEvent): void {
if (e.fg === INVERTED_DEFAULT_COLOR) {
this._ctx.fillStyle = this._colors.background.css;
} else if (is256Color(e.fg)) {
} else if (e.fg !== undefined && is256Color(e.fg)) {
// 256 color support
this._ctx.fillStyle = this._colors.ansi[e.fg].css;
this._ctx.fillStyle = this._colors.ansi[e.fg!].css;
} else {
this._ctx.fillStyle = this._colors.foreground.css;
}
if (e.y1 === e.y2) {
// Single line link
this.fillBottomLineAtCells(e.x1, e.y1, e.x2 - e.x1);
this._fillBottomLineAtCells(e.x1, e.y1, e.x2 - e.x1);
} else {
// Multi-line link
this.fillBottomLineAtCells(e.x1, e.y1, e.cols - e.x1);
this._fillBottomLineAtCells(e.x1, e.y1, e.cols - e.x1);
for (let y = e.y1 + 1; y < e.y2; y++) {
this.fillBottomLineAtCells(0, y, e.cols);
this._fillBottomLineAtCells(0, y, e.cols);
}
this.fillBottomLineAtCells(0, e.y2, e.x2);
this._fillBottomLineAtCells(0, e.y2, e.x2);
}
this._state = e;
}
@@ -0,0 +1,66 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { IDisposable, Terminal } from 'xterm';
import { IColorSet } from 'browser/Types';
import { IRenderDimensions } from 'browser/renderer/Types';
export interface IRenderLayer extends IDisposable {
/**
* Called when the terminal loses focus.
*/
onBlur(terminal: Terminal): void;
/**
* * Called when the terminal gets focus.
*/
onFocus(terminal: Terminal): void;
/**
* Called when the cursor is moved.
*/
onCursorMove(terminal: Terminal): void;
/**
* Called when options change.
*/
onOptionsChanged(terminal: Terminal): void;
/**
* Called when the theme changes.
*/
setColors(terminal: Terminal, colorSet: IColorSet): void;
/**
* Called when the data in the grid has changed (or needs to be rendered
* again).
*/
onGridChanged(terminal: Terminal, startRow: number, endRow: number): void;
/**
* Calls when the selection changes.
*/
onSelectionChanged(terminal: Terminal, start: [number, number], end: [number, number], columnSelectMode: boolean): void;
/**
* Registers a handler to join characters to render as a group
*/
registerCharacterJoiner?(handler: (text: string) => [number, number][]): void;
/**
* Deregisters the specified character joiner handler
*/
deregisterCharacterJoiner?(joinerId: number): void;
/**
* Resize the render layer.
*/
resize(terminal: Terminal, dim: IRenderDimensions): void;
/**
* Clear the state of the render layer.
*/
reset(terminal: Terminal): void;
}
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"lib": [
"dom",
"es6",
],
"rootDir": ".",
"outDir": "../out",
"sourceMap": true,
"removeComments": true,
"baseUrl": ".",
"paths": {
"common/*": [ "../../../src/common/*" ],
"browser/*": [ "../../../src/browser/*" ]
},
"strict": true
},
"include": [
"./**/*",
"../../../typings/xterm.d.ts"
],
"references": [
{ "path": "../../../src/common" },
{ "path": "../../../src/browser" }
]
}
+26
View File
@@ -0,0 +1,26 @@
/**
* Copyright (c) 2017 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { Terminal, IDisposable, ITerminalAddon } from 'xterm';
declare module 'xterm-addon-webgl' {
/**
* An xterm.js addon that provides search functionality.
*/
export class WebglAddon implements ITerminalAddon {
constructor(preserveDrawingBuffer?: boolean);
/**
* Activates the addon
* @param terminal The terminal the addon is being loaded in.
*/
public activate(terminal: Terminal): void;
/**
* Disposes the addon.
*/
public dispose(): void;
}
}
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const path = require('path');
const addonName = 'WebglAddon';
const mainFile = 'xterm-addon-webgl.js';
module.exports = {
entry: `./out/${addonName}.js`,
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre",
exclude: /node_modules/
}
]
},
resolve: {
modules: ['./node_modules'],
extensions: [ '.js' ],
alias: {
common: path.resolve('../../out/common'),
browser: path.resolve('../../out/browser')
}
},
output: {
filename: mainFile,
path: path.resolve('./lib'),
library: addonName,
libraryTarget: 'umd'
},
mode: 'production'
};
+53 -19
View File
@@ -20,8 +20,8 @@ jobs:
yarn
displayName: 'Install dependencies and build'
- script: |
yarn mocha
displayName: 'Test'
yarn test-unit --forbid-only
displayName: 'Unit tests'
- script: |
yarn lint
displayName: 'Lint'
@@ -38,16 +38,11 @@ jobs:
yarn
displayName: 'Install dependencies and build'
- script: |
yarn mocha
displayName: 'Test'
yarn test-unit --forbid-only
displayName: 'Unit tests'
- script: |
yarn lint
displayName: 'Lint'
- script: |
yarn test-coverage
export COVERALLS_GIT_BRANCH=$BUILD_SOURCEBRANCH
yarn coveralls
displayName: 'Generate and publish coverage'
- job: Windows
pool:
@@ -61,18 +56,58 @@ jobs:
yarn
displayName: 'Install dependencies and build'
- script: |
yarn mocha
displayName: 'Test'
yarn test-unit --forbid-only
displayName: 'Unit tests'
- script: |
yarn lint
displayName: 'Lint'
- job: Release
dependsOn:
- Linux
- macOS
- Windows
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
- job: Linux_IntegrationTests
pool:
vmImage: 'ubuntu-16.04'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.9.4"
displayName: 'Install Yarn'
- script: |
yarn
displayName: 'Install dependencies and build'
- script: |
yarn start &
sleep 10
yarn test-api --headless --forbid-only
displayName: 'Linux Integration tests'
- job: macOS_IntegrationTests
pool:
vmImage: 'xcode9-macos10.13'
steps:
- task: NodeTool@0
inputs:
versionSpec: '8.x'
displayName: 'Install Node.js'
- script: |
yarn
displayName: 'Install dependencies and build'
- script: |
yarn start &
sleep 10
yarn test-api --headless --forbid-only
displayName: 'MacOS Integration tests'
- job: Release
dependsOn:
- Linux
- macOS
- Windows
- Linux_IntegrationTests
- macOS_IntegrationTests
condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['FORCE_RELEASE'], 'true')))
pool:
vmImage: 'ubuntu-16.04'
steps:
@@ -86,8 +121,7 @@ jobs:
displayName: 'Install Yarn'
- script: |
yarn
BUILD_DIR=dist npm run build
displayName: 'Install dependencies and build'
- script: |
NPM_AUTH_TOKEN="$(NPM_AUTH_TOKEN)" node ./bin/publish.js
displayName: 'Publish to npm'
displayName: 'Package and publish to npm'
-24
View File
@@ -1,24 +0,0 @@
#! /usr/bin/env sh
# Usage: ./bin/prepare-release x.y.z
# x.y.z should be semver (e.g. 1.0.0)
set -e
NEW_VERSION=$1
CURRENT_PACKAGE_JSON_VERSION=$(cat package.json \
| grep version \
| head -1 \
| awk -F: '{ print $2 }' \
| sed 's/[",]//g' \
| tr -d '[[:space:]]')
# Build xterm.js into `dist`
export BUILD_DIR=dist
npm run build
# Update version in package.json
sed -i "s/\"version\": \"$CURRENT_PACKAGE_JSON_VERSION\"/\"version\": \"$NEW_VERSION\"/g" package.json
git commit -S -s -a -m "Bump version to $NEW_VERSION"
git tag $NEW_VERSION
+98 -26
View File
@@ -5,44 +5,99 @@
const cp = require('child_process');
const fs = require('fs');
const os = require('os');
const path = require('path');
const packageJson = require('../package.json');
// Setup auth
fs.writeFileSync(`${process.env['HOME']}/.npmrc`, `//registry.npmjs.org/:_authToken=${process.env['NPM_AUTH_TOKEN']}`);
// Determine if this is a stable or beta release
const publishedVersions = getPublishedVersions();
const isStableRelease = publishedVersions.indexOf(packageJson.version) === -1;
// Get the next version
let nextVersion = isStableRelease ? packageJson.version : getNextBetaVersion();
console.log(`Publishing version: ${nextVersion}`);
// Set the version in package.json
const packageJsonFile = path.resolve(__dirname, '..', 'package.json');
packageJson.version = nextVersion;
fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2));
// Publish
const args = ['publish'];
if (!isStableRelease) {
args.push('--tag', 'beta');
const isDryRun = process.argv.indexOf('--dry') !== -1;
if (isDryRun) {
console.log('Publish dry run');
}
const result = cp.spawn('npm', args, { stdio: 'inherit' });
result.on('exit', code => process.exit(code));
function getNextBetaVersion() {
const changedFiles = getChangedFilesInCommit('HEAD');
// Publish xterm if any files were changed outside of the addons directory
let isStableRelease = false;
if (changedFiles.some(e => e.search(/^addons\//) === -1)) {
isStableRelease = checkAndPublishPackage(path.resolve(__dirname, '..'));
}
// Publish addons if any files were changed inside of the addon
const addonPackageDirs = [
path.resolve(__dirname, '../addons/xterm-addon-attach'),
path.resolve(__dirname, '../addons/xterm-addon-fit'),
path.resolve(__dirname, '../addons/xterm-addon-search'),
path.resolve(__dirname, '../addons/xterm-addon-web-links'),
path.resolve(__dirname, '../addons/xterm-addon-webgl')
];
console.log(`Checking if addons need to be published`);
addonPackageDirs.forEach(p => {
const addon = path.basename(p);
if (changedFiles.some(e => e.indexOf(addon) !== -1)) {
console.log(`Try publish ${addon}`);
checkAndPublishPackage(p);
}
});
// Publish website if it's a stable release
if (isStableRelease) {
updateWebsite();
}
function checkAndPublishPackage(packageDir) {
const packageJson = require(path.join(packageDir, 'package.json'));
// Determine if this is a stable or beta release
const publishedVersions = getPublishedVersions(packageJson);
const isStableRelease = publishedVersions.indexOf(packageJson.version) === -1;
// Get the next version
let nextVersion = isStableRelease ? packageJson.version : getNextBetaVersion(packageJson);
console.log(`Publishing version: ${nextVersion}`);
// Set the version in package.json
const packageJsonFile = path.join(packageDir, 'package.json');
packageJson.version = nextVersion;
console.log(`Set version of ${packageJsonFile} to ${nextVersion}`);
if (!isDryRun) {
fs.writeFileSync(packageJsonFile, JSON.stringify(packageJson, null, 2));
}
// Publish
const args = ['publish'];
if (!isStableRelease) {
args.push('--tag', 'beta');
}
console.log(`Spawn: npm ${args.join(' ')}`);
if (!isDryRun) {
const result = cp.spawnSync('npm', args, {
cwd: packageDir,
stdio: 'inherit'
});
if (result.status) {
console.error(`Spawn exited with code ${result.status}`);
process.exit(result.status);
}
}
console.groupEnd();
return isStableRelease;
}
function getNextBetaVersion(packageJson) {
if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.exec(packageJson.version)) {
console.error('The package.json version must be of the form x.y.z');
process.exit(1);
}
const tag = 'beta';
const stableVersion = packageJson.version.split('.');
const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.${stableVersion[2]}`;
const publishedVersions = getPublishedVersions(nextStableVersion, tag);
const nextStableVersion = `${stableVersion[0]}.${parseInt(stableVersion[1]) + 1}.0`;
const publishedVersions = getPublishedVersions(packageJson, nextStableVersion, tag);
if (publishedVersions.length === 0) {
return `${packageJson.version}-${tag}1`;
return `${nextStableVersion}-${tag}1`;
}
const latestPublishedVersion = publishedVersions.sort((a, b) => {
const aVersion = parseInt(a.substr(a.search(/[0-9]+$/)));
@@ -53,11 +108,28 @@ function getNextBetaVersion() {
return `${nextStableVersion}-${tag}${latestTagVersion + 1}`;
}
function getPublishedVersions(version, tag) {
const versionsProcess = cp.spawnSync('npm', ['view', 'xterm', 'versions', '--json']);
function getPublishedVersions(packageJson, version, tag) {
const versionsProcess = cp.spawnSync('npm', ['view', packageJson.name, 'versions', '--json']);
const versionsJson = JSON.parse(versionsProcess.stdout);
if (tag) {
return versionsJson.filter(v => !v.search(new RegExp(`${version}-${tag}[0-9]+`)));
}
return versionsJson;
}
function getChangedFilesInCommit(commit) {
const args = ['log', '-m', '-1', '--name-only', `--pretty=format:`, commit];
const result = cp.spawnSync('git', args);
const output = result.stdout.toString();
const changedFiles = output.split('\n').filter(e => e.length > 0);
return changedFiles;
}
function updateWebsite() {
console.log('Updating website');
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'website-'));
const packageJson = require(path.join(path.resolve(__dirname, '..'), 'package.json'));
if (!isDryRun) {
cp.spawnSync('sh', [path.join(__dirname, 'update-website.sh'), packageJson.version], { cwd, stdio: [process.stdin, process.stdout, process.stderr] });
}
}
-22
View File
@@ -1,22 +0,0 @@
#! /usr/bin/env sh
# Usage: ./bin/release x.y.z
# x.y.z should be semver (e.g. 1.0.0)
set -e
if [ -z "$1" ];
then
echo "No version supplied. Please a version argument\n"
echo "Usage: $0 VERSION\n"
echo "Example: $0 1.0.0"
exit
fi
NEW_VERSION=$1
./bin/prepare-release $NEW_VERSION
git push && \
git push --tags && \
npm publish
+41
View File
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*/
const cp = require('child_process');
const path = require('path');
// Add `out` to the NODE_PATH so absolute paths can be resolved.
const env = { ...process.env };
env.NODE_PATH = path.resolve(__dirname, '../out');
let testFiles = [
'./out/*test.js',
'./out/**/*test.js'
];
let flagArgs = [];
if (process.argv.length > 2) {
const args = process.argv.slice(2);
flagArgs = args.filter(e => e.startsWith('--'));
// ability to inject particular test files via
// yarn test [testFileA testFileB ...]
files = args.filter(e => !e.startsWith('--'));
if (files.length) {
testFiles = files;
}
}
const run = cp.spawnSync(
path.resolve(__dirname, '../node_modules/.bin/mocha'),
[...testFiles, ...flagArgs],
{
cwd: path.resolve(__dirname, '..'),
env,
stdio: 'inherit'
}
);
process.exit(run.status);
+212
View File
@@ -0,0 +1,212 @@
/**
* Copyright (c) 2019 The xterm.js authors. All rights reserved.
* @license MIT
*
* Script to test different mouse modes in terminal emulators.
* Tests for protocols DECSET 9, 1000, 1002, 1003 with different
* report encodings (default, UTF8, SGR, URXVT).
*
* VT200 Highlight mode (DECSET 1001) is not implemented.
*
* The test basically applies the report data to the cursor, thus
* a mouse report should move the cursor to the cell under the mouse.
* Furthermore the reports are printed in the left lower corner as
* raw data and their meaning.
*
* A failing test might show:
* - wrong coords: the cursor will jump to some other place
* - wrong buttons: see meaning output and check whether it makes sense
* - faulty reports: inspect the raw data and compare with other emulators
* - missing events: compare with spec / other emulators
*/
let activeProtocol = 0;
let activeEnc = 0;
const stdin = process.openStdin();
process.stdin.setRawMode(true);
// close handler - reset terminal on exit
stdin.addListener('data', function(data) {
if (data[0] === 0x03) {
process.stdin.setRawMode(false);
process.stdout.write('\x1bc');
process.exit();
}
if (data[0] === 0x01) {
switchActiveProtocol();
printMenu();
}
if (data[0] === 0x02) {
switchActiveEnc();
printMenu();
}
console.log('\x1b[100;H\x1b[2A\x1b[2KReport:', data, [data.toString('binary')]);
// filter mouse reports
if (data[0] === 0x1b && data[1] === '['.charCodeAt(0)) {
applyReportData(data);
}
});
// button definitions
const buttons = {
'<none>': -1,
left: 0,
middle: 1,
right: 2,
released: 3,
wheelUp: 4,
wheelDown: 5,
wheelLeft: 6,
wheelRight: 7,
aux1: 8,
aux2: 9,
aux3: 10,
aux4: 11,
aux5: 12,
aux6: 13,
aux7: 14,
aux8: 15
};
const reverseButtons = {};
for (const el in buttons) {
reverseButtons[buttons[el]] = el;
}
// extract button data from buttonCode
function evalButtonCode(code) {
// more than 15 buttons are not supported
if (code > 255) {
return {button: 'invalid', action: 'invalid', modifier: {}};
}
const modifier = {shift: !!(code & 4), meta: !!(code & 8), control: !!(code & 16)};
const move = code & 32;
let button = code & 3;
if (code & 128) {
button |= 8;
}
if (code & 64) {
button |= 4
}
let actionS = 'press';
let buttonS = reverseButtons[button];
if (button === 3) {
buttonS = '<none>';
actionS = 'release';
}
if (move) {
actionS = 'move';
} else if (4 <= button && button <= 7) {
buttonS = 'wheel';
actionS = button === 4 ? 'up' : button === 5 ? 'down' : button === 6 ? 'left' : 'right';
}
return {button: buttonS, action: actionS, modifier};
}
// protocols
const PROTOCOLS = {
'9 (X10: press only)': '\x1b[?9h',
'1000 (VT200: press, release, wheel)': '\x1b[?1000h',
// '1001 (VT200 highlight)': '\x1b[?1001h', // handle of backreport - not implemented
'1002 (press, release, move on pressed, wheel)': '\x1b[?1002h',
'1003 (press, relase, move, wheel)': '\x1b[?1003h'
}
// encodings: ENCODING_NAME => [sequence, parse_report]
const ENC = {
'DEFAULT' : [
'',
// format: CSI M <button + 32> <row + 32> <col + 32>
report => ({
state: evalButtonCode(report[3] - 32),
col: report[4] - 32,
row: report[5] - 32
})
],
'UTF8' : [
'\x1b[?1005h',
// format: CSI M <button + 32> <row + 32> <col + 32>
// + utf8 encoding on row/col
report => {
const sReport = report.toString(); // decode with utf8
return {
state: evalButtonCode(sReport.charCodeAt(3) - 32),
col: sReport.charCodeAt(4) - 32,
row: sReport.charCodeAt(5) - 32
};
}
],
'SGR' : [
'\x1b[?1006h',
// format: CSI < Pbutton ; Prow ; Pcol M
report => {
// strip off introducer + M
const sReport = report.toString().slice(3, -1);
const [buttonCode, col, row] = sReport.split(';');
const state = evalButtonCode(buttonCode);
if (report[report.length - 1] === 'm'.charCodeAt(0)) {
state.action = 'release';
}
return {state, row, col};
}
],
'URXVT': [
'\x1b[?1015h',
// format: CSI <button + 32> ; Prow ; Pcol M
report => {
// strip off introducer + M
const sReport = report.toString().slice(2, -1);
const [button, col, row] = sReport.split(';');
return {state: evalButtonCode(button - 32), row, col};
}
]
}
function printMenu() {
console.log('\x1b[2J\x1b\[HTest mouse reports [Ctrl-C to exit]');
console.log();
console.log(' Selected protocol [Ctrl-A to switch]');
const protocols = Object.keys(PROTOCOLS);
for (let i = 0; i < protocols.length; ++i) {
console.log(` ${activeProtocol === i ? '->' : ' '} ${protocols[i]}`);
}
console.log();
console.log(' Selected encoding [Ctrl-B to switch]');
const encs = Object.keys(ENC);
for (let i = 0; i < encs.length; ++i) {
console.log(` ${activeEnc === i ? '->' : ' '} ${encs[i]}`);
}
process.stdout.write('\x1b[100;H');
}
function switchActiveProtocol() {
activeProtocol++;
activeProtocol %= Object.keys(PROTOCOLS).length;
activate();
}
function switchActiveEnc() {
activeEnc++;
activeEnc %= Object.keys(ENC).length;
activate();
}
function activate() {
// clear all protocols and encodings
process.stdout.write('\x1b[?9l\x1b[?1000l\x1b[?1001l\x1b[?1002l\x1b[?1003l');
process.stdout.write('\x1b[?1005l\x1b[?1006l\x1b[?1015l');
// apply new protocol and encoding
process.stdout.write(PROTOCOLS[Object.keys(PROTOCOLS)[activeProtocol]]);
process.stdout.write(ENC[Object.keys(ENC)[activeEnc]][0]);
console.log('\x1b[100;H\x1b[2A\x1b[2KReport:');
}
function applyReportData(data) {
let {state, row, col} = ENC[Object.keys(ENC)[activeEnc]][1](data);
console.log('\x1b[2KButton:', state.button, 'Action:', state.action, 'Modifier:', state.modifier, 'row:', row, 'col:', col);
// apply to cursor position
process.stdout.write(`\x1b[${row};${col}H`);
}
printMenu();
activate();
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
# Name the arguments
VERSION=$1
# Clone docs repo and update the documentation
git clone https://github.com/xtermjs/xtermjs.org
cd xtermjs.org
yarn
./bin/update-docs
# Add changes to index and only proceed if there are changes to commit
touch test-file
git add .
if ! git diff-index --quiet HEAD --; then
# Delete the upstream branch if it exists for some reason
export BRANCH_NAME=update-$VERSION
git branch -D $BRANCH_NAME || true
git push origin :$BRANCH_NAME || true
# Create commit and push it to update-x.y.z
git checkout -b $BRANCH_NAME
git config --global user.name Daniel Imms
git config --global user.email tyriar@tyriar.com
git commit -m 'Update docs for v$VERSION'
git push --set-upstream origin update-4.2.0
git push -f
# Create a PR in the GitHub repo
curl \
-H "Authorization: token $GITHUB_TOKEN" \
-X POST \
-d "{\"title\":\"Update docs for v$VERSION\",\"base\":\"master\",\"head\":\"xtermjs:$BRANCH_NAME\"}" \
https://api.github.com/repos/xtermjs/xtermjs.org/pulls
else
echo "No changes to commit"
fi
+3 -3
View File
@@ -55,7 +55,7 @@
* The z-index of the helpers must be higher than the canvases in order for
* IMEs to appear on top.
*/
z-index: 10;
z-index: 5;
}
.xterm .xterm-helper-textarea {
@@ -69,7 +69,7 @@
top: 0;
width: 0;
height: 0;
z-index: -10;
z-index: -5;
/** Prevent wrapping so the IME appears against the textarea at the correct position */
white-space: nowrap;
overflow: hidden;
@@ -150,7 +150,7 @@
top: 0;
bottom: 0;
right: 0;
z-index: 100;
z-index: 10;
color: transparent;
}
+64 -37
View File
@@ -7,13 +7,21 @@
/// <reference path="../typings/xterm.d.ts"/>
import { Terminal } from '../lib/public/Terminal';
import * as attach from '../lib/addons/attach/attach';
import * as fit from '../lib/addons/fit/fit';
import * as fullscreen from '../lib/addons/fullscreen/fullscreen';
import * as search from '../lib/addons/search/search';
import * as webLinks from '../lib/addons/webLinks/webLinks';
import { ISearchOptions } from '../lib/addons/search/Interfaces';
// Use tsc version (yarn watch)
import { Terminal } from '../out/public/Terminal';
import { AttachAddon } from '../addons/xterm-addon-attach/out/AttachAddon';
import { FitAddon } from '../addons/xterm-addon-fit/out/FitAddon';
import { SearchAddon, ISearchOptions } from '../addons/xterm-addon-search/out/SearchAddon';
import { WebLinksAddon } from '../addons/xterm-addon-web-links/out/WebLinksAddon';
import { WebglAddon } from '../addons/xterm-addon-webgl/out/WebglAddon';
// Use webpacked version (yarn package)
// import { Terminal } from '../lib/xterm';
// import { AttachAddon } from 'xterm-addon-attach';
// import { FitAddon } from 'xterm-addon-fit';
// import { SearchAddon, ISearchOptions } from 'xterm-addon-search';
// import { WebLinksAddon } from 'xterm-addon-web-links';
// import { WebglAddon } from 'xterm-addon-webgl';
// Pulling in the module's types relies on the <reference> above, it's looks a
// little weird here as we're importing "this" module
@@ -21,17 +29,18 @@ import { Terminal as TerminalType, ITerminalOptions } from 'xterm';
export interface IWindowWithTerminal extends Window {
term: TerminalType;
Terminal?: typeof TerminalType;
AttachAddon?: typeof AttachAddon;
FitAddon?: typeof FitAddon;
SearchAddon?: typeof SearchAddon;
WebLinksAddon?: typeof WebLinksAddon;
WebglAddon?: typeof WebglAddon;
}
declare let window: IWindowWithTerminal;
Terminal.applyAddon(attach);
Terminal.applyAddon(fit);
Terminal.applyAddon(fullscreen);
Terminal.applyAddon(search);
Terminal.applyAddon(webLinks);
let term;
let fitAddon: FitAddon;
let searchAddon: SearchAddon;
let protocol;
let socketURL;
let socket;
@@ -49,16 +58,15 @@ function setPadding(): void {
term.fit();
}
function getSearchOptions(): ISearchOptions {
function getSearchOptions(e: KeyboardEvent): ISearchOptions {
return {
regex: (document.getElementById('regex') as HTMLInputElement).checked,
wholeWord: (document.getElementById('whole-word') as HTMLInputElement).checked,
caseSensitive: (document.getElementById('case-sensitive') as HTMLInputElement).checked
caseSensitive: (document.getElementById('case-sensitive') as HTMLInputElement).checked,
incremental: e.key !== `Enter`
};
}
createTerminal();
const disposeRecreateButtonHandler = () => {
// If the terminal exists dispose of it, otherwise recreate it
if (term) {
@@ -74,17 +82,38 @@ const disposeRecreateButtonHandler = () => {
}
};
document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler);
if (document.location.pathname === '/test') {
window.Terminal = Terminal;
window.AttachAddon = AttachAddon;
window.FitAddon = FitAddon;
window.SearchAddon = SearchAddon;
window.WebLinksAddon = WebLinksAddon;
window.WebglAddon = WebglAddon;
} else {
createTerminal();
document.getElementById('dispose').addEventListener('click', disposeRecreateButtonHandler);
document.getElementById('webgl').addEventListener('click', () => term.loadAddon(new WebglAddon()));
}
function createTerminal(): void {
// Clean terminal
while (terminalContainer.children.length) {
terminalContainer.removeChild(terminalContainer.children[0]);
}
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
term = new Terminal({
windowsMode: isWindows
} as ITerminalOptions);
// Load addons
const typedTerm = term as TerminalType;
typedTerm.loadAddon(new WebLinksAddon());
searchAddon = new SearchAddon();
typedTerm.loadAddon(searchAddon);
fitAddon = new FitAddon();
typedTerm.loadAddon(fitAddon);
window.term = term; // Expose `term` to window for debugging purposes
term.onResize((size: { cols: number, rows: number }) => {
if (!pid) {
@@ -100,23 +129,17 @@ function createTerminal(): void {
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
term.open(terminalContainer);
term.webLinksInit();
term.fit();
fitAddon.fit();
term.focus();
addDomListener(paddingElement, 'change', setPadding);
addDomListener(actionElements.findNext, 'keyup', (e) => {
const searchOptions = getSearchOptions();
searchOptions.incremental = e.key !== `Enter`;
term.findNext(actionElements.findNext.value, searchOptions);
searchAddon.findNext(actionElements.findNext.value, getSearchOptions(e));
});
addDomListener(actionElements.findPrevious, 'keyup', (e) => {
if (e.key === `Enter`) {
term.findPrevious(actionElements.findPrevious.value, getSearchOptions());
}
searchAddon.findPrevious(actionElements.findPrevious.value, getSearchOptions(e));
});
// fit is called within a setTimeout, cols and rows need this.
@@ -144,7 +167,7 @@ function createTerminal(): void {
}
function runRealTerminal(): void {
term.attach(socket);
term.loadAddon(new AttachAddon(socket));
term._initialized = true;
}
@@ -187,7 +210,6 @@ function initOptions(term: TerminalType): void {
// Internal only options
'cancelEvents',
'convertEol',
'debug',
'handler',
'screenKeys',
'termName',
@@ -199,11 +221,13 @@ function initOptions(term: TerminalType): void {
bellSound: null,
bellStyle: ['none', 'sound'],
cursorStyle: ['block', 'underline', 'bar'],
experimentalCharAtlas: ['none', 'static', 'dynamic'],
fastScrollModifier: ['alt', 'ctrl', 'shift', undefined],
fontFamily: null,
fontWeight: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
fontWeightBold: ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
rendererType: ['dom', 'canvas']
logLevel: ['debug', 'info', 'warn', 'error', 'off'],
rendererType: ['dom', 'canvas'],
wordSeparator: null
};
const options = Object.keys((<any>term)._core.options);
const booleanOptions = [];
@@ -230,7 +254,7 @@ function initOptions(term: TerminalType): void {
});
html += '</div><div class="option-group">';
numberOptions.forEach(o => {
html += `<div class="option"><label>${o} <input id="opt-${o}" type="number" value="${term.getOption(o)}" step="${o === 'lineHeight' ? '0.1' : '1'}"/></label></div>`;
html += `<div class="option"><label>${o} <input id="opt-${o}" type="number" value="${term.getOption(o)}" step="${o === 'lineHeight' || o === 'scrollSensitivity' ? '0.1' : '1'}"/></label></div>`;
});
html += '</div><div class="option-group">';
Object.keys(stringOptions).forEach(o => {
@@ -259,8 +283,11 @@ function initOptions(term: TerminalType): void {
console.log('change', o, input.value);
if (o === 'cols' || o === 'rows') {
updateTerminalSize();
} else if (o === 'lineHeight' || o === 'scrollSensitivity') {
term.setOption(o, parseFloat(input.value));
updateTerminalSize();
} else {
term.setOption(o, o === 'lineHeight' ? parseFloat(input.value) : parseInt(input.value, 10));
term.setOption(o, parseInt(input.value));
}
});
});
@@ -281,9 +308,9 @@ function addDomListener(element: HTMLElement, type: string, handler: (...args: a
function updateTerminalSize(): void {
const cols = parseInt((<HTMLInputElement>document.getElementById(`opt-cols`)).value, 10);
const rows = parseInt((<HTMLInputElement>document.getElementById(`opt-rows`)).value, 10);
const width = (cols * term._core.renderer.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px';
const height = (rows * term._core.renderer.dimensions.actualCellHeight).toString() + 'px';
const width = (cols * term._core._renderService.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px';
const height = (rows * term._core._renderService.dimensions.actualCellHeight).toString() + 'px';
terminalContainer.style.width = width;
terminalContainer.style.height = height;
term.fit();
fitAddon.fit();
}
+5 -4
View File
@@ -2,9 +2,9 @@
<html>
<head>
<title>xterm.js demo</title>
<link rel="stylesheet" href="/src/xterm.css" />
<link rel="stylesheet" href="/src/addons/fullscreen/fullscreen.css" />
<link rel="stylesheet" href="style.css" />
<link rel="shortcut icon" type="image/png" href="/logo.png">
<link rel="stylesheet" href="/xterm.css" />
<link rel="stylesheet" href="/style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/4.1.1/es6-promise.auto.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/1.0.0/fetch.min.js"></script>
</head>
@@ -16,7 +16,7 @@
<p>
<label>Find next <input id="find-next"/></label>
<label>Find previous <input id="find-previous"/></label>
<label>Use regex<input type="checkbox" id="regex"/></label>
<label>Use regex<input type="checkbox" id="regex"/></label>
<label>Case sensitive<input type="checkbox" id="case-sensitive"/></label>
<label>Whole word<input type="checkbox" id="whole-word"/></label>
</p>
@@ -36,6 +36,7 @@
<hr/>
<p><strong>Attention:</strong> The demo is a barebones implementation and is designed for the development and evaluation of xterm.js only. Exposing the demo to the public as is would introduce security risks for the host.</p>
<button id="dispose" title="This is used to testing memory leaks">Dispose terminal</button>
<button id="webgl">Enable WebGL Renderer</button>
<script src="dist/client-bundle.js" defer ></script>
</body>
</html>
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

+43 -12
View File
@@ -3,6 +3,9 @@ var expressWs = require('express-ws');
var os = require('os');
var pty = require('node-pty');
// Whether to use binary transport.
const USE_BINARY = os.platform() !== "win32";
function startServer() {
var app = express();
expressWs(app);
@@ -10,29 +13,38 @@ function startServer() {
var terminals = {},
logs = {};
app.use('/src', express.static(__dirname + '/../src'));
app.use('/xterm.css', express.static(__dirname + '/../css/xterm.css'));
app.get('/logo.png', (req, res) => { // lgtm [js/missing-rate-limiting]
res.sendFile(__dirname + '/logo.png');
});
app.get('/', function(req, res){
app.get('/', (req, res) => { // lgtm [js/missing-rate-limiting]
res.sendFile(__dirname + '/index.html');
});
app.get('/style.css', function(req, res){
app.get('/test', (req, res) => { // lgtm [js/missing-rate-limiting]
res.sendFile(__dirname + '/test.html');
});
app.get('/style.css', (req, res) => { // lgtm [js/missing-rate-limiting]
res.sendFile(__dirname + '/style.css');
});
app.get('/dist/client-bundle.js', function(req, res){
res.sendFile(__dirname + '/dist/client-bundle.js');
});
app.use('/dist', express.static(__dirname + '/dist'));
app.use('/src', express.static(__dirname + '/src'));
app.post('/terminals', function (req, res) {
app.post('/terminals', (req, res) => {
const env = Object.assign({}, process.env);
env['COLORTERM'] = 'truecolor';
var cols = parseInt(req.query.cols),
rows = parseInt(req.query.rows),
term = pty.spawn(process.platform === 'win32' ? 'cmd.exe' : 'bash', [], {
name: 'xterm-color',
name: 'xterm-256color',
cols: cols || 80,
rows: rows || 24,
cwd: process.env.PWD,
env: process.env
cwd: env.PWD,
env: env,
encoding: USE_BINARY ? null : 'utf8'
});
console.log('Created terminal with PID: ' + term.pid);
@@ -45,7 +57,7 @@ function startServer() {
res.end();
});
app.post('/terminals/:pid/size', function (req, res) {
app.post('/terminals/:pid/size', (req, res) => {
var pid = parseInt(req.params.pid),
cols = parseInt(req.query.cols),
rows = parseInt(req.query.rows),
@@ -61,6 +73,7 @@ function startServer() {
console.log('Connected to terminal ' + term.pid);
ws.send(logs[term.pid]);
// string message buffering
function buffer(socket, timeout) {
let s = '';
let sender = null;
@@ -75,7 +88,25 @@ function startServer() {
}
};
}
const send = buffer(ws, 5);
// binary message buffering
function bufferUtf8(socket, timeout) {
let buffer = [];
let sender = null;
let length = 0;
return (data) => {
buffer.push(data);
length += data.length;
if (!sender) {
sender = setTimeout(() => {
socket.send(Buffer.concat(buffer, length));
buffer = [];
sender = null;
length = 0;
}, timeout);
}
};
}
const send = USE_BINARY ? bufferUtf8(ws, 5) : buffer(ws, 5);
term.on('data', function(data) {
try {
+22 -3
View File
@@ -11,7 +11,16 @@ const startServer = require('./server.js');
startServer();
// Build/watch client source
/**
* This webpack config builds and watches the demo project. It works by taking the output from tsc
* (via `yarn watch`) which is put into `out/` and then webpacks it into `demo/dist/`. The aliases
* are used fix up the absolute paths output by tsc (because of `baseUrl` and `paths` in
* `tsconfig.json`.
*
* For production builds see `webpack.config.js` in the root directory. If that is built the demo
* can use that by switching out which `Terminal` is imported in `client.ts`, this is useful for
* validating that the packaged version works correctly.
*/
const clientConfig = {
entry: path.resolve(__dirname, 'client.ts'),
devtool: 'inline-source-map',
@@ -25,12 +34,22 @@ const clientConfig = {
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre"
enforce: "pre",
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
modules: [
'node_modules',
path.resolve(__dirname, '..'),
path.resolve(__dirname, '../addons')
],
extensions: [ '.tsx', '.ts', '.js' ],
alias: {
common: path.resolve('./out/common'),
browser: path.resolve('./out/browser')
}
},
output: {
filename: 'client-bundle.js',
+12
View File
@@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<title>xterm.js integration test fixture</title>
<link rel="stylesheet" href="/xterm.css" />
<link rel="stylesheet" href="/style.css" />
</head>
<body>
<div id="terminal-container"></div>
<script src="dist/client-bundle.js" defer ></script>
</body>
</html>
+10 -2
View File
@@ -1,9 +1,17 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"target": "es2015",
"rootDir": ".",
"sourceMap": true
"sourceMap": true,
"baseUrl": ".",
"paths": {
"xterm-addon-attach": ["../addons/xterm-addon-attach"],
"xterm-addon-fit": ["../addons/xterm-addon-fit"],
"xterm-addon-search": ["../addons/xterm-addon-search"],
"xterm-addon-web-links": ["../addons/xterm-addon-web-links"],
"xterm-addon-webgl": ["../addons/xterm-addon-webgl"]
}
},
"include": [
"client.ts",
@@ -0,0 +1,73 @@
from glob import glob
import os
import sys
import termios
import atexit
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def enable_echo(fd, enabled):
(iflag, oflag, cflag, lflag, ispeed, ospeed, cc) = termios.tcgetattr(fd)
if enabled:
lflag |= termios.ECHO
else:
lflag &= ~termios.ECHO
new_attr = [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
termios.tcsetattr(fd, termios.TCSANOW, new_attr)
atexit.register(enable_echo, sys.stdin.fileno(), True)
output = []
def log(append=False, *s):
if append:
output[-1] += ' ' + ' '.join(str(part) for part in s)
else:
output.append(' '.join(str(part) for part in s))
def reset_terminal():
sys.stdout.write('\x1bc\x1b[H')
sys.stdout.flush()
def test():
count = 0
passed = 0
for i, testfile in enumerate(sorted(glob(os.path.join(BASE_DIR, '*.in')))):
count += 1
log(False, os.path.basename(testfile))
reset_terminal()
with open(testfile) as test:
sys.stdout.write('\x1b]0;%s\x07' % os.path.basename(testfile))
sys.stdout.write(test.read()+'\x1bt')
sys.stdout.flush()
with open(os.path.join(os.path.dirname(testfile),
os.path.basename(testfile).split('.')[0]+'.text')) as expected:
terminal_output = sys.stdin.read()
if not terminal_output:
# we are in xterm
continue
if terminal_output != expected.read():
log(True, '\x1b[31merror\x1b[0m')
with open(os.path.join(os.path.dirname(testfile), 'output',
os.path.basename(testfile)), 'w') as t_out:
t_out.write(terminal_output)
else:
passed += 1
log(True, '\x1b[32mpass\x1b[0m')
return count, passed
if __name__ == '__main__':
enable_echo(sys.stdin.fileno(), False)
count, passed = test()
enable_echo(sys.stdin.fileno(), True)
reset_terminal()
for i in range(len(output)/2+1):
if not (i+1) % 25:
sys.stdin.read()
print ''.join(i.ljust(40) for i in output[i*2:i*2+2])
print '\x1b[33mcoverage: %s/%s (%d%%) tests passed.\x1b[0m' % (passed, count, passed*100/count)
@@ -27,5 +27,5 @@ r
s
t
uvwxyz


The end.
@@ -1,25 +1,25 @@
1
2
6
7
8
9 ABC
6
7
8
9 ABC
DEF
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
yz qrstu vwx
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
yz vwx
The end.
@@ -1,3 +1,3 @@
1D2D3D4D5D6D7D8D9ABCDEFaDbDcDdDeDfDgDhDiDjDkDlDmDnDoDpDqDrDsDtDuvwxyz


The end.
@@ -1,4 +1,3 @@
2
6
7
8
@@ -21,5 +20,6 @@ DEF
o
p
q
The end. rstu vwx
yz rstu vwx
The end.
@@ -1,24 +1,25 @@
a
b
c
d
f
g
h
i
b
c
d
f
g
h
i
j
k
l
m
j
k
l
m
n
o
p
q
r
s
w
x
n
o
p
q
r
s
w
x
@@ -0,0 +1,24 @@
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x12
@@ -0,0 +1,25 @@
a
b
c
d
e
f
g
h
i
2
k
l
m
n
o
p
q
r
1
t
u
v
w
x
@@ -0,0 +1,24 @@
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x1
@@ -0,0 +1,25 @@
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
1
@@ -1,25 +1,25 @@
n
o
p
q
r
s
t
u
v
w
x
y
z
1
2
3
4
5
6
7
8
9
10
o
p
q
r
s
t
u
v
w
x
y
z
1
2
3
4
5
6
7
8
9
10
11
11

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