From 34445ebfb4a34760fdd1d781c7ffe946903c9d1b Mon Sep 17 00:00:00 2001 From: masukomi Date: Sat, 8 Oct 2022 13:14:15 -0400 Subject: [PATCH] [screen modes] fix: explicit handling of screen modes Escape sequences that set screen modes were not handled Now they are explicitly handled, and ignored. --- .../2e97ab2c3597636c8da399451aa57812.json | 1 + .../34e99410c2fe5f6f718294dda8a5c098.json | 1 + .../9a8c11ee5c165b78734f8293c31ec0a3.json | 1 + CHANGELOG.md | 55 +++++++++++++ README.md | 13 ++++ spec/oho/color_escape_code_spec.cr | 35 +++++++++ spec/oho/converter_spec.cr | 21 +++++ src/oho/color_escape_code.cr | 77 +++++++++++++++---- 8 files changed, 189 insertions(+), 15 deletions(-) create mode 100644 .changelog_entries/2e97ab2c3597636c8da399451aa57812.json create mode 100644 .changelog_entries/34e99410c2fe5f6f718294dda8a5c098.json create mode 100644 .changelog_entries/9a8c11ee5c165b78734f8293c31ec0a3.json create mode 100644 CHANGELOG.md diff --git a/.changelog_entries/2e97ab2c3597636c8da399451aa57812.json b/.changelog_entries/2e97ab2c3597636c8da399451aa57812.json new file mode 100644 index 0000000..4294fd8 --- /dev/null +++ b/.changelog_entries/2e97ab2c3597636c8da399451aa57812.json @@ -0,0 +1 @@ +{"type":"Added","tickets":[],"description":"added a CHANGELOG.md file","tags":[]} \ No newline at end of file diff --git a/.changelog_entries/34e99410c2fe5f6f718294dda8a5c098.json b/.changelog_entries/34e99410c2fe5f6f718294dda8a5c098.json new file mode 100644 index 0000000..94f7060 --- /dev/null +++ b/.changelog_entries/34e99410c2fe5f6f718294dda8a5c098.json @@ -0,0 +1 @@ +{"type":"Fixed","tickets":[],"description":"fixed indexing error when escape code included no integers","tags":[]} \ No newline at end of file diff --git a/.changelog_entries/9a8c11ee5c165b78734f8293c31ec0a3.json b/.changelog_entries/9a8c11ee5c165b78734f8293c31ec0a3.json new file mode 100644 index 0000000..13964fc --- /dev/null +++ b/.changelog_entries/9a8c11ee5c165b78734f8293c31ec0a3.json @@ -0,0 +1 @@ +{"type":"Added","tickets":[],"description":"added specific non-handling of screen modes","tags":[]} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..02a7827 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,55 @@ +## [1.3.6] - 2022-10-08 +### Added +* added a CHANGELOG.md file +* added specific non-handling of screen modes + +### Fixed +* fixed indexing error when escape code included no integers + +## [1.3.5] - 2021-02-05 +### Changed +* Output no longer includes useless spans. + +### Fixed +* better handling of non-display code amidst display ones + +## [1.3.4] - 2021-02-05 +### Changed +* now supports building under Crystal v0.35.1 + +### Fixed +* fixed missing end span edge case + +## [1.3.3] - 2018-10-01 +## [1.3.2] - 2018-10-01 +### Fixed +* Corrected bug where the ends of escape sequences were not being correctly detected + +## [1.3.1] - 2018-09-03 +### Deprecated +* [\[4\]](https://github.com/masukomi/oho/issues/4) corrects detection and handling of rgb color escape sequences + +## [1.3.0] - 2018-06-15 +### Added +* Added Support for ITU's T.416 / 8613-6 color codes + +## [1.2.0] - 2018-06-05 +### Added +* Added support for customer styling via -s arg + +### Fixed +* further corrections to default background and foreground handling + +## [1.1.1] - 2018-06-05 +### Fixed +* Corrected problem where requesting --help resulted in double output +* Corrected background and foreground color handling + +## [1.1.0] - 2018-05-26 +### Added +* Added print media CSS for better PDF conversions + +### Fixed +* simplified build.sh to remove some git complications + +## [1.0.0] - 2018-05-25 diff --git a/README.md b/README.md index 4f697f3..74ca8cd 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,19 @@ crystal build src/oho.cr An `oho` executable will be created in the current directory. Just move that into your PATH and follow the Usage instructions. + +## Caveats +There are many, _many_ escape sequences that are used in terminals. Oho supports ANSI 3/4 bit (basic and high intensity), 8 bit, +& 24 bit color codes as well as ITU's T.416 / 8613-6 color codes. + +"Screen mode" escape sequences are _not_ supported. In general, this isn't going to be an issue. +For example: `^[=5;7h` would tell a terminal to render as 320 x 200 in Black & White mode. +To support that would require reformatting your text, and making a judgement call about which +colors should be converted to black, and which to white. Currently oho does not address +formatting issues or make judgement calls about colors. If, however, you feel like implementing this, +Pull Requests will be happily accepted. + + ## Development If you're adding new functionality or fixing a bug in existing functionality diff --git a/spec/oho/color_escape_code_spec.cr b/spec/oho/color_escape_code_spec.cr index ba009ca..594dd81 100644 --- a/spec/oho/color_escape_code_spec.cr +++ b/spec/oho/color_escape_code_spec.cr @@ -63,6 +63,41 @@ describe Oho::ColorEscapeCode do "")) end + it "should not blow up when it encounters private use codes" do + ec = Oho::ColorEscapeCode.new("[?1h", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters ? screen mode codes" do + ec = Oho::ColorEscapeCode.new("[?7h", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters = screen mode codes" do + ec = Oho::ColorEscapeCode.new("[=1;7h", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters = screen mode codes 2" do + ec = Oho::ColorEscapeCode.new("[=0h", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters ? screen mode reset codes" do + ec = Oho::ColorEscapeCode.new("[?7l", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters = screen mode reset codes" do + ec = Oho::ColorEscapeCode.new("[=1;7l", default_options) #background + ec.to_span(nil).should(eq("")) + end + + it "should not blow up when it encounters = screen mode reset codes 2" do + ec = Oho::ColorEscapeCode.new("[=0l", default_options) #background + ec.to_span(nil).should(eq("")) + end + it "0 resets all" do ec = Oho::ColorEscapeCode.new("[0m", default_options) #reset all the things prior_ec = Oho::ColorEscapeCode.new("[1;2;3;4;8;36;46m", default_options) diff --git a/spec/oho/converter_spec.cr b/spec/oho/converter_spec.cr index 239708e..694c09d 100644 --- a/spec/oho/converter_spec.cr +++ b/spec/oho/converter_spec.cr @@ -35,7 +35,27 @@ describe Oho::Converter do test_string = "\033[36mfoo\033[Kbar\033[0m" response, escape_code = c.process(test_string, nil) response.should(eq("foobar")) + end + + it "ignores screen mode sequences" do + c = Oho::Converter.new(default_options) + test_string = "\033[=1;7hfoo\033[=0l" + response, escape_code = c.process(test_string, nil) + response.should(eq("foo")) + end + + it "really ignores screen mode sequences" do + c = Oho::Converter.new(default_options) + test_string="\033[?1h\033=\r\033[33mcommit abcd\r\033[K\033[?1l\033>" + response, escape_code = c.process(test_string, nil) + response.should(eq("\rcommit abcd\r")) + end + it "ignores question mark screen mode sequences" do + c = Oho::Converter.new(default_options) + test_string = "\033[?7hfoo\033[?7l" + response, escape_code = c.process(test_string, nil) + response.should(eq("foo")) end it "removes empty spans that do nothing" do @@ -44,6 +64,7 @@ describe Oho::Converter do response, escape_code = c.process(test_string, nil) response.should(eq("foo")) end + it "removes spans that encapsulate nothing" do c = Oho::Converter.new(default_options) test_string = "\033[0mfoo\033[0m" diff --git a/src/oho/color_escape_code.cr b/src/oho/color_escape_code.cr index ea0a762..db03160 100644 --- a/src/oho/color_escape_code.cr +++ b/src/oho/color_escape_code.cr @@ -373,18 +373,26 @@ module Oho getter background_color getter styles : Array(Int32) getter string + getter ignorable @foreground_color : String? @background_color : String? @styles : Array(Int32) + @ignorable : Bool def initialize(@string : String, @options : Hash(Symbol, String)) - if @string.size < 3 || @string[0] != '[' || @string[-1] != 'm' - if @string != "[m" - raise InvalidEscapeCode.new("Invalid escape code: #{@string.split("").inspect}") - else + @ignorable = false + if @string.size < 3 || @string[0] != '[' || @string[-1] != 'm' || @string[1] == '?' + if @string == "[m" # really? was it so hard to write a damn zero? @string = "[0m" + elsif @string[1] == '?' || is_screen_mode?(@string) + #argh. ? marks it as "private use" + # (a category set aside for implementation-specific features in the standard) + # "screen mode" sequences are not supported. + @ignorable = true + else + raise InvalidEscapeCode.new("Invalid escape code: #{@string.split("").inspect}") end end # if the string has a zero code in it that isn't part of @@ -405,21 +413,27 @@ module Oho # end # end # hell_regexp=".*(?" @@ -470,6 +485,38 @@ module Oho def raw : String @string end + + # Screen Modes + # Documented for future work, but not directly supported. + # ESC[=#;7h or + # ESC[=h or + # ESC[=0h or + # ESC[?7h + # put screen in indicated mode where # is: + # 0 40 x 25 black & white + # 1 40 x 25 color + # 2 80 x 25 b&w + # 3 80 x 25 color + # 4 320 x 200 color graphics + # 5 320 x 200 b & w graphics + # 6 640 x 200 b & w graphics + # 7 to wrap at end of line + # RESETTING.... + # ESC[=#;7l or + # ESC[=l or + # ESC[=0l or + # ESC[?7l + # resets mode # set with above command + private def is_screen_mode?(sequence : String ) : Bool + + # they start with [=Xh or [?7h + # they end with [=xl or [?7l + # start screen mode + return true if /^\[=\d?(?:h|l)$/ =~ @string + return true if /^\[?7(?:h|l)/ =~ @string + return true if /^\[=\d;7(?:h|l)/ =~ @string + false + end private def generate_foreground_string(escape_code : EscapeCode?) : String if ! foreground_color.nil? && foreground_color != "" return "color: #{foreground_color}; "