From eacbef73b404209f196376c729b91d57f5c1553c Mon Sep 17 00:00:00 2001 From: Gavin Laking Date: Wed, 11 Nov 2015 19:02:41 +0000 Subject: [PATCH] Compress position escape sequences; Compression is achieved by not repeatedly sending a position when only the x coordinate has changed; i.e. we are on the same line, just advancing a character. In the test application, we have gone from sending 72260 characters to the terminal to just 13971- approximately 80% reduction. Reported compression time has changed from average 20.6ms to 13.2ms- a ~35% improvement. Also, add more documentation. Work related to #302. --- lib/vedeu/output/compressor.rb | 23 ++++++++- test/lib/vedeu/output/compressor_test.rb | 59 +++++++++++++----------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/lib/vedeu/output/compressor.rb b/lib/vedeu/output/compressor.rb index 0052de086..e4c8b8d49 100644 --- a/lib/vedeu/output/compressor.rb +++ b/lib/vedeu/output/compressor.rb @@ -62,7 +62,7 @@ def compress out = '' content.each do |cell| - out << cell.position.to_s + out << position_for(cell) out << colour_for(cell) out << style_for(cell) out << cell.value @@ -91,6 +91,23 @@ def uncompress out end + # Compress by not repeatedly sending a position when only the x + # coordinate has changed; i.e. we are on the same line, just + # advancing a character. + # + # @param char [Vedeu::Views::Char] + # @return [String] + def position_for(char) + return ''.freeze if char.position.y == @y + + @y = char.position.y + char.position.to_s + end + + # Compress by not repeatedly sending the same colours for each + # character which has the same colours as the last character + # output. + # # @param char [Vedeu::Views::Char] # @return [String] def colour_for(char) @@ -100,6 +117,10 @@ def colour_for(char) @colour.to_s end + # Compress by not repeatedly sending the same style(s) for each + # character which has the same style(s) as the last character + # output. + # # @param char [Vedeu::Views::Char] # @return [String] def style_for(char) diff --git a/test/lib/vedeu/output/compressor_test.rb b/test/lib/vedeu/output/compressor_test.rb index 57cfd9b6f..75af3adf2 100644 --- a/test/lib/vedeu/output/compressor_test.rb +++ b/test/lib/vedeu/output/compressor_test.rb @@ -29,42 +29,49 @@ module Output context 'when the output is all Vedeu::Views::Char elements' do let(:output) { Vedeu::Models::Page.coerce([ - Vedeu::Views::Char.new(value: 'Y', - name: _name, - colour: { foreground: '#ff0000' }), - Vedeu::Views::Char.new(value: 'e', - name: _name, - colour: { foreground: '#ff0000' }), - Vedeu::Views::Char.new(value: 's', - name: _name, - colour: { foreground: '#ff0000' }), + Vedeu::Views::Char.new(value: 'Y', + name: _name, + colour: { foreground: '#ff0000' }, + position: [1, 1]), + Vedeu::Views::Char.new(value: 'e', + name: _name, + colour: { foreground: '#ff0000' }, + position: [1, 2]), + Vedeu::Views::Char.new(value: 's', + name: _name, + colour: { foreground: '#ff0000' }, + position: [1, 3]) ]) } it 'converts the non-Vedeu::Views::Char elements into String ' \ 'elements' do - subject.must_equal("\e[38;2;255;0;0mYes") + subject.must_equal("\e[1;1H\e[38;2;255;0;0mYes") end end context 'when the output is all Vedeu::Views::Char elements' do let(:output) { Vedeu::Models::Page.coerce([ - Vedeu::Views::Char.new(value: 'a', - name: _name, - colour: { foreground: '#ff0000' }), - Vedeu::Views::Char.new(value: 'b', - name: _name, - colour: { foreground: '#ff0000' }), - Vedeu::Views::Char.new(value: 'c', - name: _name, - colour: { foreground: '#0000ff' }), - Vedeu::Views::Char.new(value: 'd', - name: _name, - colour: { foreground: '#0000ff' }), + Vedeu::Views::Char.new(value: 'a', + name: _name, + colour: { foreground: '#ff0000' }, + position: [1, 1]), + Vedeu::Views::Char.new(value: 'b', + name: _name, + colour: { foreground: '#ff0000' }, + position: [1, 2]), + Vedeu::Views::Char.new(value: 'c', + name: _name, + colour: { foreground: '#0000ff' }, + position: [1, 3]), + Vedeu::Views::Char.new(value: 'd', + name: _name, + colour: { foreground: '#0000ff' }, + position: [1, 4]), ]) } it 'compresses multiple colours and styles where possible' do - subject.must_equal("\e[38;2;255;0;0mab\e[38;2;0;0;255mcd") + subject.must_equal("\e[1;1H\e[38;2;255;0;0mab\e[38;2;0;0;255mcd") end end @@ -72,14 +79,14 @@ module Output 'elements' do let(:output) { Vedeu::Models::Page.coerce([ - Vedeu::Views::Char.new(name: _name, value: 'N'), + Vedeu::Views::Char.new(name: _name, value: 'N', position: [1, 1]), Vedeu::Models::Escape.new(value: "\e[?25l"), - Vedeu::Views::Char.new(name: _name, value: 't'), + Vedeu::Views::Char.new(name: _name, value: 't', position: [1, 3]), ]) } it 'converts the non-Vedeu::Views::Char elements into String ' \ 'elements' do - subject.must_equal("N\e[1;1H\e[?25lt") + subject.must_equal("\e[1;1HN\e[?25lt") end end end