From 036cc23e9bfe2364dc0cc4e336ebb7e1032909bf Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Wed, 27 Sep 2017 22:30:31 +0200 Subject: [PATCH 01/86] Fix file permissions (why do so many have the x flag?) --- js/lib/chibi.js | 0 js/utils.js | 0 pages/cfg_wifi_conn.php | 0 sass/_grid-settings.scss | 0 sass/_normalize.scss | 0 sass/_utils.scss | 0 sass/app.scss | 0 sass/form/_buttons.scss | 0 sass/form/_fancy_button_mixins.scss | 0 sass/form/_form_elements.scss | 0 sass/form/_form_layout.scss | 0 sass/form/_index.scss | 0 sass/form/_select.scss | 0 sass/layout/_base.scss | 0 sass/layout/_box.scss | 0 sass/layout/_content.scss | 0 sass/layout/_index.scss | 0 sass/layout/_menu.scss | 0 sass/layout/_modal.scss | 0 sass/layout/_outer-wrap.scss | 0 sass/lib/bourbon/_bourbon-deprecated-upcoming.scss | 0 sass/lib/bourbon/_bourbon.scss | 0 sass/lib/bourbon/addons/_border-color.scss | 0 sass/lib/bourbon/addons/_border-radius.scss | 0 sass/lib/bourbon/addons/_border-style.scss | 0 sass/lib/bourbon/addons/_border-width.scss | 0 sass/lib/bourbon/addons/_buttons.scss | 0 sass/lib/bourbon/addons/_clearfix.scss | 0 sass/lib/bourbon/addons/_ellipsis.scss | 0 sass/lib/bourbon/addons/_font-stacks.scss | 0 sass/lib/bourbon/addons/_hide-text.scss | 0 sass/lib/bourbon/addons/_margin.scss | 0 sass/lib/bourbon/addons/_padding.scss | 0 sass/lib/bourbon/addons/_position.scss | 0 sass/lib/bourbon/addons/_prefixer.scss | 0 sass/lib/bourbon/addons/_retina-image.scss | 0 sass/lib/bourbon/addons/_size.scss | 0 sass/lib/bourbon/addons/_text-inputs.scss | 0 sass/lib/bourbon/addons/_timing-functions.scss | 0 sass/lib/bourbon/addons/_triangle.scss | 0 sass/lib/bourbon/addons/_word-wrap.scss | 0 sass/lib/bourbon/css3/_animation.scss | 0 sass/lib/bourbon/css3/_appearance.scss | 0 sass/lib/bourbon/css3/_backface-visibility.scss | 0 sass/lib/bourbon/css3/_background-image.scss | 0 sass/lib/bourbon/css3/_background.scss | 0 sass/lib/bourbon/css3/_border-image.scss | 0 sass/lib/bourbon/css3/_calc.scss | 0 sass/lib/bourbon/css3/_columns.scss | 0 sass/lib/bourbon/css3/_filter.scss | 0 sass/lib/bourbon/css3/_flex-box.scss | 0 sass/lib/bourbon/css3/_font-face.scss | 0 sass/lib/bourbon/css3/_font-feature-settings.scss | 0 sass/lib/bourbon/css3/_hidpi-media-query.scss | 0 sass/lib/bourbon/css3/_hyphens.scss | 0 sass/lib/bourbon/css3/_image-rendering.scss | 0 sass/lib/bourbon/css3/_keyframes.scss | 0 sass/lib/bourbon/css3/_linear-gradient.scss | 0 sass/lib/bourbon/css3/_perspective.scss | 0 sass/lib/bourbon/css3/_placeholder.scss | 0 sass/lib/bourbon/css3/_radial-gradient.scss | 0 sass/lib/bourbon/css3/_selection.scss | 0 sass/lib/bourbon/css3/_text-decoration.scss | 0 sass/lib/bourbon/css3/_transform.scss | 0 sass/lib/bourbon/css3/_transition.scss | 0 sass/lib/bourbon/css3/_user-select.scss | 0 sass/lib/bourbon/functions/_assign-inputs.scss | 0 sass/lib/bourbon/functions/_contains-falsy.scss | 0 sass/lib/bourbon/functions/_contains.scss | 0 sass/lib/bourbon/functions/_is-length.scss | 0 sass/lib/bourbon/functions/_is-light.scss | 0 sass/lib/bourbon/functions/_is-number.scss | 0 sass/lib/bourbon/functions/_is-size.scss | 0 sass/lib/bourbon/functions/_modular-scale.scss | 0 sass/lib/bourbon/functions/_px-to-em.scss | 0 sass/lib/bourbon/functions/_px-to-rem.scss | 0 sass/lib/bourbon/functions/_shade.scss | 0 sass/lib/bourbon/functions/_strip-units.scss | 0 sass/lib/bourbon/functions/_tint.scss | 0 sass/lib/bourbon/functions/_transition-property-name.scss | 0 sass/lib/bourbon/functions/_unpack.scss | 0 sass/lib/bourbon/helpers/_convert-units.scss | 0 sass/lib/bourbon/helpers/_directional-values.scss | 0 sass/lib/bourbon/helpers/_font-source-declaration.scss | 0 sass/lib/bourbon/helpers/_gradient-positions-parser.scss | 0 sass/lib/bourbon/helpers/_linear-angle-parser.scss | 0 sass/lib/bourbon/helpers/_linear-gradient-parser.scss | 0 sass/lib/bourbon/helpers/_linear-positions-parser.scss | 0 sass/lib/bourbon/helpers/_linear-side-corner-parser.scss | 0 sass/lib/bourbon/helpers/_radial-arg-parser.scss | 0 sass/lib/bourbon/helpers/_radial-gradient-parser.scss | 0 sass/lib/bourbon/helpers/_radial-positions-parser.scss | 0 sass/lib/bourbon/helpers/_render-gradients.scss | 0 sass/lib/bourbon/helpers/_shape-size-stripper.scss | 0 sass/lib/bourbon/helpers/_str-to-num.scss | 0 sass/lib/bourbon/settings/_asset-pipeline.scss | 0 sass/lib/bourbon/settings/_prefixer.scss | 0 sass/lib/bourbon/settings/_px-to-em.scss | 0 sass/lib/neat/_neat-helpers.scss | 0 sass/lib/neat/_neat.scss | 0 sass/lib/neat/functions/_new-breakpoint.scss | 0 sass/lib/neat/functions/_private.scss | 0 sass/lib/neat/grid/_box-sizing.scss | 0 sass/lib/neat/grid/_direction-context.scss | 0 sass/lib/neat/grid/_display-context.scss | 0 sass/lib/neat/grid/_fill-parent.scss | 0 sass/lib/neat/grid/_media.scss | 0 sass/lib/neat/grid/_omega.scss | 0 sass/lib/neat/grid/_outer-container.scss | 0 sass/lib/neat/grid/_pad.scss | 0 sass/lib/neat/grid/_private.scss | 0 sass/lib/neat/grid/_row.scss | 0 sass/lib/neat/grid/_shift.scss | 0 sass/lib/neat/grid/_span-columns.scss | 0 sass/lib/neat/grid/_to-deprecate.scss | 0 sass/lib/neat/grid/_visual-grid.scss | 0 sass/lib/neat/settings/_disable-warnings.scss | 0 sass/lib/neat/settings/_grid.scss | 0 sass/lib/neat/settings/_visual-grid.scss | 0 sass/pages/_term.scss | 0 sass/pages/_wifi.scss | 0 sass/utils/_background-tiling.scss | 0 sass/utils/_index.scss | 0 sass/utils/_misc.scss | 0 sass/utils/_pointer.scss | 0 125 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 js/lib/chibi.js mode change 100755 => 100644 js/utils.js mode change 100755 => 100644 pages/cfg_wifi_conn.php mode change 100755 => 100644 sass/_grid-settings.scss mode change 100755 => 100644 sass/_normalize.scss mode change 100755 => 100644 sass/_utils.scss mode change 100755 => 100644 sass/app.scss mode change 100755 => 100644 sass/form/_buttons.scss mode change 100755 => 100644 sass/form/_fancy_button_mixins.scss mode change 100755 => 100644 sass/form/_form_elements.scss mode change 100755 => 100644 sass/form/_form_layout.scss mode change 100755 => 100644 sass/form/_index.scss mode change 100755 => 100644 sass/form/_select.scss mode change 100755 => 100644 sass/layout/_base.scss mode change 100755 => 100644 sass/layout/_box.scss mode change 100755 => 100644 sass/layout/_content.scss mode change 100755 => 100644 sass/layout/_index.scss mode change 100755 => 100644 sass/layout/_menu.scss mode change 100755 => 100644 sass/layout/_modal.scss mode change 100755 => 100644 sass/layout/_outer-wrap.scss mode change 100755 => 100644 sass/lib/bourbon/_bourbon-deprecated-upcoming.scss mode change 100755 => 100644 sass/lib/bourbon/_bourbon.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_border-color.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_border-radius.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_border-style.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_border-width.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_buttons.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_clearfix.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_ellipsis.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_font-stacks.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_hide-text.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_margin.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_padding.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_position.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_prefixer.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_retina-image.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_size.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_text-inputs.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_timing-functions.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_triangle.scss mode change 100755 => 100644 sass/lib/bourbon/addons/_word-wrap.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_animation.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_appearance.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_backface-visibility.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_background-image.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_background.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_border-image.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_calc.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_columns.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_filter.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_flex-box.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_font-face.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_font-feature-settings.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_hidpi-media-query.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_hyphens.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_image-rendering.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_keyframes.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_linear-gradient.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_perspective.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_placeholder.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_radial-gradient.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_selection.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_text-decoration.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_transform.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_transition.scss mode change 100755 => 100644 sass/lib/bourbon/css3/_user-select.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_assign-inputs.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_contains-falsy.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_contains.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_is-length.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_is-light.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_is-number.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_is-size.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_modular-scale.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_px-to-em.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_px-to-rem.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_shade.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_strip-units.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_tint.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_transition-property-name.scss mode change 100755 => 100644 sass/lib/bourbon/functions/_unpack.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_convert-units.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_directional-values.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_font-source-declaration.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_gradient-positions-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_linear-angle-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_linear-gradient-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_linear-positions-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_linear-side-corner-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_radial-arg-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_radial-gradient-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_radial-positions-parser.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_render-gradients.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_shape-size-stripper.scss mode change 100755 => 100644 sass/lib/bourbon/helpers/_str-to-num.scss mode change 100755 => 100644 sass/lib/bourbon/settings/_asset-pipeline.scss mode change 100755 => 100644 sass/lib/bourbon/settings/_prefixer.scss mode change 100755 => 100644 sass/lib/bourbon/settings/_px-to-em.scss mode change 100755 => 100644 sass/lib/neat/_neat-helpers.scss mode change 100755 => 100644 sass/lib/neat/_neat.scss mode change 100755 => 100644 sass/lib/neat/functions/_new-breakpoint.scss mode change 100755 => 100644 sass/lib/neat/functions/_private.scss mode change 100755 => 100644 sass/lib/neat/grid/_box-sizing.scss mode change 100755 => 100644 sass/lib/neat/grid/_direction-context.scss mode change 100755 => 100644 sass/lib/neat/grid/_display-context.scss mode change 100755 => 100644 sass/lib/neat/grid/_fill-parent.scss mode change 100755 => 100644 sass/lib/neat/grid/_media.scss mode change 100755 => 100644 sass/lib/neat/grid/_omega.scss mode change 100755 => 100644 sass/lib/neat/grid/_outer-container.scss mode change 100755 => 100644 sass/lib/neat/grid/_pad.scss mode change 100755 => 100644 sass/lib/neat/grid/_private.scss mode change 100755 => 100644 sass/lib/neat/grid/_row.scss mode change 100755 => 100644 sass/lib/neat/grid/_shift.scss mode change 100755 => 100644 sass/lib/neat/grid/_span-columns.scss mode change 100755 => 100644 sass/lib/neat/grid/_to-deprecate.scss mode change 100755 => 100644 sass/lib/neat/grid/_visual-grid.scss mode change 100755 => 100644 sass/lib/neat/settings/_disable-warnings.scss mode change 100755 => 100644 sass/lib/neat/settings/_grid.scss mode change 100755 => 100644 sass/lib/neat/settings/_visual-grid.scss mode change 100755 => 100644 sass/pages/_term.scss mode change 100755 => 100644 sass/pages/_wifi.scss mode change 100755 => 100644 sass/utils/_background-tiling.scss mode change 100755 => 100644 sass/utils/_index.scss mode change 100755 => 100644 sass/utils/_misc.scss mode change 100755 => 100644 sass/utils/_pointer.scss diff --git a/js/lib/chibi.js b/js/lib/chibi.js old mode 100755 new mode 100644 diff --git a/js/utils.js b/js/utils.js old mode 100755 new mode 100644 diff --git a/pages/cfg_wifi_conn.php b/pages/cfg_wifi_conn.php old mode 100755 new mode 100644 diff --git a/sass/_grid-settings.scss b/sass/_grid-settings.scss old mode 100755 new mode 100644 diff --git a/sass/_normalize.scss b/sass/_normalize.scss old mode 100755 new mode 100644 diff --git a/sass/_utils.scss b/sass/_utils.scss old mode 100755 new mode 100644 diff --git a/sass/app.scss b/sass/app.scss old mode 100755 new mode 100644 diff --git a/sass/form/_buttons.scss b/sass/form/_buttons.scss old mode 100755 new mode 100644 diff --git a/sass/form/_fancy_button_mixins.scss b/sass/form/_fancy_button_mixins.scss old mode 100755 new mode 100644 diff --git a/sass/form/_form_elements.scss b/sass/form/_form_elements.scss old mode 100755 new mode 100644 diff --git a/sass/form/_form_layout.scss b/sass/form/_form_layout.scss old mode 100755 new mode 100644 diff --git a/sass/form/_index.scss b/sass/form/_index.scss old mode 100755 new mode 100644 diff --git a/sass/form/_select.scss b/sass/form/_select.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_base.scss b/sass/layout/_base.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_box.scss b/sass/layout/_box.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_content.scss b/sass/layout/_content.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_index.scss b/sass/layout/_index.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_menu.scss b/sass/layout/_menu.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_modal.scss b/sass/layout/_modal.scss old mode 100755 new mode 100644 diff --git a/sass/layout/_outer-wrap.scss b/sass/layout/_outer-wrap.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/_bourbon-deprecated-upcoming.scss b/sass/lib/bourbon/_bourbon-deprecated-upcoming.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/_bourbon.scss b/sass/lib/bourbon/_bourbon.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_border-color.scss b/sass/lib/bourbon/addons/_border-color.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_border-radius.scss b/sass/lib/bourbon/addons/_border-radius.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_border-style.scss b/sass/lib/bourbon/addons/_border-style.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_border-width.scss b/sass/lib/bourbon/addons/_border-width.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_buttons.scss b/sass/lib/bourbon/addons/_buttons.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_clearfix.scss b/sass/lib/bourbon/addons/_clearfix.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_ellipsis.scss b/sass/lib/bourbon/addons/_ellipsis.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_font-stacks.scss b/sass/lib/bourbon/addons/_font-stacks.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_hide-text.scss b/sass/lib/bourbon/addons/_hide-text.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_margin.scss b/sass/lib/bourbon/addons/_margin.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_padding.scss b/sass/lib/bourbon/addons/_padding.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_position.scss b/sass/lib/bourbon/addons/_position.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_prefixer.scss b/sass/lib/bourbon/addons/_prefixer.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_retina-image.scss b/sass/lib/bourbon/addons/_retina-image.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_size.scss b/sass/lib/bourbon/addons/_size.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_text-inputs.scss b/sass/lib/bourbon/addons/_text-inputs.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_timing-functions.scss b/sass/lib/bourbon/addons/_timing-functions.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_triangle.scss b/sass/lib/bourbon/addons/_triangle.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/addons/_word-wrap.scss b/sass/lib/bourbon/addons/_word-wrap.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_animation.scss b/sass/lib/bourbon/css3/_animation.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_appearance.scss b/sass/lib/bourbon/css3/_appearance.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_backface-visibility.scss b/sass/lib/bourbon/css3/_backface-visibility.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_background-image.scss b/sass/lib/bourbon/css3/_background-image.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_background.scss b/sass/lib/bourbon/css3/_background.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_border-image.scss b/sass/lib/bourbon/css3/_border-image.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_calc.scss b/sass/lib/bourbon/css3/_calc.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_columns.scss b/sass/lib/bourbon/css3/_columns.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_filter.scss b/sass/lib/bourbon/css3/_filter.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_flex-box.scss b/sass/lib/bourbon/css3/_flex-box.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_font-face.scss b/sass/lib/bourbon/css3/_font-face.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_font-feature-settings.scss b/sass/lib/bourbon/css3/_font-feature-settings.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_hidpi-media-query.scss b/sass/lib/bourbon/css3/_hidpi-media-query.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_hyphens.scss b/sass/lib/bourbon/css3/_hyphens.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_image-rendering.scss b/sass/lib/bourbon/css3/_image-rendering.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_keyframes.scss b/sass/lib/bourbon/css3/_keyframes.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_linear-gradient.scss b/sass/lib/bourbon/css3/_linear-gradient.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_perspective.scss b/sass/lib/bourbon/css3/_perspective.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_placeholder.scss b/sass/lib/bourbon/css3/_placeholder.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_radial-gradient.scss b/sass/lib/bourbon/css3/_radial-gradient.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_selection.scss b/sass/lib/bourbon/css3/_selection.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_text-decoration.scss b/sass/lib/bourbon/css3/_text-decoration.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_transform.scss b/sass/lib/bourbon/css3/_transform.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_transition.scss b/sass/lib/bourbon/css3/_transition.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/css3/_user-select.scss b/sass/lib/bourbon/css3/_user-select.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_assign-inputs.scss b/sass/lib/bourbon/functions/_assign-inputs.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_contains-falsy.scss b/sass/lib/bourbon/functions/_contains-falsy.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_contains.scss b/sass/lib/bourbon/functions/_contains.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_is-length.scss b/sass/lib/bourbon/functions/_is-length.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_is-light.scss b/sass/lib/bourbon/functions/_is-light.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_is-number.scss b/sass/lib/bourbon/functions/_is-number.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_is-size.scss b/sass/lib/bourbon/functions/_is-size.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_modular-scale.scss b/sass/lib/bourbon/functions/_modular-scale.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_px-to-em.scss b/sass/lib/bourbon/functions/_px-to-em.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_px-to-rem.scss b/sass/lib/bourbon/functions/_px-to-rem.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_shade.scss b/sass/lib/bourbon/functions/_shade.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_strip-units.scss b/sass/lib/bourbon/functions/_strip-units.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_tint.scss b/sass/lib/bourbon/functions/_tint.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_transition-property-name.scss b/sass/lib/bourbon/functions/_transition-property-name.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/functions/_unpack.scss b/sass/lib/bourbon/functions/_unpack.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_convert-units.scss b/sass/lib/bourbon/helpers/_convert-units.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_directional-values.scss b/sass/lib/bourbon/helpers/_directional-values.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_font-source-declaration.scss b/sass/lib/bourbon/helpers/_font-source-declaration.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_gradient-positions-parser.scss b/sass/lib/bourbon/helpers/_gradient-positions-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_linear-angle-parser.scss b/sass/lib/bourbon/helpers/_linear-angle-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_linear-gradient-parser.scss b/sass/lib/bourbon/helpers/_linear-gradient-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_linear-positions-parser.scss b/sass/lib/bourbon/helpers/_linear-positions-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_linear-side-corner-parser.scss b/sass/lib/bourbon/helpers/_linear-side-corner-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_radial-arg-parser.scss b/sass/lib/bourbon/helpers/_radial-arg-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_radial-gradient-parser.scss b/sass/lib/bourbon/helpers/_radial-gradient-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_radial-positions-parser.scss b/sass/lib/bourbon/helpers/_radial-positions-parser.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_render-gradients.scss b/sass/lib/bourbon/helpers/_render-gradients.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_shape-size-stripper.scss b/sass/lib/bourbon/helpers/_shape-size-stripper.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/helpers/_str-to-num.scss b/sass/lib/bourbon/helpers/_str-to-num.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/settings/_asset-pipeline.scss b/sass/lib/bourbon/settings/_asset-pipeline.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/settings/_prefixer.scss b/sass/lib/bourbon/settings/_prefixer.scss old mode 100755 new mode 100644 diff --git a/sass/lib/bourbon/settings/_px-to-em.scss b/sass/lib/bourbon/settings/_px-to-em.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/_neat-helpers.scss b/sass/lib/neat/_neat-helpers.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/_neat.scss b/sass/lib/neat/_neat.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/functions/_new-breakpoint.scss b/sass/lib/neat/functions/_new-breakpoint.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/functions/_private.scss b/sass/lib/neat/functions/_private.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_box-sizing.scss b/sass/lib/neat/grid/_box-sizing.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_direction-context.scss b/sass/lib/neat/grid/_direction-context.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_display-context.scss b/sass/lib/neat/grid/_display-context.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_fill-parent.scss b/sass/lib/neat/grid/_fill-parent.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_media.scss b/sass/lib/neat/grid/_media.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_omega.scss b/sass/lib/neat/grid/_omega.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_outer-container.scss b/sass/lib/neat/grid/_outer-container.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_pad.scss b/sass/lib/neat/grid/_pad.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_private.scss b/sass/lib/neat/grid/_private.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_row.scss b/sass/lib/neat/grid/_row.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_shift.scss b/sass/lib/neat/grid/_shift.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_span-columns.scss b/sass/lib/neat/grid/_span-columns.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_to-deprecate.scss b/sass/lib/neat/grid/_to-deprecate.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/grid/_visual-grid.scss b/sass/lib/neat/grid/_visual-grid.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/settings/_disable-warnings.scss b/sass/lib/neat/settings/_disable-warnings.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/settings/_grid.scss b/sass/lib/neat/settings/_grid.scss old mode 100755 new mode 100644 diff --git a/sass/lib/neat/settings/_visual-grid.scss b/sass/lib/neat/settings/_visual-grid.scss old mode 100755 new mode 100644 diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss old mode 100755 new mode 100644 diff --git a/sass/pages/_wifi.scss b/sass/pages/_wifi.scss old mode 100755 new mode 100644 diff --git a/sass/utils/_background-tiling.scss b/sass/utils/_background-tiling.scss old mode 100755 new mode 100644 diff --git a/sass/utils/_index.scss b/sass/utils/_index.scss old mode 100755 new mode 100644 diff --git a/sass/utils/_misc.scss b/sass/utils/_misc.scss old mode 100755 new mode 100644 diff --git a/sass/utils/_pointer.scss b/sass/utils/_pointer.scss old mode 100755 new mode 100644 From ba24c4f9675853332be57459f397233aaba7e7af Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Wed, 27 Sep 2017 22:34:14 +0200 Subject: [PATCH 02/86] Remove hackity hack setting debug canvas styles --- js/term/debug_screen.js | 6 +----- sass/pages/_term.scss | 7 +++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/js/term/debug_screen.js b/js/term/debug_screen.js index d49d747..dc9dcee 100644 --- a/js/term/debug_screen.js +++ b/js/term/debug_screen.js @@ -4,11 +4,7 @@ module.exports = function attachDebugScreen (screen) { const debugCanvas = mk('canvas') const ctx = debugCanvas.getContext('2d') - debugCanvas.style.position = 'absolute' - // hackity hack should probably set this in CSS - debugCanvas.style.top = '6px' - debugCanvas.style.left = '6px' - debugCanvas.style.pointerEvents = 'none' + debugCanvas.classList.add('debug-canvas') let addCanvas = function () { if (!debugCanvas.parentNode) screen.canvas.parentNode.appendChild(debugCanvas) diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index 0bbc809..19df4d1 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -67,6 +67,13 @@ body.term { } } + .debug-canvas { + position: absolute; + top: 6px; + left: 6px; + pointer-events: none; + } + .debug-toolbar { line-height: 1.5; } From 57a295b544d713d45dd8d22477454e9195463f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 28 Sep 2017 14:10:25 +0200 Subject: [PATCH 03/86] html minification --- base.php | 1 + compile_html.php | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/base.php b/base.php index e31c847..30eeea4 100644 --- a/base.php +++ b/base.php @@ -35,6 +35,7 @@ if (!file_exists(__DIR__ . '/_env.php')) { define('JS_WEB_ROOT', $root); +define('ESP_PROD', (bool)getenv('ESP_PROD')); define('ESP_DEMO', (bool)getenv('ESP_DEMO')); if (ESP_DEMO) { define('DEMO_APS', << $p) { // making it not a very big improvement at the expense of ugly html. // $s = process_html($s); ob_clean(); - } // clean up - $of = $dest . $_k . ((in_array($_k, $no_tpl_files)||ESP_DEMO) ? '.html' : '.tpl'); - file_put_contents($of, $s); // write to a file + } + + $outputPath = $dest . $_k . ((in_array($_k, $no_tpl_files)||ESP_DEMO) ? '.html' : '.tpl'); + + if (file_exists($outputPath)) unlink($outputPath); + if (ESP_PROD) { + $tmpfile = tempnam('/tmp', 'espterm').'.html'; + file_put_contents($tmpfile, $s); + // using https://github.com/tdewolff/minify + system('minify --html-keep-default-attrvals '. + '-o '.escapeshellarg($outputPath).' '. + ''.escapeshellarg($tmpfile), $rv); + + // fallback if minify is not installed + if (!file_exists($outputPath)) file_put_contents($outputPath, $s); + } else { + file_put_contents($outputPath, $s); + } } ob_flush(); From 4c1da9aaacc1a1d519d774adb7874ebe30a1998e Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Thu, 28 Sep 2017 20:07:34 +0200 Subject: [PATCH 04/86] Do padding in canvas instead of CSS --- js/term/screen.js | 25 ++++++++++----- js/term/screen_renderer.js | 62 ++++++++++++++++++++++++++------------ sass/pages/_term.scss | 1 - 3 files changed, 59 insertions(+), 29 deletions(-) diff --git a/js/term/screen.js b/js/term/screen.js index b24ce98..e350234 100644 --- a/js/term/screen.js +++ b/js/term/screen.js @@ -55,6 +55,7 @@ module.exports = class TermScreen extends EventEmitter { devicePixelRatio: 1, fontFamily: '"DejaVu Sans Mono", "Liberation Mono", "Inconsolata", "Menlo", monospace', fontSize: 20, + padding: 6, gridScaleX: 1.0, gridScaleY: 1.2, fitIntoWidth: 0, @@ -67,11 +68,15 @@ module.exports = class TermScreen extends EventEmitter { // scaling caused by fitIntoWidth/fitIntoHeight this._windowScale = 1 + // actual padding, as it may be disabled by fullscreen mode etc. + this._padding = 0 + // properties of this.window that require updating size and redrawing this.windowState = { width: 0, height: 0, devicePixelRatio: 0, + padding: 0, gridScaleX: 0, gridScaleY: 0, fontFamily: '', @@ -313,8 +318,8 @@ module.exports = class TermScreen extends EventEmitter { let cellSize = this.getCellSize() return [ - Math.floor((x + (rounded ? cellSize.width / 2 : 0)) / cellSize.width), - Math.floor(y / cellSize.height) + Math.floor((x - this._padding + (rounded ? cellSize.width / 2 : 0)) / cellSize.width), + Math.floor((y - this._padding) / cellSize.height) ] } @@ -328,7 +333,7 @@ module.exports = class TermScreen extends EventEmitter { gridToScreen (x, y, withScale = false) { let cellSize = this.getCellSize() - return [x * cellSize.width, y * cellSize.height].map(v => withScale ? v * this._windowScale : v) + return [x * cellSize.width, y * cellSize.height].map(v => this._padding + (withScale ? v * this._windowScale : v)) } /** @@ -378,13 +383,14 @@ module.exports = class TermScreen extends EventEmitter { width, height, fitIntoWidth, - fitIntoHeight + fitIntoHeight, + padding } = this.window const cellSize = this.getCellSize() // real height of the canvas element in pixels - let realWidth = width * cellSize.width - let realHeight = height * cellSize.height + let realWidth = width * cellSize.width + 2 * padding + let realHeight = height * cellSize.height + 2 * padding if (fitIntoWidth && fitIntoHeight) { let terminalAspect = realWidth / realHeight @@ -409,13 +415,16 @@ module.exports = class TermScreen extends EventEmitter { // store new window scale this._windowScale = realWidth / (width * cellSize.width) + // and padding + // TODO: disable in fullscreen mode + this._padding = padding // the DPR must be rounded to a very nice value to prevent gaps between cells let devicePixelRatio = this._window.devicePixelRatio = Math.round(this._windowScale * (window.devicePixelRatio || 1) * 2) / 2 - this.canvas.width = width * devicePixelRatio * cellSize.width + this.canvas.width = (width * cellSize.width + 2 * padding) * devicePixelRatio this.canvas.style.width = `${realWidth}px` - this.canvas.height = height * devicePixelRatio * cellSize.height + this.canvas.height = (height * cellSize.height + 2 * padding) * devicePixelRatio this.canvas.style.height = `${realHeight}px` // the screen has been cleared (by changing canvas width) diff --git a/js/term/screen_renderer.js b/js/term/screen_renderer.js index a557351..9d0f5af 100644 --- a/js/term/screen_renderer.js +++ b/js/term/screen_renderer.js @@ -159,9 +159,26 @@ module.exports = class ScreenRenderer { */ drawBackground ({ x, y, cellWidth, cellHeight, bg }) { const ctx = this.ctx + const { width, height } = this.screen.window ctx.fillStyle = this.getColor(bg) - ctx.clearRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) - ctx.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding + let isBorderCell = x === 0 || y === 0 || x === width - 1 || y === height - 1 + if (isBorderCell) { + let left = screenX + let top = screenY + let right = screenX + cellWidth + let bottom = screenY + cellHeight + if (x === 0) left -= this.screen._padding + else if (x === width - 1) right += this.screen._padding + if (y === 0) top -= this.screen._padding + else if (y === height - 1) bottom += this.screen._padding + ctx.clearRect(left, top, right - left, bottom - top) + ctx.fillRect(left, top, right - left, bottom - top) + } else { + ctx.clearRect(screenX, screenY, cellWidth, cellHeight) + ctx.fillRect(screenX, screenY, cellWidth, cellHeight) + } } /** @@ -194,12 +211,15 @@ module.exports = class ScreenRenderer { ctx.fillStyle = this.getColor(fg) + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding + let codePoint = text.codePointAt(0) if (codePoint >= 0x2580 && codePoint <= 0x259F) { // block elements ctx.beginPath() - const left = x * cellWidth - const top = y * cellHeight + const left = screenX + const top = screenY const cw = cellWidth const ch = cellHeight const c2w = cellWidth / 2 @@ -251,16 +271,16 @@ module.exports = class ScreenRenderer { for (let dx = 0; dx < cw; dx += dotSpacingX) { // prevent overflow let dotSizeY = Math.min(dotSize, ch - dy) - ctx.rect(x * cw + (alignRight ? cw - dx - dotSize : dx), y * ch + dy, dotSize, dotSizeY) + ctx.rect(left + (alignRight ? cw - dx - dotSize : dx), top + dy, dotSize, dotSizeY) } alignRight = !alignRight } } else if (codePoint === 0x2594) { // upper one eighth block >▔< - ctx.rect(x * cw, y * ch, cw, ch / 8) + ctx.rect(left, top, cw, ch / 8) } else if (codePoint === 0x2595) { // right one eighth block >▕< - ctx.rect((x + 7 / 8) * cw, y * ch, cw / 8, ch) + ctx.rect(left + (7 / 8) * cw, top, cw / 8, ch) } else if (codePoint === 0x2596) { // left bottom quadrant >▖< ctx.rect(left, top + c2h, c2w, c2h) @@ -302,7 +322,7 @@ module.exports = class ScreenRenderer { ctx.fill() } else { // Draw other characters using the text renderer - ctx.fillText(text, (x + 0.5) * cellWidth, (y + 0.5) * cellHeight) + ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight) } // -- line drawing - a reference for a possible future rect/line implementation --- @@ -324,21 +344,21 @@ module.exports = class ScreenRenderer { ctx.beginPath() if (underline) { - let lineY = Math.round(y * cellHeight + charSize.height) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY + charSize.height) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } if (strike) { - let lineY = Math.round((y + 0.5) * cellHeight) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY + 0.5 * cellHeight) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } if (overline) { - let lineY = Math.round(y * cellHeight) + 0.5 - ctx.moveTo(x * cellWidth, lineY) - ctx.lineTo((x + 1) * cellWidth, lineY) + let lineY = Math.round(screenY) + 0.5 + ctx.moveTo(screenX, lineY) + ctx.lineTo(screenX + cellWidth, lineY) } ctx.stroke() @@ -570,17 +590,19 @@ module.exports = class ScreenRenderer { if (isCursor && !inSelection) { ctx.save() ctx.beginPath() + let screenX = x * cellWidth + this.screen._padding + let screenY = y * cellHeight + this.screen._padding if (this.screen.cursor.style === 'block') { // block - ctx.rect(x * cellWidth, y * cellHeight, cellWidth, cellHeight) + ctx.rect(screenX, screenY, cellWidth, cellHeight) } else if (this.screen.cursor.style === 'bar') { // vertical bar let barWidth = 2 - ctx.rect(x * cellWidth, y * cellHeight, barWidth, cellHeight) + ctx.rect(screenX, screenY, barWidth, cellHeight) } else if (this.screen.cursor.style === 'line') { // underline let lineHeight = 2 - ctx.rect(x * cellWidth, y * cellHeight + charSize.height, cellWidth, lineHeight) + ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight) } ctx.clip() diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index 19df4d1..6eaddd8 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -18,7 +18,6 @@ body.term { #screen { white-space: nowrap; background: #111213; - padding: 6px; display: inline-block; border: 2px solid #3983CD; position: relative; From aa41cf512e03946212106af6afb3d974e362463d Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Thu, 28 Sep 2017 20:16:05 +0200 Subject: [PATCH 05/86] Add screen margin overlays and add a margin to the soft keyboard extension --- pages/term.php | 4 ++++ sass/pages/_term.scss | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/pages/term.php b/pages/term.php index 3c0ede0..1a3bf9f 100644 --- a/pages/term.php +++ b/pages/term.php @@ -49,6 +49,10 @@
+
+
+
+
diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index 6eaddd8..3e18539 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -29,6 +29,36 @@ body.term { cursor: text; } + .screen-margin { + position: absolute; + // #111213 as rgb + background: rgba(17, 18, 19, 0.2); + -webkit-backdrop-filter: blur(10px); + + &.top { + top: 0; + left: 0; + right: 0; + height: 6px; + } + &.left, &.right { + top: 6px; + left: 0; + bottom: 0; + width: 6px; + } + &.right { + left: auto; + right: 0; + } + &.bottom { + left: 6px; + right: 6px; + bottom: 0; + height: 6px; + } + } + @include noselect(); // Dummy input field used to open soft keyboard @@ -220,6 +250,7 @@ body.term { background: #d1d5db; padding: 5px 10px; overflow-x: auto; + margin: 6px; &:not(.open) { display: none; From 342433be53ab27d193e6de1769a4238a1b42e60c Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Thu, 28 Sep 2017 20:26:11 +0200 Subject: [PATCH 06/86] Turns out backdrop-filter works fine in Chrome (at least in this case) --- sass/pages/_term.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index 3e18539..b39b3af 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -34,6 +34,7 @@ body.term { // #111213 as rgb background: rgba(17, 18, 19, 0.2); -webkit-backdrop-filter: blur(10px); + backdrop-filter: blur(10px); &.top { top: 0; From 65eb8b1830abe3f5da3c8cb7b779e7dd2c8963f3 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Thu, 28 Sep 2017 20:45:54 +0200 Subject: [PATCH 07/86] Add powerline triangles --- js/term/screen_renderer.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/js/term/screen_renderer.js b/js/term/screen_renderer.js index 9d0f5af..11c6315 100644 --- a/js/term/screen_renderer.js +++ b/js/term/screen_renderer.js @@ -320,6 +320,30 @@ module.exports = class ScreenRenderer { } ctx.fill() + } else if (codePoint >= 0xE0B0 && codePoint <= 0xE0B3) { + // powerline symbols, except branch, line, and lock. Basically, just the triangles + ctx.beginPath() + + if (codePoint === 0xE0B0 || codePoint === 0xE0B1) { + // right-pointing triangle + ctx.moveTo(screenX, screenY) + ctx.lineTo(screenX + cellWidth, screenY + cellHeight / 2) + ctx.lineTo(screenX, screenY + cellHeight) + } else if (codePoint === 0xE0B2 || codePoint === 0xE0B3) { + // left-pointing triangle + ctx.moveTo(screenX + cellWidth, screenY) + ctx.lineTo(screenX, screenY + cellHeight / 2) + ctx.lineTo(screenX + cellWidth, screenY + cellHeight) + } + + if (codePoint % 2 === 0) { + // triangle + ctx.fill() + } else { + // chevron + ctx.strokeStyle = ctx.fillStyle + ctx.stroke() + } } else { // Draw other characters using the text renderer ctx.fillText(text, screenX + 0.5 * cellWidth, screenY + 0.5 * cellHeight) From 91d270fce387bd5ce206a7843a74d1818b690397 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Thu, 28 Sep 2017 20:59:15 +0200 Subject: [PATCH 08/86] Draw hanging cursor in the margin --- js/term/screen_renderer.js | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/js/term/screen_renderer.js b/js/term/screen_renderer.js index 11c6315..66838cc 100644 --- a/js/term/screen_renderer.js +++ b/js/term/screen_renderer.js @@ -457,11 +457,10 @@ module.exports = class ScreenRenderer { for (let cell = 0; cell < screenLength; cell++) { let x = cell % width let y = Math.floor(cell / width) - let isCursor = !this.screen.cursor.hanging && + let isCursor = this.cursorBlinkOn && this.screen.cursor.x === x && this.screen.cursor.y === y && - this.screen.cursor.visible && - this.cursorBlinkOn + this.screen.cursor.visible let wasCursor = x === this.drawnCursor[0] && y === this.drawnCursor[1] @@ -494,7 +493,8 @@ module.exports = class ScreenRenderer { bg !== this.drawnScreenBG[cell] || // background updated attrs !== this.drawnScreenAttrs[cell] || // attributes updated isCursor !== wasCursor || // cursor blink/position updated - (isCursor && this.screen.cursor.style !== this.drawnCursor[2]) // cursor style updated + (isCursor && this.screen.cursor.style !== this.drawnCursor[2]) || // cursor style updated + (isCursor && this.screen.cursor.hanging !== this.drawnCursor[3]) // cursor hanging updated let font = attrs & FONT_MASK if (!fontGroups.has(font)) fontGroups.set(font, []) @@ -609,13 +609,23 @@ module.exports = class ScreenRenderer { this.drawnScreenBG[cell] = bg this.drawnScreenAttrs[cell] = attrs - if (isCursor) this.drawnCursor = [x, y, this.screen.cursor.style] + if (isCursor) this.drawnCursor = [x, y, this.screen.cursor.style, this.screen.cursor.hanging] + // draw cursor if (isCursor && !inSelection) { ctx.save() ctx.beginPath() - let screenX = x * cellWidth + this.screen._padding - let screenY = y * cellHeight + this.screen._padding + + let cursorX = x + let cursorY = y + + if (this.screen.cursor.hanging) { + // draw hanging cursor in the margin + cursorX += 1 + } + + let screenX = cursorX * cellWidth + this.screen._padding + let screenY = cursorY * cellHeight + this.screen._padding if (this.screen.cursor.style === 'block') { // block ctx.rect(screenX, screenY, cellWidth, cellHeight) @@ -636,9 +646,9 @@ module.exports = class ScreenRenderer { // HACK: ensure cursor is visible if (fg === bg) bg = fg === 0 ? 7 : 0 - this.drawBackground({ x, y, cellWidth, cellHeight, bg }) + this.drawBackground({ x: cursorX, y: cursorY, cellWidth, cellHeight, bg }) this.drawCharacter({ - x, y, charSize, cellWidth, cellHeight, text, fg, attrs + x: cursorX, y: cursorY, charSize, cellWidth, cellHeight, text, fg, attrs }) ctx.restore() } From b5c135e5056fd14fbafce78ee653c32d99e69cbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 29 Sep 2017 00:57:35 +0200 Subject: [PATCH 09/86] new parser, may be a bit buggy --- .eslintrc | 2 +- js/term/index.js | 1 - js/term/screen_parser.js | 507 ++++++++++++++++++++++--------------- js/term/screen_renderer.js | 39 ++- pages/term.php | 8 +- 5 files changed, 331 insertions(+), 226 deletions(-) diff --git a/.eslintrc b/.eslintrc index b6aeb27..3d11065 100644 --- a/.eslintrc +++ b/.eslintrc @@ -148,7 +148,7 @@ "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }], "one-var": ["error", { "initialized": "never" }], "operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" } }], - "padded-blocks": ["error", { "blocks": "never", "switches": "never", "classes": "never" }], + "padded-blocks": ["off", { "blocks": "never", "switches": "never", "classes": "never" }], "prefer-promise-reject-errors": "error", "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }], "rest-spread-spacing": ["error", "never"], diff --git a/js/term/index.js b/js/term/index.js index 41593ac..3109d25 100644 --- a/js/term/index.js +++ b/js/term/index.js @@ -67,7 +67,6 @@ module.exports = function (opts) { } qs('#screen').appendChild(screen.canvas) - screen.load(opts.labels, opts) // load labels and theme initSoftKeyboard(screen, input) if (attachDebugScreen) attachDebugScreen(screen) diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js index c210e00..9fea01d 100644 --- a/js/term/screen_parser.js +++ b/js/term/screen_parser.js @@ -9,6 +9,46 @@ const SEQ_SET_ATTRS = 4 const SEQ_SET_FG = 5 const SEQ_SET_BG = 6 +function du (str) { + return str.codePointAt(0) - 1 +} + +/* eslint-disable no-multi-spaces */ +const TOPIC_SCREEN_OPTS = 'O' +const TOPIC_CONTENT = 'S' +const TOPIC_TITLE = 'T' +const TOPIC_BUTTONS = 'B' +const TOPIC_CURSOR = 'C' +const TOPIC_INTERNAL = 'D' +const TOPIC_BELL = '!' + +const OPT_CURSOR_VISIBLE = (1 << 0) +const OPT_DEBUGBAR = (1 << 1) +const OPT_CURSORS_ALT_MODE = (1 << 2) +const OPT_NUMPAD_ALT_MODE = (1 << 3) +const OPT_FN_ALT_MODE = (1 << 4) +const OPT_CLICK_TRACKING = (1 << 5) +const OPT_MOVE_TRACKING = (1 << 6) +const OPT_SHOW_BUTTONS = (1 << 7) +const OPT_SHOW_CONFIG_LINKS = (1 << 8) +// const OPT_CURSOR_SHAPE = (7 << 9) +const OPT_CRLF_MODE = (1 << 12) +const OPT_BRACKETED_PASTE = (1 << 13) +const OPT_REVERSE_VIDEO = (1 << 14) + +const ATTR_FG = (1 << 0) // 1 if not using default background color (ignore cell bg) - color extension bit +const ATTR_BG = (1 << 1) // 1 if not using default foreground color (ignore cell fg) - color extension bit +const ATTR_BOLD = (1 << 2) // Bold font +const ATTR_UNDERLINE = (1 << 3) // Underline decoration +const ATTR_INVERSE = (1 << 4) // Invert colors - this is useful so we can clear then with SGR manipulation commands +const ATTR_BLINK = (1 << 5) // Blinking +const ATTR_ITALIC = (1 << 6) // Italic font +const ATTR_STRIKE = (1 << 7) // Strike-through decoration +const ATTR_OVERLINE = (1 << 8) // Over-line decoration +const ATTR_FAINT = (1 << 9) // Faint foreground color (reduced alpha) +const ATTR_FRAKTUR = (1 << 10) // Fraktur font (unicode substitution) +/* eslint-enable no-multi-spaces */ + module.exports = class ScreenParser { constructor (screen) { this.screen = screen @@ -16,246 +56,303 @@ module.exports = class ScreenParser { // true if TermScreen#load was called at least once this.contentLoaded = false } + /** - * Parses the content of an `S` message and schedules a draw - * @param {string} str - the message content + * Hide the warning message about failed data load */ - loadContent (str) { - // current index - let i = 0 - let strArray = Array.from ? Array.from(str) : str.split('') - - // Uncomment to capture screen content for the demo page - // console.log(JSON.stringify(`S${str}`)) - + hideLoadFailedMsg () { if (!this.contentLoaded) { let errmsg = qs('#load-failed') if (errmsg) errmsg.parentNode.removeChild(errmsg) this.contentLoaded = true } + } - // window size - const newHeight = strArray[i++].codePointAt(0) - 1 - const newWidth = strArray[i++].codePointAt(0) - 1 - const resized = (this.screen.window.height !== newHeight) || (this.screen.window.width !== newWidth) - this.screen.window.height = newHeight - this.screen.window.width = newWidth - - // cursor position - let [cursorY, cursorX] = [ - strArray[i++].codePointAt(0) - 1, - strArray[i++].codePointAt(0) - 1 - ] - let cursorMoved = (cursorX !== this.screen.cursor.x || cursorY !== this.screen.cursor.y) - this.screen.cursor.x = cursorX - this.screen.cursor.y = cursorY - - if (cursorMoved) { - this.screen.renderer.resetCursorBlink() - this.screen.emit('cursor-moved') - } + loadUpdate (str) { + console.log(`update ${str}`) + // current index + let ci = 0 + let strArray = Array.from ? Array.from(str) : str.split('') - // attributes - let attributes = strArray[i++].codePointAt(0) - 1 + let text + let resized = false + const topics = du(strArray[ci++]) + // this.screen.cursor.hanging = !!(attributes & (1 << 1)) - this.screen.cursor.visible = !!(attributes & 1) - this.screen.cursor.hanging = !!(attributes & (1 << 1)) + while (ci < strArray.length) { + const topic = strArray[ci++] + console.log(`topic ${topic}`) - this.screen.input.setAlts( - !!(attributes & (1 << 2)), // cursors alt - !!(attributes & (1 << 3)), // numpad alt - !!(attributes & (1 << 4)), // fn keys alt - !!(attributes & (1 << 12)) // crlf mode - ) + if (topic === TOPIC_SCREEN_OPTS) { - let trackMouseClicks = !!(attributes & (1 << 5)) - let trackMouseMovement = !!(attributes & (1 << 6)) + const newHeight = du(strArray[ci++]) + const newWidth = du(strArray[ci++]) + const theme = du(strArray[ci++]) + const defFg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) + const defBg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) + const attributes = du(strArray[ci++]) - // 0 - Block blink 2 - Block steady (1 is unused) - // 3 - Underline blink 4 - Underline steady - // 5 - I-bar blink 6 - I-bar steady - let cursorShape = (attributes >> 9) & 0x07 + // themeing + if (theme >= 0 && theme < themes.length) { + this.screen.renderer.palette = themes[theme] + } + this.screen.renderer.setDefaultColors(defFg, defBg) - // if it's not zero, decrement such that the two most significant bits - // are the type and the least significant bit is the blink state - if (cursorShape > 0) cursorShape-- + // apply size + resized = (this.screen.window.height !== newHeight) || (this.screen.window.width !== newWidth) + this.screen.window.height = newHeight + this.screen.window.width = newWidth - let cursorStyle = cursorShape >> 1 - let cursorBlinking = !(cursorShape & 1) + // process attributes + this.screen.cursor.visible = !!(attributes & OPT_CURSOR_VISIBLE) - if (cursorStyle === 0) this.screen.cursor.style = 'block' - else if (cursorStyle === 1) this.screen.cursor.style = 'line' - else if (cursorStyle === 2) this.screen.cursor.style = 'bar' + this.screen.input.setAlts( + !!(attributes & OPT_CURSORS_ALT_MODE), + !!(attributes & OPT_NUMPAD_ALT_MODE), + !!(attributes & OPT_FN_ALT_MODE), + !!(attributes & OPT_CRLF_MODE) + ) - if (this.screen.cursor.blinking !== cursorBlinking) { - this.screen.cursor.blinking = cursorBlinking - this.screen.renderer.resetCursorBlink() - } + const trackMouseClicks = !!(attributes & OPT_CLICK_TRACKING) + const trackMouseMovement = !!(attributes & OPT_MOVE_TRACKING) + + // 0 - Block blink 2 - Block steady (1 is unused) + // 3 - Underline blink 4 - Underline steady + // 5 - I-bar blink 6 - I-bar steady + let cursorShape = (attributes >> 9) & 0x07 + // if it's not zero, decrement such that the two most significant bits + // are the type and the least significant bit is the blink state + if (cursorShape > 0) cursorShape-- + const cursorStyle = cursorShape >> 1 + const cursorBlinking = !(cursorShape & 1) + if (cursorStyle === 0) this.screen.cursor.style = 'block' + else if (cursorStyle === 1) this.screen.cursor.style = 'line' + else if (cursorStyle === 2) this.screen.cursor.style = 'bar' + if (this.screen.cursor.blinking !== cursorBlinking) { + this.screen.cursor.blinking = cursorBlinking + this.screen.renderer.resetCursorBlink() + } - this.screen.input.setMouseMode(trackMouseClicks, trackMouseMovement) - this.screen.selection.selectable = !trackMouseClicks && !trackMouseMovement - $(this.screen.canvas).toggleClass('selectable', this.screen.selection.selectable) - this.screen.mouseMode = { - clicks: trackMouseClicks, - movement: trackMouseMovement - } + this.screen.input.setMouseMode(trackMouseClicks, trackMouseMovement) + this.screen.selection.selectable = !trackMouseClicks && !trackMouseMovement + $(this.screen.canvas).toggleClass('selectable', this.screen.selection.selectable) + this.screen.mouseMode = { + clicks: trackMouseClicks, + movement: trackMouseMovement + } - let showButtons = !!(attributes & (1 << 7)) - let showConfigLinks = !!(attributes & (1 << 8)) - - $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks) - $('#action-buttons').toggleClass('hidden', !showButtons) - - this.screen.bracketedPaste = !!(attributes & (1 << 13)) - this.screen.reverseVideo = !!(attributes & (1 << 14)) - - // content - let fg = 7 - let bg = 0 - let attrs = 0 - let cell = 0 // cell index - let lastChar = ' ' - let screenLength = this.screen.window.width * this.screen.window.height - - if (resized) { - this.screen.updateSize() - this.screen.blinkingCellCount = 0 - this.screen.screen = new Array(screenLength).fill(' ') - this.screen.screenFG = new Array(screenLength).fill(' ') - this.screen.screenBG = new Array(screenLength).fill(' ') - this.screen.screenAttrs = new Array(screenLength).fill(0) - } + const showButtons = !!(attributes & OPT_SHOW_BUTTONS) + const showConfigLinks = !!(attributes & OPT_SHOW_CONFIG_LINKS) - const MASK_LINE_ATTR = 0xC8 - const MASK_BLINK = 1 << 4 - - let setCellContent = () => { - // Remove blink attribute if it wouldn't have any effect - let myAttrs = attrs - let hasFG = attrs & (1 << 8) - let hasBG = attrs & (1 << 9) - if ((myAttrs & MASK_BLINK) !== 0 && - ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles - (fg === bg && hasFG && hasBG) // invisible text - ) - ) { - myAttrs ^= MASK_BLINK - } - // update blinking cells counter if blink state changed - if ((this.screen.screenAttrs[cell] & MASK_BLINK) !== (myAttrs & MASK_BLINK)) { - if (myAttrs & MASK_BLINK) this.screen.blinkingCellCount++ - else this.screen.blinkingCellCount-- - } + $('.x-term-conf-btn').toggleClass('hidden', !showConfigLinks) + $('#action-buttons').toggleClass('hidden', !showButtons) - this.screen.screen[cell] = lastChar - this.screen.screenFG[cell] = fg - this.screen.screenBG[cell] = bg - this.screen.screenAttrs[cell] = myAttrs - } + this.screen.bracketedPaste = !!(attributes & OPT_BRACKETED_PASTE) + this.screen.reverseVideo = !!(attributes & OPT_REVERSE_VIDEO) + + const debugbar = !!(attributes & OPT_DEBUGBAR) + // TODO do something with debugbar + + } else if (topic === TOPIC_CURSOR) { + + // cursor position + const [cursorY, cursorX] = [ + strArray[ci++].codePointAt(0) - 1, + strArray[ci++].codePointAt(0) - 1 + ] + const hanging = du(strArray[ci++]) + + const cursorMoved = ( + hanging !== this.screen.cursor.hanging || + cursorX !== this.screen.cursor.x || + cursorY !== this.screen.cursor.y) - while (i < strArray.length && cell < screenLength) { - let character = strArray[i++] - let charCode = character.codePointAt(0) - - let data - switch (charCode) { - case SEQ_REPEAT: - let count = strArray[i++].codePointAt(0) - 1 - for (let j = 0; j < count; j++) { - setCellContent() - if (++cell > screenLength) break + this.screen.cursor.x = cursorX + this.screen.cursor.y = cursorY + + this.screen.cursor.hanging = hanging + + if (cursorMoved) { + this.screen.renderer.resetCursorBlink() + this.screen.emit('cursor-moved') + } + + } else if (topic === TOPIC_TITLE) { + + // TODO optimize this + text = '' + while (ci < strArray.length) { + let c = strArray[ci++] + if (c !== '\x01') { + text += c + } else { + break } - break - - case SEQ_SET_COLORS: - data = strArray[i++].codePointAt(0) - 1 - fg = data & 0xFF - bg = (data >> 8) & 0xFF - break - - case SEQ_SET_ATTRS: - data = strArray[i++].codePointAt(0) - 1 - attrs = data & 0xFFFF - break - - case SEQ_SET_FG: - data = strArray[i++].codePointAt(0) - 1 - fg = data & 0xFF - break - - case SEQ_SET_BG: - data = strArray[i++].codePointAt(0) - 1 - bg = data & 0xFF - break - - default: - if (charCode < 32) character = '\ufffd' - lastChar = character - setCellContent() - cell++ - } - } + } - if (this.screen.window.debug) console.log(`Blinky cells: ${this.screen.blinkingCellCount}`) + qs('#screen-title').textContent = text + if (text.length === 0) text = 'Terminal' + qs('title').textContent = `${text} :: ESPTerm` - this.screen.renderer.scheduleDraw('load', 16) - this.screen.conn.emit('load') - } + } else if (topic === TOPIC_BUTTONS) { - /** - * Parses the content of a `T` message and updates the screen title and button - * labels. - * @param {string} str - the message content - */ - loadLabels (str) { - let pieces = str.split('\x01') - let screenTitle = pieces[0] - qs('#screen-title').textContent = screenTitle - if (screenTitle.length === 0) screenTitle = 'Terminal' - qs('title').textContent = `${screenTitle} :: ESPTerm` - $('#action-buttons button').forEach((button, i) => { - let label = pieces[i + 1].trim() - // if empty string, use the "dim" effect and put nbsp instead to - // stretch the button vertically - button.innerHTML = label ? $.htmlEscape(label) : ' ' - button.style.opacity = label ? 1 : 0.2 - }) + // TODO optimize this + const count = du(strArray[ci++]) + + let buttons = [] + for (let j = 0; j < count; j++) { + text = '' + while (ci < strArray.length) { + let c = strArray[ci++] + if (c === '\x01') break + text += c + } + buttons.push(text) + } + + $('#action-buttons button').forEach((button, i) => { + let label = buttons[i].trim() + // if empty string, use the "dim" effect and put nbsp instead to + // stretch the button vertically + button.innerHTML = label.length ? $.htmlEscape(label) : ' ' + button.style.opacity = label.length ? 1 : 0.2 + }) + + } else if (topic === TOPIC_BELL) { + + this.screen.beep() + + } else if (topic === TOPIC_INTERNAL) { + + // debug info + const flags = du(strArray[ci++]) + const cursorAttrs = du(strArray[ci++]) + const regionStart = du(strArray[ci++]) + const regionEnd = du(strArray[ci++]) + const charsetGx = du(strArray[ci++]) + const charsetG0 = strArray[ci++] + const charsetG1 = strArray[ci++] + const freeHeap = du(strArray[ci++]) + const numClients = du(strArray[ci++]) + // TODO do something with those + + } else if (topic === TOPIC_CONTENT) { + + const window_y = du(strArray[ci++]) + const window_x = du(strArray[ci++]) + const window_h = du(strArray[ci++]) + const window_w = du(strArray[ci++]) + // TODO use + + // content + let fg = 7 + let bg = 0 + let attrs = 0 + let cell = 0 // cell index + let lastChar = ' ' + let screenLength = this.screen.window.width * this.screen.window.height + + if (resized) { + this.screen.updateSize() + this.screen.blinkingCellCount = 0 + this.screen.screen = new Array(screenLength).fill(' ') + this.screen.screenFG = new Array(screenLength).fill(' ') + this.screen.screenBG = new Array(screenLength).fill(' ') + this.screen.screenAttrs = new Array(screenLength).fill(0) + } + + const MASK_LINE_ATTR = ATTR_UNDERLINE | ATTR_OVERLINE | ATTR_STRIKE + const MASK_BLINK = ATTR_BLINK + + let setCellContent = () => { + // Remove blink attribute if it wouldn't have any effect + let myAttrs = attrs + let hasFG = attrs & ATTR_FG + let hasBG = attrs & ATTR_BG + if ((myAttrs & MASK_BLINK) !== 0 && + ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles + (fg === bg && hasFG && hasBG) // invisible text + ) + ) { + myAttrs ^= MASK_BLINK + } + // update blinking cells counter if blink state changed + if ((this.screen.screenAttrs[cell] & MASK_BLINK) !== (myAttrs & MASK_BLINK)) { + if (myAttrs & MASK_BLINK) this.screen.blinkingCellCount++ + else this.screen.blinkingCellCount-- + } + + this.screen.screen[cell] = lastChar + this.screen.screenFG[cell] = fg + this.screen.screenBG[cell] = bg + this.screen.screenAttrs[cell] = myAttrs + } + + while (ci < strArray.length && cell < screenLength) { + let character = strArray[ci++] + let charCode = character.codePointAt(0) + + let data + switch (charCode) { + case SEQ_REPEAT: + let count = strArray[ci++].codePointAt(0) - 1 + for (let j = 0; j < count; j++) { + setCellContent() + if (++cell > screenLength) break + } + break + + case SEQ_SET_COLORS: + data = strArray[ci++].codePointAt(0) - 1 + fg = data & 0xFF + bg = (data >> 8) & 0xFF + break + + case SEQ_SET_ATTRS: + data = strArray[ci++].codePointAt(0) - 1 + attrs = data & 0xFFFF + break + + case SEQ_SET_FG: + data = strArray[ci++].codePointAt(0) - 1 + fg = data & 0xFF + break + + case SEQ_SET_BG: + data = strArray[ci++].codePointAt(0) - 1 + bg = data & 0xFF + break + + default: + if (charCode < 32) character = '\ufffd' + lastChar = character + setCellContent() + cell++ + } + } + + if (this.screen.window.debug) console.log(`Blinky cells: ${this.screen.blinkingCellCount}`) + + this.screen.renderer.scheduleDraw('load', 16) + this.screen.conn.emit('load') + + } + + if ((topics & 0x3B) !== 0) this.hideLoadFailedMsg() + } } /** * Loads a message from the server, and optionally a theme. * @param {string} str - the message - * @param {object} [opts] - options - * @param {number} [opts.theme] - theme - * @param {number} [opts.defaultFg] - default foreground - * @param {number} [opts.defaultBg] - default background */ - load (str, opts = null) { + load (str) { + console.log(`RX: ${str}`) const content = str.substr(1) - if (opts) { - if (typeof opts.defaultFg !== 'undefined' && typeof opts.defaultBg !== 'undefined') { - this.screen.renderer.setDefaultColors(opts.defaultFg, opts.defaultBg) - } - - if (typeof opts.theme !== 'undefined') { - if (opts.theme >= 0 && opts.theme < themes.length) { - this.screen.renderer.palette = themes[opts.theme] - } - } - } - switch (str[0]) { - case 'S': - this.loadContent(content) - break - - case 'T': - this.loadLabels(content) - break - - case 'B': - this.screen.beep() + case 'U': + this.loadUpdate(content) break case 'G': diff --git a/js/term/screen_renderer.js b/js/term/screen_renderer.js index 66838cc..4eb9420 100644 --- a/js/term/screen_renderer.js +++ b/js/term/screen_renderer.js @@ -9,6 +9,21 @@ const frakturExceptions = { 'Z': '\u2128' } +// TODO do not repeat - this is also defined in screen_parser ... +/* eslint-disable no-multi-spaces */ +const ATTR_FG = (1 << 0) // 1 if not using default background color (ignore cell bg) - color extension bit +const ATTR_BG = (1 << 1) // 1 if not using default foreground color (ignore cell fg) - color extension bit +const ATTR_BOLD = (1 << 2) // Bold font +const ATTR_UNDERLINE = (1 << 3) // Underline decoration +const ATTR_INVERSE = (1 << 4) // Invert colors - this is useful so we can clear then with SGR manipulation commands +const ATTR_BLINK = (1 << 5) // Blinking +const ATTR_ITALIC = (1 << 6) // Italic font +const ATTR_STRIKE = (1 << 7) // Strike-through decoration +const ATTR_OVERLINE = (1 << 8) // Over-line decoration +const ATTR_FAINT = (1 << 9) // Faint foreground color (reduced alpha) +const ATTR_FRAKTUR = (1 << 10) // Fraktur font (unicode substitution) +/* eslint-enable no-multi-spaces */ + module.exports = class ScreenRenderer { constructor (screen) { this.screen = screen @@ -203,11 +218,11 @@ module.exports = class ScreenRenderer { let underline = false let strike = false let overline = false - if (attrs & (1 << 1)) ctx.globalAlpha = 0.5 - if (attrs & (1 << 3)) underline = true - if (attrs & (1 << 5)) text = ScreenRenderer.alphaToFraktur(text) - if (attrs & (1 << 6)) strike = true - if (attrs & (1 << 7)) overline = true + if (attrs & ATTR_FAINT) ctx.globalAlpha = 0.5 + if (attrs & ATTR_UNDERLINE) underline = true + if (attrs & ATTR_FRAKTUR) text = ScreenRenderer.alphaToFraktur(text) + if (attrs & ATTR_STRIKE) strike = true + if (attrs & ATTR_OVERLINE) overline = true ctx.fillStyle = this.getColor(fg) @@ -446,7 +461,7 @@ module.exports = class ScreenRenderer { ctx.textBaseline = 'middle' // bits in the attr value that affect the font - const FONT_MASK = 0b101 + const FONT_MASK = ATTR_BOLD | ATTR_ITALIC // Map of (attrs & FONT_MASK) -> Array of cell indices let fontGroups = new Map() @@ -471,13 +486,13 @@ module.exports = class ScreenRenderer { let bg = this.screen.screenBG[cell] | 0 let attrs = this.screen.screenAttrs[cell] | 0 - if (!(attrs & (1 << 8))) fg = this.defaultFgNum - if (!(attrs & (1 << 9))) bg = this.defaultBgNum + if (!(attrs & ATTR_FG)) fg = this.defaultFgNum + if (!(attrs & ATTR_BG)) bg = this.defaultBgNum - if (attrs & (1 << 10)) [fg, bg] = [bg, fg] // swap - reversed character colors + if (attrs & ATTR_INVERSE) [fg, bg] = [bg, fg] // swap - reversed character colors if (this.screen.reverseVideo) [fg, bg] = [bg, fg] // swap - reversed all screen - if (attrs & (1 << 4) && !this.blinkStyleOn) { + if (attrs & ATTR_BLINK && !this.blinkStyleOn) { // blinking is enabled and blink style is off // set text to nothing so drawCharacter doesn't draw anything text = '' @@ -592,8 +607,8 @@ module.exports = class ScreenRenderer { // set font once because in Firefox, this is a really slow action for some // reason let modifiers = {} - if (font & 1) modifiers.weight = 'bold' - if (font & 1 << 2) modifiers.style = 'italic' + if (font & ATTR_BOLD) modifiers.weight = 'bold' + if (font & ATTR_ITALIC) modifiers.style = 'italic' ctx.font = this.screen.getFont(modifiers) for (let data of fontGroups.get(font)) { diff --git a/pages/term.php b/pages/term.php index 1a3bf9f..feb3c92 100644 --- a/pages/term.php +++ b/pages/term.php @@ -76,13 +76,7 @@ diff --git a/sass/pages/_term.scss b/sass/pages/_term.scss index ae23265..56f2de6 100644 --- a/sass/pages/_term.scss +++ b/sass/pages/_term.scss @@ -381,3 +381,23 @@ body.pseudo-fullscreen { display: inline-block; padding: 5px; } + +.theme-nav-btn { + width: 2em; + height: 2em; + display: flex; + align-items: center; + justify-content: space-around; + background: #4c4c4c; + color: #eaeaea; + margin: 5px; + border-radius: 5px; + + @include noselect(); + + cursor: pointer; + position: relative; + &:active { + top: 1px; + } +} From 46099bb7495c51ac2d6e0e14dd41105da9b41de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 30 Sep 2017 13:52:57 +0200 Subject: [PATCH 26/86] Fix def fg bg color encoding. Protocol change! --- js/term/screen_parser.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js index b767df5..a2c8dd3 100644 --- a/js/term/screen_parser.js +++ b/js/term/screen_parser.js @@ -86,12 +86,10 @@ module.exports = class ScreenParser { const newHeight = du(strArray[ci++]) const newWidth = du(strArray[ci++]) const theme = du(strArray[ci++]) - const defFg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) - const defBg = du(strArray[ci++]) | (du(strArray[ci++]) << 12) + const defFg = (du(strArray[ci++]) & 0xFFFF) | ((du(strArray[ci++]) & 0xFFFF) << 16) + const defBg = (du(strArray[ci++]) & 0xFFFF) | ((du(strArray[ci++]) & 0xFFFF) << 16) const attributes = du(strArray[ci++]) - console.log(`set colors ${defFg}, ${defBg}, theme ${theme}`) - // theming this.screen.renderer.loadTheme(theme) this.screen.renderer.setDefaultColors(defFg, defBg) @@ -323,8 +321,8 @@ module.exports = class ScreenParser { case SEQ_SET_FG: data = du(strArray[ci++]) if (data & 0x10000) { - data ^= 0x10000 - data |= du(strArray[ci++]) << 12 + data &= 0xFFF + data |= (du(strArray[ci++]) & 0xFFF) << 12 data += 256 } fg = data @@ -333,8 +331,8 @@ module.exports = class ScreenParser { case SEQ_SET_BG: data = du(strArray[ci++]) if (data & 0x10000) { - data ^= 0x10000 - data |= du(strArray[ci++]) << 12 + data &= 0xFFF + data |= (du(strArray[ci++]) & 0xFFF) << 12 data += 256 } bg = data From 5245917c88918e23179bb872eec5b0e344b713d1 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 30 Sep 2017 14:35:24 +0200 Subject: [PATCH 27/86] Update demo for new protocol, add `themes` command --- js/term/demo.js | 272 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 84 deletions(-) diff --git a/js/term/demo.js b/js/term/demo.js index 0ea9e33..39dc9ec 100644 --- a/js/term/demo.js +++ b/js/term/demo.js @@ -36,30 +36,41 @@ class ANSIParser { this.handler('insert-blanks', numOr1) } else if (type === 'q') this.handler('set-cursor-style', numOr1) else if (type === 'm') { - if (!numbers.length || numbers[0] === 0) { + if (!numbers.length) { this.handler('reset-style') return } - let type = numbers[0] - if (type === 1) this.handler('add-attrs', 1) // bold - else if (type === 2) this.handler('add-attrs', 1 << 1) // faint - else if (type === 3) this.handler('add-attrs', 1 << 2) // italic - else if (type === 4) this.handler('add-attrs', 1 << 3) // underline - else if (type === 5 || type === 6) this.handler('add-attrs', 1 << 4) // blink - else if (type === 7) this.handler('add-attrs', -1) // invert - else if (type === 9) this.handler('add-attrs', 1 << 6) // strike - else if (type === 20) this.handler('add-attrs', 1 << 5) // fraktur - else if (type >= 30 && type <= 37) this.handler('set-color-fg', type % 10) - else if (type >= 40 && type <= 47) this.handler('set-color-bg', type % 10) - else if (type === 39) this.handler('reset-color-fg') - else if (type === 49) this.handler('reset-color-bg') - else if (type >= 90 && type <= 98) this.handler('set-color-fg', (type % 10) + 8) - else if (type >= 100 && type <= 108) this.handler('set-color-bg', (type % 10) + 8) - else if (type === 38 || type === 48) { - if (numbers[1] === 5) { - let color = (numbers[2] | 0) & 0xFF - if (type === 38) this.handler('set-color-fg', color) - if (type === 48) this.handler('set-color-bg', color) + let type + while ((type = numbers.shift())) { + if (type === 0) this.handler('reset-style') + else if (type === 1) this.handler('add-attrs', 1 << 2) // bold + else if (type === 2) this.handler('add-attrs', 1 << 9) // faint + else if (type === 3) this.handler('add-attrs', 1 << 6) // italic + else if (type === 4) this.handler('add-attrs', 1 << 3) // underline + else if (type === 5 || type === 6) this.handler('add-attrs', 1 << 5) // blink + else if (type === 7) this.handler('add-attrs', 1 << 4) // invert + else if (type === 9) this.handler('add-attrs', 1 << 7) // strike + else if (type === 20) this.handler('add-attrs', 1 << 10) // fraktur + else if (type >= 30 && type <= 37) this.handler('set-color-fg', type % 10) + else if (type >= 40 && type <= 47) this.handler('set-color-bg', type % 10) + else if (type === 39) this.handler('reset-color-fg') + else if (type === 49) this.handler('reset-color-bg') + else if (type >= 90 && type <= 98) this.handler('set-color-fg', (type % 10) + 8) + else if (type >= 100 && type <= 108) this.handler('set-color-bg', (type % 10) + 8) + else if (type === 38 || type === 48) { + let mode = numbers.shift() + if (mode === 2) { + let r = numbers.shift() + let g = numbers.shift() + let b = numbers.shift() + let color = (r << 16 | g << 8 | b) + 256 + if (type === 38) this.handler('set-color-fg', color) + if (type === 48) this.handler('set-color-bg', color) + } else if (mode === 5) { + let color = (numbers.shift() | 0) & 0xFF + if (type === 38) this.handler('set-color-fg', color) + if (type === 48) this.handler('set-color-bg', color) + } } } } else if (type === 'h' || type === 'l') { @@ -101,7 +112,7 @@ class ANSIParser { if (!this.joinChunks) this.reset() } } -const TERM_DEFAULT_STYLE = 0 +const TERM_DEFAULT_STYLE = [0, 0, 0] const TERM_MIN_DRAW_DELAY = 10 let getRainbowColor = t => { @@ -117,19 +128,20 @@ class ScrollingTerminal { this.height = 25 this.termScreen = screen this.parser = new ANSIParser((...args) => this.handleParsed(...args)) + this.buttonLabels = ['', '', '^C', '', 'Help'] this.reset() this._lastLoad = Date.now() - this.termScreen.load(this.serialize()) + this.loadTimer() window.showPage() } reset () { - this.style = TERM_DEFAULT_STYLE + this.style = TERM_DEFAULT_STYLE.slice() this.cursor = { x: 0, y: 0, style: 1, visible: true } this.trackMouse = false - this.theme = -1 + this.theme = 0 this.rainbow = false this.parser.reset() this.clear() @@ -137,13 +149,13 @@ class ScrollingTerminal { clear () { this.screen = [] for (let i = 0; i < this.width * this.height; i++) { - this.screen.push([' ', this.style]) + this.screen.push([' ', this.style.slice()]) } } scroll () { this.screen.splice(0, this.width) for (let i = 0; i < this.width; i++) { - this.screen.push([' ', TERM_DEFAULT_STYLE]) + this.screen.push([' ', TERM_DEFAULT_STYLE.slice()]) } this.cursor.y-- } @@ -152,7 +164,7 @@ class ScrollingTerminal { if (this.cursor.y >= this.height) this.scroll() } writeChar (character) { - this.screen[this.cursor.y * this.width + this.cursor.x] = [character, this.style] + this.screen[this.cursor.y * this.width + this.cursor.x] = [character, this.style.slice()] this.cursor.x++ if (this.cursor.x >= this.width) { this.cursor.x = 0 @@ -181,12 +193,12 @@ class ScrollingTerminal { } deleteChar () { // FIXME unused? this.moveBack() - this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE]) + this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()]) this.screen.splice(this.cursor.y * this.width + this.cursor.x, 1) } deleteForward (n) { n = Math.min(this.width, n) - for (let i = 0; i < n; i++) this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE]) + for (let i = 0; i < n; i++) this.screen.splice((this.cursor.y + 1) * this.width, 0, [' ', TERM_DEFAULT_STYLE.slice()]) this.screen.splice(this.cursor.y * this.width + this.cursor.x, n) } clampCursor () { @@ -205,11 +217,12 @@ class ScrollingTerminal { } else if (action === 'clear') { this.clear() } else if (action === 'bell') { - this.termScreen.load('B') + this.termScreen.load('U\x01B') } else if (action === 'back') { this.moveBack() } else if (action === 'new-line') { this.newLine() + this.cursor.x = 0 } else if (action === 'return') { this.cursor.x = 0 } else if (action === 'set-cursor') { @@ -231,17 +244,21 @@ class ScrollingTerminal { } else if (action === 'set-cursor-style') { this.cursor.style = Math.max(0, Math.min(6, args[0])) } else if (action === 'reset-style') { - this.style = TERM_DEFAULT_STYLE + this.style = TERM_DEFAULT_STYLE.slice() } else if (action === 'add-attrs') { - this.style |= (args[0] << 16) + this.style[2] |= args[0] } else if (action === 'set-color-fg') { - this.style = (this.style & 0xFFFFFF00) | (1 << 8 << 16) | args[0] + this.style[0] = args[0] + this.style[2] |= 1 } else if (action === 'set-color-bg') { - this.style = (this.style & 0xFFFF00FF) | (1 << 9 << 16) | (args[0] << 8) + this.style[1] = args[0] + this.style[2] |= 1 << 1 } else if (action === 'reset-color-fg') { - this.style = this.style & 0xFFFEFF00 + this.style[0] = 0 + if (this.style[2] & 1) this.style[2] ^= 1 } else if (action === 'reset-color-bg') { - this.style = this.style & 0xFFFD00FF + this.style[1] = 0 + if (this.style[2] & (1 << 1)) this.style[2] ^= (1 << 1) } else if (action === 'hide-cursor') { this.cursor.visible = false } else if (action === 'show-cursor') { @@ -250,65 +267,119 @@ class ScrollingTerminal { } write (text) { this.parser.write(text) - this.scheduleLoad() } - serialize () { - let serialized = 'S' - serialized += String.fromCodePoint(this.height + 1) + String.fromCodePoint(this.width + 1) - serialized += String.fromCodePoint(this.cursor.y + 1) + String.fromCodePoint(this.cursor.x + 1) - + getScreenOpts () { + let data = 'O' + data += String.fromCodePoint(26) + data += String.fromCodePoint(81) + data += String.fromCodePoint(this.theme + 1) + data += String.fromCodePoint(8) + data += String.fromCodePoint(1) + data += String.fromCodePoint(1) + data += String.fromCodePoint(1) let attributes = +this.cursor.visible attributes |= (3 << 5) * +this.trackMouse // track mouse controls both attributes |= 3 << 7 // buttons/links always visible attributes |= (this.cursor.style << 9) - serialized += String.fromCodePoint(attributes + 1) + data += String.fromCodePoint(attributes + 1) + return data + } + getButtons () { + let data = 'B' + data += String.fromCodePoint(6) + data += this.buttonLabels.map(x => x + '\x01').join('') + return data + } + getCursor () { + let data = 'C' + data += String.fromCodePoint(this.cursor.y + 1) + data += String.fromCodePoint(this.cursor.x + 1) + data += String.fromCodePoint(1) + return data + } + encodeColor (color) { + if (color < 256) { + return String.fromCodePoint(color + 1) + } else { + color -= 256 + return String.fromCodePoint(((color & 0xFFF) | 0x10000) + 1) + String.fromCodePoint((color >> 12) + 1) + } + } + serializeScreen () { + let serialized = 'S' + serialized += String.fromCodePoint(1) + String.fromCodePoint(1) + serialized += String.fromCodePoint(this.height + 1) + String.fromCodePoint(this.width + 1) - let lastStyle = null + let lastStyle = [null, null, null] let index = 0 for (let cell of this.screen) { - let style = cell[1] + let style = cell[1].slice() if (this.rainbow) { let x = index % this.width let y = Math.floor(index / this.width) - // C instead of F in mask and 1 << 8 in attrs to change attr bits 8 and 9 - style = (style & 0xFFFC0000) | (1 << 8 << 16) | getRainbowColor((x + y) / 10 + Date.now() / 1000) + // C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2 + style[0] = getRainbowColor((x + y) / 10 + Date.now() / 1000) + style[1] = 0 + style[2] = style[2] | 1 + if (style[2] & (1 << 1)) style[2] ^= (1 << 1) index++ } - if (style !== lastStyle) { - let foreground = style & 0xFF - let background = (style >> 8) & 0xFF - let attributes = (style >> 16) & 0xFFFF - let setForeground = foreground !== (lastStyle & 0xFF) - let setBackground = background !== ((lastStyle >> 8) & 0xFF) - let setAttributes = attributes !== ((lastStyle >> 16) & 0xFFFF) - - if (setForeground && setBackground) serialized += '\x03' + String.fromCodePoint((style & 0xFFFF) + 1) - else if (setForeground) serialized += '\x05' + String.fromCodePoint(foreground + 1) - else if (setBackground) serialized += '\x06' + String.fromCodePoint(background + 1) - if (setAttributes) serialized += '\x04' + String.fromCodePoint(attributes + 1) - lastStyle = style - } + + let foreground = style[0] + let background = style[1] + let attributes = style[2] + let setForeground = foreground !== lastStyle[0] + let setBackground = background !== lastStyle[1] + let setAttributes = attributes !== lastStyle[2] + + if (setForeground && setBackground) { + if (foreground < 256 && background < 256) { + serialized += '\x03' + String.fromCodePoint(((background << 8) | foreground) + 1) + } else { + serialized += '\x05' + this.encodeColor(foreground) + serialized += '\x06' + this.encodeColor(background) + } + } else if (setForeground) serialized += '\x05' + this.encodeColor(foreground) + else if (setBackground) serialized += '\x06' + this.encodeColor(background) + if (setAttributes) serialized += '\x04' + String.fromCodePoint(attributes + 1) + lastStyle = style + serialized += cell[0] } return serialized } - scheduleLoad () { - clearTimeout(this._scheduledLoad) - if (this._lastLoad < Date.now() - TERM_MIN_DRAW_DELAY) { - this.termScreen.load(this.serialize(), { theme: this.theme }) - this.theme = -1 // prevent useless theme setting next time - } else { - this._scheduledLoad = setTimeout(() => { - this.termScreen.load(this.serialize()) - }, TERM_MIN_DRAW_DELAY - this._lastLoad) - } - } - rainbowTimer () { - if (!this.rainbow) return - clearInterval(this._rainbowTimer) - this._rainbowTimer = setInterval(() => { - if (this.rainbow) this.scheduleLoad() - }, 50) + getUpdate () { + let topics = 0 + let topicData = [] + let screenOpts = this.getScreenOpts() + let buttons = this.getButtons() + let cursor = this.getCursor() + let screen = this.serializeScreen() + if (this._screenOpts !== screenOpts) { + this._screenOpts = screenOpts + topicData.push(screenOpts) + } + if (this._buttons !== buttons) { + this._buttons = buttons + topicData.push(buttons) + } + if (this._cursor !== cursor) { + this._cursor = cursor + topicData.push(cursor) + } + if (this._screen !== screen) { + this._screen = screen + topicData.push(screen) + } + if (!topicData.length) return '' + return 'U' + String.fromCodePoint(topics + 1) + topicData.join('') + } + loadTimer () { + clearInterval(this._loadTimer) + this._loadTimer = setInterval(() => { + let update = this.getUpdate() + if (update) this.termScreen.load(update) + }, 30) } } @@ -329,7 +400,7 @@ let demoData = { buttons: { 1: '', 2: '', - 3: '', + 3: (terminal, shell) => shell.write('\x03'), 4: '', 5: function (terminal, shell) { if (shell.child) shell.child.destroy() @@ -466,7 +537,7 @@ let demoshIndex = { if (++x < 69) { if (++cycles >= 3) { - setTimeout(loop, 20) + setTimeout(loop, 50) cycles = 0 } else loop() } else { @@ -557,7 +628,7 @@ let demoshIndex = { let theme = +args[0] | 0 const maxnum = themes.length if (!args.length || !Number.isFinite(theme) || theme < 0 || theme >= maxnum) { - this.emit('write', `\x1b[31mUsage: theme [0–${maxnum - 1}]\r\n`) + this.emit('write', `\x1b[31mUsage: theme [0–${maxnum - 1}]\n`) this.destroy() return } @@ -568,6 +639,40 @@ let demoshIndex = { this.destroy() } }, + themes: class ShowThemes extends Process { + color (hex) { + hex = parseInt(hex.substr(1), 16) + let r = hex >> 16 + let g = (hex >> 8) & 0xFF + let b = hex & 0xFF + this.emit('write', `\x1b[48;2;${r};${g};${b}m`) + if (((r + g + b) / 3) > 127) { + this.emit('write', '\x1b[38;5;16m') + } else { + this.emit('write', '\x1b[38;5;255m') + } + } + run (...args) { + for (let i in themes) { + let theme = themes[i] + + let name = ` ${i}`.substr(-2) + + this.emit('write', `Theme ${name}: `) + + for (let col = 0; col < 16; col++) { + let text = ` ${col}`.substr(-2) + this.color(theme[col]) + this.emit('write', text) + this.emit('write', '\x1b[m ') + } + + this.emit('write', '\n') + } + + this.destroy() + } + }, cursor: class SetCursor extends Process { run (...args) { let steady = args.includes('--steady') @@ -590,7 +695,6 @@ let demoshIndex = { } run () { this.shell.terminal.rainbow = !this.shell.terminal.rainbow - this.shell.terminal.rainbowTimer() this.emit('write', '') this.destroy() } @@ -618,7 +722,7 @@ let demoshIndex = { } render () { this.emit('write', '\x1b[m\x1b[2J\x1b[1;1H') - this.emit('write', '\x1b[97m\x1b[1mMouse Demo\r\n\x1b[mMouse movement, clicking and scrolling!') + this.emit('write', '\x1b[97m\x1b[1mMouse Demo\r\n\x1b[mMouse movement, clicking, and scrolling!') // render random data for scrolling for (let y = 0; y < 23; y++) { From cee23ca951bd1c07b9c1d1d1334f18c0894cc028 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 30 Sep 2017 14:36:33 +0200 Subject: [PATCH 28/86] Fix for unpaired surrogates in data codepoints. PROTOCOL CHANGE! --- js/term/screen_parser.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js index a2c8dd3..2c0dbea 100644 --- a/js/term/screen_parser.js +++ b/js/term/screen_parser.js @@ -10,7 +10,9 @@ const SEQ_SET_BG = 6 const SEQ_SET_ATTR_0 = 7 function du (str) { - return str.codePointAt(0) - 1 + let num = str.codePointAt(0) + if (num > 0xDFFF) num -= 0x800 + return num - 1 } /* eslint-disable no-multi-spaces */ @@ -152,10 +154,8 @@ module.exports = class ScreenParser { } else if (topic === TOPIC_CURSOR) { // cursor position - const [cursorY, cursorX] = [ - strArray[ci++].codePointAt(0) - 1, - strArray[ci++].codePointAt(0) - 1 - ] + const cursorY = du(strArray[ci++]) + const cursorX = du(strArray[ci++]) const hanging = du(strArray[ci++]) const cursorMoved = ( @@ -296,7 +296,7 @@ module.exports = class ScreenParser { let data switch (charCode) { case SEQ_REPEAT: - let count = strArray[ci++].codePointAt(0) - 1 + let count = du(strArray[ci++]) for (let j = 0; j < count; j++) { pushCell() if (++cell > screenLength) break From 276d3af7da68f583992d3948c7ae4b7471593940 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 30 Sep 2017 14:58:18 +0200 Subject: [PATCH 29/86] Update demo for new new protocol https://github.com/espterm/espterm-front-end/commit/5245917c88918e23179bb872eec5b0e344b713d1#commitcomment-24670890 --- js/term/demo.js | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/js/term/demo.js b/js/term/demo.js index 39dc9ec..af542fa 100644 --- a/js/term/demo.js +++ b/js/term/demo.js @@ -2,6 +2,8 @@ const EventEmitter = require('events') const { parse2B } = require('../utils') const { themes } = require('./themes') +const encodeAsCodePoint = i => String.fromCodePoint(i + (i >= 0xD800 ? 0x801 : 1)) + class ANSIParser { constructor (handler) { this.reset() @@ -113,7 +115,6 @@ class ANSIParser { } } const TERM_DEFAULT_STYLE = [0, 0, 0] -const TERM_MIN_DRAW_DELAY = 10 let getRainbowColor = t => { let r = Math.floor(Math.sin(t) * 2.5 + 2.5) @@ -270,45 +271,45 @@ class ScrollingTerminal { } getScreenOpts () { let data = 'O' - data += String.fromCodePoint(26) - data += String.fromCodePoint(81) - data += String.fromCodePoint(this.theme + 1) - data += String.fromCodePoint(8) - data += String.fromCodePoint(1) - data += String.fromCodePoint(1) - data += String.fromCodePoint(1) + data += encodeAsCodePoint(25) + data += encodeAsCodePoint(80) + data += encodeAsCodePoint(this.theme) + data += encodeAsCodePoint(7) + data += encodeAsCodePoint(0) + data += encodeAsCodePoint(0) + data += encodeAsCodePoint(0) let attributes = +this.cursor.visible attributes |= (3 << 5) * +this.trackMouse // track mouse controls both attributes |= 3 << 7 // buttons/links always visible attributes |= (this.cursor.style << 9) - data += String.fromCodePoint(attributes + 1) + data += encodeAsCodePoint(attributes) return data } getButtons () { let data = 'B' - data += String.fromCodePoint(6) + data += encodeAsCodePoint(5) data += this.buttonLabels.map(x => x + '\x01').join('') return data } getCursor () { let data = 'C' - data += String.fromCodePoint(this.cursor.y + 1) - data += String.fromCodePoint(this.cursor.x + 1) - data += String.fromCodePoint(1) + data += encodeAsCodePoint(this.cursor.y) + data += encodeAsCodePoint(this.cursor.x) + data += encodeAsCodePoint(0) return data } encodeColor (color) { if (color < 256) { - return String.fromCodePoint(color + 1) + return encodeAsCodePoint(color) } else { color -= 256 - return String.fromCodePoint(((color & 0xFFF) | 0x10000) + 1) + String.fromCodePoint((color >> 12) + 1) + return encodeAsCodePoint((color & 0xFFF) | 0x10000) + encodeAsCodePoint(color >> 12) } } serializeScreen () { let serialized = 'S' - serialized += String.fromCodePoint(1) + String.fromCodePoint(1) - serialized += String.fromCodePoint(this.height + 1) + String.fromCodePoint(this.width + 1) + serialized += encodeAsCodePoint(0) + encodeAsCodePoint(0) + serialized += encodeAsCodePoint(this.height) + encodeAsCodePoint(this.width) let lastStyle = [null, null, null] let index = 0 @@ -334,14 +335,14 @@ class ScrollingTerminal { if (setForeground && setBackground) { if (foreground < 256 && background < 256) { - serialized += '\x03' + String.fromCodePoint(((background << 8) | foreground) + 1) + serialized += '\x03' + encodeAsCodePoint((background << 8) | foreground) } else { serialized += '\x05' + this.encodeColor(foreground) serialized += '\x06' + this.encodeColor(background) } } else if (setForeground) serialized += '\x05' + this.encodeColor(foreground) else if (setBackground) serialized += '\x06' + this.encodeColor(background) - if (setAttributes) serialized += '\x04' + String.fromCodePoint(attributes + 1) + if (setAttributes) serialized += '\x04' + encodeAsCodePoint(attributes) lastStyle = style serialized += cell[0] @@ -372,7 +373,7 @@ class ScrollingTerminal { topicData.push(screen) } if (!topicData.length) return '' - return 'U' + String.fromCodePoint(topics + 1) + topicData.join('') + return 'U' + encodeAsCodePoint(topics) + topicData.join('') } loadTimer () { clearInterval(this._loadTimer) From a25d0a4c0583b96b88bd4da33c6ffab01900345a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 30 Sep 2017 15:22:47 +0200 Subject: [PATCH 30/86] Fix https://github.com/espterm/espterm-firmware/issues/226 foreach on node list --- js/term/themes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/js/term/themes.js b/js/term/themes.js index 5cab5ca..699c017 100644 --- a/js/term/themes.js +++ b/js/term/themes.js @@ -1,3 +1,4 @@ +const $ = require('../lib/chibi') const themes = exports.themes = [ [ // 0 - Tango - terminator @@ -99,12 +100,12 @@ exports.SELECTION_FG = '#333' exports.SELECTION_BG = '#b2d7fe' exports.themePreview = function (themeN) { - document.querySelectorAll('[data-fg]').forEach((elem) => { + $('[data-fg]').forEach((elem) => { let shade = elem.dataset.fg if (/^\d+$/.test(shade)) shade = exports.toCss(shade, themeN) elem.style.color = shade }) - document.querySelectorAll('[data-bg]').forEach((elem) => { + $('[data-bg]').forEach((elem) => { let shade = elem.dataset.bg if (/^\d+$/.test(shade)) shade = exports.toCss(shade, themeN) elem.style.backgroundColor = shade From d2dc99b6ff7221e7226e75d49da9c59ec4e42c99 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 30 Sep 2017 16:54:24 +0200 Subject: [PATCH 31/86] Add various things to the demo --- js/term/demo.js | 178 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 136 insertions(+), 42 deletions(-) diff --git a/js/term/demo.js b/js/term/demo.js index af542fa..f5175d7 100644 --- a/js/term/demo.js +++ b/js/term/demo.js @@ -143,7 +143,7 @@ class ScrollingTerminal { this.cursor = { x: 0, y: 0, style: 1, visible: true } this.trackMouse = false this.theme = 0 - this.rainbow = false + this.rainbow = this.superRainbow = false this.parser.reset() this.clear() } @@ -291,6 +291,9 @@ class ScrollingTerminal { data += this.buttonLabels.map(x => x + '\x01').join('') return data } + getTitle () { + return 'TESPTerm Web UI Demo\x01' + } getCursor () { let data = 'C' data += encodeAsCodePoint(this.cursor.y) @@ -319,10 +322,15 @@ class ScrollingTerminal { let x = index % this.width let y = Math.floor(index / this.width) // C instead of F in mask and 1 << 8 in attrs to change attr bits 1 and 2 - style[0] = getRainbowColor((x + y) / 10 + Date.now() / 1000) + let t = (x + y) / 10 + Date.now() / 1000 + if (this.superRainbow) { + t = (x * y + Date.now()) / 100 + Date.now() / 1000 + } + style[0] = getRainbowColor(t) style[1] = 0 + if (this.superRainbow) style[1] = getRainbowColor(t / 10) style[2] = style[2] | 1 - if (style[2] & (1 << 1)) style[2] ^= (1 << 1) + if (!this.superRainbow && style[2] & (1 << 1)) style[2] ^= (1 << 1) index++ } @@ -353,6 +361,7 @@ class ScrollingTerminal { let topics = 0 let topicData = [] let screenOpts = this.getScreenOpts() + let title = this.getTitle() let buttons = this.getButtons() let cursor = this.getCursor() let screen = this.serializeScreen() @@ -360,6 +369,10 @@ class ScrollingTerminal { this._screenOpts = screenOpts topicData.push(screenOpts) } + if (this._title !== title) { + this._title = title + topicData.push(title) + } if (this._buttons !== buttons) { this._buttons = buttons topicData.push(buttons) @@ -528,7 +541,7 @@ let demoshIndex = { } return new Promise((resolve, reject) => { const self = this - let x = 14 + let x = 13 let cycles = 0 let loop = function () { for (let y = 0; y < splash.length; y++) { @@ -536,7 +549,7 @@ let demoshIndex = { if (dx > 0) drawCell(dx, y) } - if (++x < 69) { + if (++x < 70) { if (++cycles >= 3) { setTimeout(loop, 50) cycles = 0 @@ -690,15 +703,40 @@ let demoshIndex = { } }, rainbow: class ToggleRainbow extends Process { - constructor (shell) { + constructor (shell, options = {}) { super() this.shell = shell + this.su = options.su + this.abort = false } - run () { - this.shell.terminal.rainbow = !this.shell.terminal.rainbow - this.emit('write', '') + write (data, newLine = true) { + if (data === 'y') { + this.shell.terminal.rainbow = !this.shell.terminal.rainbow + this.shell.terminal.superRainbow = true + demoData._didWarnRainbow = true + } else { + this.emit('write', data) + } + if (newLine) this.emit('write', '\x1b[0;32m\x1b[G\x1b[79PRainbow!\n') this.destroy() } + run () { + if (this.su && !this.shell.terminal.rainbow) { + if (!demoData._didWarnRainbow) { + this.emit('write', '\x1b[31;1mWarning: flashy colors. Continue? [y/N] ') + } else { + this.write('y', false) + } + } else { + this.shell.terminal.rainbow = !this.shell.terminal.rainbow + this.shell.terminal.superRainbow = false + this.destroy() + } + } + destroy () { + this.abort = true + super.destroy() + } }, mouse: class ShowMouse extends Process { constructor (shell) { @@ -767,43 +805,19 @@ let demoshIndex = { constructor (shell) { super() this.shell = shell + this.didDestroy = false } run (...args) { if (args.length === 0) { - this.emit('write', '\x1b[31mUsage: sudo \x1b[m\r\n') - this.destroy() - } else if (args.length === 4 && args.join(' ').toLowerCase() === 'make me a sandwich') { - const b = '\x1b[33m' - const r = '\x1b[0m' - const l = '\x1b[32m' - const c = '\x1b[38;5;229m' - const h = '\x1b[38;5;225m' - this.emit('write', - ` ${b}_.---._\r\n` + - ` _.-~ ~-._\r\n` + - ` _.-~ ~-._\r\n` + - ` _.-~ ~---._\r\n` + - ` _.-~ ~\\\r\n` + - ` .-~ _.;\r\n` + - ` :-._ _.-~ ./\r\n` + - ` \`-._~-._ _..__.-~ _.-~\r\n` + - ` ${c}/ ${b}~-._~-._ / .__..--${c}~-${l}---._\r\n` + - `${c} \\_____(_${b};-._\\. _.-~_/${c} ~)${l}.. . \\\r\n` + - `${l} /(_____ ${b}\\\`--...--~_.-~${c}______..-+${l}_______)\r\n` + - `${l} .(_________/${b}\`--...--~/${l} _/ ${h} ${b}/\\\r\n` + - `${b} /-._${h} \\_ ${l}(___./_..-~${h}__.....${b}__..-~./\r\n` + - `${b} \`-._~-._${h} ~\\--------~ .-~${b}_..__.-~ _.-~\r\n` + - `${b} ~-._~-._ ${h}~---------\` ${b}/ .__..--~\r\n` + - `${b} ~-._\\. _.-~_/\r\n` + - `${b} \\\`--...--~_.-~\r\n` + - `${b} \`--...--~${r}\r\n`) + this.emit('write', '\x1b[31mUsage: sudo [command]\x1b[m\r\n') this.destroy() } else { let name = args.shift() if (this.shell.index[name]) { let Process = this.shell.index[name] if (Process instanceof Function) { - let child = new Process(this) + let child = this.child = new Process(this.shell, { su: true }) + this.on('in', data => child.write(data)) let write = data => this.emit('write', data) child.on('write', write) child.on('exit', code => { @@ -821,12 +835,50 @@ let demoshIndex = { } } } + destroy () { + if (this.didDestroy) return + this.didDestroy = true + this.child.destroy() + super.destroy() + } }, make: class Make extends Process { + constructor (shell, options = {}) { + super() + this.su = options.su + } run (...args) { if (args.length === 0) this.emit('write', '\x1b[31mmake: *** No targets specified. Stop.\x1b[0m\r\n') else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') { - this.emit('write', '\x1b[31mmake: me a sandwich : Permission denied\x1b[0m\r\n') + console.log(this) + if (this.su) { + const b = '\x1b[33m' + const r = '\x1b[0m' + const l = '\x1b[32m' + const c = '\x1b[38;5;229m' + const h = '\x1b[38;5;225m' + this.emit('write', + ` ${b}_.---._\r\n` + + ` _.-~ ~-._\r\n` + + ` _.-~ ~-._\r\n` + + ` _.-~ ~---._\r\n` + + ` _.-~ ~\\\r\n` + + ` .-~ _.;\r\n` + + ` :-._ _.-~ ./\r\n` + + ` \`-._~-._ _..__.-~ _.-~\r\n` + + ` ${c}/ ${b}~-._~-._ / .__..--${c}~-${l}---._\r\n` + + `${c} \\_____(_${b};-._\\. _.-~_/${c} ~)${l}.. . \\\r\n` + + `${l} /(_____ ${b}\\\`--...--~_.-~${c}______..-+${l}_______)\r\n` + + `${l} .(_________/${b}\`--...--~/${l} _/ ${h} ${b}/\\\r\n` + + `${b} /-._${h} \\_ ${l}(___./_..-~${h}__.....${b}__..-~./\r\n` + + `${b} \`-._~-._${h} ~\\--------~ .-~${b}_..__.-~ _.-~\r\n` + + `${b} ~-._~-._ ${h}~---------\` ${b}/ .__..--~\r\n` + + `${b} ~-._\\. _.-~_/\r\n` + + `${b} \\\`--...--~_.-~\r\n` + + `${b} \`--...--~${r}\r\n`) + } else { + this.emit('write', '\x1b[31mmake: me a sandwich : Permission denied\x1b[0m\r\n') + } } else { this.emit('write', `\x1b[31mmake: *** No rule to make target '${args.join(' ').toLowerCase()}'. Stop.\x1b[0m\r\n`) } @@ -852,6 +904,12 @@ let demoshIndex = { } } } +let autocompleteIndex = { + 'local-echo': 'local-echo [--suppress-note]', + theme: 'theme [n]', + cursor: 'cursor [block|line|bar] [--steady]', + sudo: 'sudo [command]' +} class DemoShell { constructor (terminal, printInfo) { @@ -861,6 +919,7 @@ class DemoShell { this.history = [] this.historyIndex = 0 this.cursorPos = 0 + this.lastInputLength = 0 this.child = null this.index = demoshIndex @@ -887,8 +946,29 @@ class DemoShell { this.history[0] = current this.historyIndex = 0 } + getCompleted (visual = false) { + if (this.history[0]) { + let input = this.history[0] + let prefix = '' + if (input.startsWith('sudo ')) { + let newInput = input.replace(/^(sudo\s+)+/, '') + prefix = input.substr(0, input.length - newInput.length) + input = newInput + } + for (let name in this.index) { + if (name.startsWith(input) && name !== input) { + if (visual && name in autocompleteIndex) return prefix + autocompleteIndex[name] + return prefix + name + } + } + return null + } + return null + } handleParsed (action, ...args) { + this.terminal.write(`\x1b[${this.lastInputLength - this.cursorPos}P`) this.terminal.write('\b\x1b[P'.repeat(this.cursorPos)) + if (action === 'write') { this.copyFromHistoryIndex() this.history[0] = this.history[0].substr(0, this.cursorPos) + args[0] + this.history[0].substr(this.cursorPos) @@ -899,7 +979,11 @@ class DemoShell { this.cursorPos-- if (this.cursorPos < 0) this.cursorPos = 0 } else if (action === 'tab') { - console.warn('TAB not implemented') // TODO completion + let completed = this.getCompleted() + if (completed) { + this.history[0] = completed + this.cursorPos = this.history[0].length + } } else if (action === 'move-cursor-x') { this.cursorPos = Math.max(0, Math.min(this.history[this.historyIndex].length, this.cursorPos + args[0])) } else if (action === 'delete-line') { @@ -922,17 +1006,27 @@ class DemoShell { this.terminal.write(this.history[this.historyIndex]) this.terminal.write('\b'.repeat(this.history[this.historyIndex].length)) this.terminal.moveForward(this.cursorPos) - this.terminal.write('') // dummy. Apply the moveFoward + + this.lastInputLength = this.cursorPos + + let completed = this.getCompleted(true) + if (this.historyIndex === 0 && completed) { + // show closest match faintly + let rest = completed.substr(this.history[0].length) + this.terminal.write(`\x1b[2m${rest}\x1b[m${'\b'.repeat(rest.length)}`) + this.lastInputLength += rest.length + } if (action === 'return') { - this.terminal.write('\r\n') + this.terminal.write('\n') this.parse(this.history[this.historyIndex]) } } parse (input) { if (input === 'help') input = 'info' // TODO: basic chaining (i.e. semicolon) - this.run(input) + if (input) this.run(input) + else this.prompt() } run (command) { let parts = [''] From 3de6e621e5f0c473d32f6bea4ab94f34497db7b2 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 30 Sep 2017 16:58:00 +0200 Subject: [PATCH 32/86] =?UTF-8?q?=E2=88=92console.log?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/term/demo.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/term/demo.js b/js/term/demo.js index f5175d7..098577d 100644 --- a/js/term/demo.js +++ b/js/term/demo.js @@ -850,7 +850,6 @@ let demoshIndex = { run (...args) { if (args.length === 0) this.emit('write', '\x1b[31mmake: *** No targets specified. Stop.\x1b[0m\r\n') else if (args.length === 3 && args.join(' ').toLowerCase() === 'me a sandwich') { - console.log(this) if (this.su) { const b = '\x1b[33m' const r = '\x1b[0m' From 73cb0a4b2b575302c95e3860ebb91cdd9078a720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 30 Sep 2017 17:48:03 +0200 Subject: [PATCH 33/86] Interpret bold 0-7 as bold 8-15 (matches Xterm reference impl), add SEQ_SKIP --- js/term/index.js | 2 +- js/term/screen_parser.js | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/js/term/index.js b/js/term/index.js index 77a1268..6600abd 100644 --- a/js/term/index.js +++ b/js/term/index.js @@ -40,7 +40,7 @@ module.exports = function (opts) { }) conn.on('disconnect', () => { // console.log('*disconnect') - showSplash({ title: 'Disconnected' }) + showSplash({ title: 'Disconnected' }, 500) screen.screen = [] screen.screenFG = [] screen.screenBG = [] diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js index 2c0dbea..cd48554 100644 --- a/js/term/screen_parser.js +++ b/js/term/screen_parser.js @@ -2,6 +2,7 @@ const $ = require('../lib/chibi') const { qs } = require('../utils') // constants for decoding the update blob +const SEQ_SKIP = 1 const SEQ_REPEAT = 2 const SEQ_SET_COLORS = 3 const SEQ_SET_ATTRS = 4 @@ -266,6 +267,12 @@ module.exports = class ScreenParser { let myAttrs = attrs let hasFG = attrs & ATTR_FG let hasBG = attrs & ATTR_BG + + // use 0,0 if no fg/bg. this is to match back-end implementation + // and allow leaving out fg/bg setting for cells with none + if (!hasFG) fg = 0 + if (!hasBG) bg = 0 + if ((myAttrs & MASK_BLINK) !== 0 && ((lastChar === ' ' && ((myAttrs & MASK_LINE_ATTR) === 0)) || // no line styles (fg === bg && hasFG && hasBG) // invisible text @@ -283,8 +290,15 @@ module.exports = class ScreenParser { let cellYInFrame = Math.floor(cell / frameWidth) let index = (frameY + cellYInFrame) * this.screen.window.width + frameX + cellXInFrame + let cellFg = fg + + // 8 dark system colors turn bright when bold + if ((myAttrs & ATTR_BOLD) && !(myAttrs & ATTR_FAINT) && hasFG && fg < 8) { + cellFg += 8 + } + this.screen.screen[index] = lastChar - this.screen.screenFG[index] = fg + this.screen.screenFG[index] = cellFg this.screen.screenBG[index] = bg this.screen.screenAttrs[index] = myAttrs } @@ -293,16 +307,20 @@ module.exports = class ScreenParser { let character = strArray[ci++] let charCode = character.codePointAt(0) - let data + let data, count switch (charCode) { case SEQ_REPEAT: - let count = du(strArray[ci++]) + count = du(strArray[ci++]) for (let j = 0; j < count; j++) { pushCell() if (++cell > screenLength) break } break + case SEQ_SKIP: + cell += du(strArray[ci++]) + break + case SEQ_SET_COLORS: data = du(strArray[ci++]) fg = data & 0xFF @@ -364,6 +382,9 @@ module.exports = class ScreenParser { load (str) { const content = str.substr(1) + // This is a good place for debugging the message + // console.log(str) + switch (str[0]) { case 'U': this.loadUpdate(content) From 3fba2d88c40c7fc78998a2b52d3e7268a52a1474 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 30 Sep 2017 18:33:33 +0200 Subject: [PATCH 34/86] Dynamic buttons --- js/term/buttons.js | 59 ++++++++++++++++++++++++++++++++++++++++ js/term/index.js | 8 ++++++ js/term/input.js | 12 ++------ js/term/screen_parser.js | 15 ++-------- pages/term.php | 8 +----- sass/pages/_term.scss | 4 +++ 6 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 js/term/buttons.js diff --git a/js/term/buttons.js b/js/term/buttons.js new file mode 100644 index 0000000..ceb5e69 --- /dev/null +++ b/js/term/buttons.js @@ -0,0 +1,59 @@ +const { qs } = require('../utils') + +module.exports = function initButtons (input) { + let container = qs('#action-buttons') + + // button labels + let labels = [] + + // button elements + let buttons = [] + + // add a button element + let pushButton = function pushButton () { + let button = document.createElement('button') + button.classList.add('action-button') + button.setAttribute('data-n', buttons.length) + buttons.push(button) + container.appendChild(button) + + button.addEventListener('click', e => { + // might as well use the attribute ¯\_(ツ)_/¯ + let index = +button.getAttribute('data-n') + input.sendButton(index) + }) + + return button + } + + // remove a button element + let popButton = function popButton () { + let button = buttons.pop() + button.parentNode.removeChild(button) + } + + // sync with DOM + let update = function updateButtons () { + console.log(labels) + if (labels.length > buttons.length) { + for (let i = buttons.length; i < labels.length; i++) { + pushButton() + } + } else if (buttons.length > labels.length) { + for (let i = labels.length; i < buttons.length; i++) { + popButton() + } + } + + for (let i = 0; i < labels.length; i++) { + let label = labels[i].trim() + let button = buttons[i] + button.textContent = label || '\u00a0' // label or nbsp + if (!label) { + button.classList.add('inactive') + } + } + } + + return { update, labels } +} diff --git a/js/term/index.js b/js/term/index.js index 6600abd..7f4337c 100644 --- a/js/term/index.js +++ b/js/term/index.js @@ -6,6 +6,7 @@ const TermInput = require('./input') const TermUpload = require('./upload') const initSoftKeyboard = require('./soft_keyboard') const attachDebugScreen = require('./debug_screen') +const initButtons = require('./buttons') /** Init the terminal sub-module - called from HTML */ module.exports = function (opts) { @@ -17,6 +18,13 @@ module.exports = function (opts) { screen.conn = conn input.termUpload = termUpload + const buttons = initButtons(input) + screen.on('button-labels', labels => { + // TODO: don't use pointers for this + buttons.labels.splice(0, buttons.labels.length, ...labels) + buttons.update() + }) + let showSplashTimeout = null let showSplash = (obj, delay = 250) => { clearTimeout(showSplashTimeout) diff --git a/js/term/input.js b/js/term/input.js index c0649d0..1f319c7 100644 --- a/js/term/input.js +++ b/js/term/input.js @@ -242,8 +242,8 @@ module.exports = function (conn, screen) { } /** Send a button event */ - function sendButton (n) { - conn.send('b' + String.fromCharCode(n)) + function sendButton (index) { + conn.send('b' + String.fromCharCode(index + 1)) } const shouldAcceptEvent = function () { @@ -354,13 +354,6 @@ module.exports = function (conn, screen) { function init (opts) { initKeys(opts) - // Button presses - $('#action-buttons button').forEach(s => { - s.addEventListener('click', function (evt) { - sendButton(+this.dataset['n']) - }) - }) - // global mouse state tracking - for motion reporting window.addEventListener('mousedown', evt => { if (evt.button === 0) mb1 = 1 @@ -404,6 +397,7 @@ module.exports = function (conn, screen) { /** Send a literal string message */ sendString, + sendButton, /** Enable alternate key modes (cursors, numpad, fn) */ setAlts: function (cu, np, fn, crlf) { diff --git a/js/term/screen_parser.js b/js/term/screen_parser.js index cd48554..16400a6 100644 --- a/js/term/screen_parser.js +++ b/js/term/screen_parser.js @@ -193,11 +193,9 @@ module.exports = class ScreenParser { qs('title').textContent = `${text} :: ESPTerm` } else if (topic === TOPIC_BUTTONS) { - - // TODO optimize this const count = du(strArray[ci++]) - let buttons = [] + let labels = [] for (let j = 0; j < count; j++) { text = '' while (ci < strArray.length) { @@ -205,17 +203,10 @@ module.exports = class ScreenParser { if (c === '\x01') break text += c } - buttons.push(text) + labels.push(text) } - $('#action-buttons button').forEach((button, i) => { - let label = buttons[i].trim() - // if empty string, use the "dim" effect and put nbsp instead to - // stretch the button vertically - button.innerHTML = label.length ? $.htmlEscape(label) : ' ' - button.style.opacity = label.length ? 1 : 0.2 - }) - + this.screen.emit('button-labels', labels) } else if (topic === TOPIC_BELL) { this.screen.beep() diff --git a/pages/term.php b/pages/term.php index feb3c92..55e26bc 100644 --- a/pages/term.php +++ b/pages/term.php @@ -55,13 +55,7 @@
-
- -
+