terminal-layout 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c65b1156a204469a85174ffa2bb761a1f4f15593
4
- data.tar.gz: 70c589abe13e269025404af7efe2555c2567e906
3
+ metadata.gz: 2b5943e939a5e3ba0dca04844bbea647acc52b05
4
+ data.tar.gz: 805918708734666de21d1298a74a245aa517eb86
5
5
  SHA512:
6
- metadata.gz: 85ba780f984691a236879b5fc8754e0cf490f7df4d5b9288aa03411c735f985d335a5a454bbb72de72a16fe93b69458acf6c8dc8b2d1c2323d3eb9bc91857abc
7
- data.tar.gz: 47c7317c78a4d5814682665fa77e27e9782b07c5af658eb8a60e73c78bb65ba90ccf490f3284240f08448a54bb38599ddb70d2e4d170574aac489e9e7620da69
6
+ metadata.gz: b87d75ee8483d361a9268fe65514bc61500590d427aab37c68b1b3c8f7ac70af11e5461e600e1629664046c4df8be33f0b8cf3add4734be0d7f1649b349f5ea2
7
+ data.tar.gz: c0cb7f37b2b2e0ea59cf3bcfa024c18f50f6f0aa572c740abc978d6ed4ca1263bf15914dc8ec5c2cdac985a1bf747f2df5a2eb2c100d8308752b7ebe2e77aec7
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.3
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- terminal-layout (0.2.0)
5
- highline
4
+ terminal-layout (0.3.0)
5
+ highline (~> 1.7, >= 1.7.8)
6
6
  ruby-terminfo (~> 0.1.1)
7
7
  ruby-termios (~> 0.9.6)
8
8
 
@@ -49,7 +49,6 @@ PLATFORMS
49
49
 
50
50
  DEPENDENCIES
51
51
  bundler (~> 1.7)
52
- pry
53
52
  pry-byebug
54
53
  rake (~> 10.0)
55
54
  rspec
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ Dir[File.join(File.dirname(__FILE__), 'lib/tasks/**/*.rake')].each {|f| load f }
data/lib/ansi_string.rb CHANGED
@@ -24,6 +24,14 @@ class ANSIString
24
24
  self
25
25
  end
26
26
 
27
+ def insert(position, string)
28
+ if position < 0
29
+ position = @without_ansi.length + position + 1
30
+ end
31
+ self[position...position] = string
32
+ self
33
+ end
34
+
27
35
  def empty?
28
36
  length == 0
29
37
  end
@@ -33,14 +41,19 @@ class ANSIString
33
41
  range = (range..range) if range.is_a?(Integer)
34
42
 
35
43
  range_begin = range.begin
36
- range_end = range.exclude_end? ? range.end - 1 : range.end
44
+ range_end = range.end
45
+ if range.end != range.begin
46
+ range_end = range.exclude_end? ? range.end - 1 : range.end
47
+ end
37
48
 
38
49
  range_begin = @without_ansi.length - range.begin.abs if range.begin < 0
39
50
  range_end = @without_ansi.length - range.end.abs if range.end < 0
40
51
 
41
- str = build_string_with_ansi_for(range_begin..range_end)
42
- if str
43
- ANSIString.new str
52
+ if range_begin == 0 && range_end == 0 && range.exclude_end?
53
+ return ""
54
+ else
55
+ str = build_string_with_ansi_for(range_begin..range_end)
56
+ ANSIString.new str if str
44
57
  end
45
58
  end
46
59
 
@@ -83,22 +96,23 @@ class ANSIString
83
96
  if md.captures.any?
84
97
  results << md.captures.map.with_index do |_, i|
85
98
  # captures use 1-based indexing
86
- self[md.begin(i+1)...md.end(i+1)]
99
+ self[md.begin(i+1)..md.end(i+1)-1]
87
100
  end
88
101
  else
89
- results << self[md.begin(0)...md.end(0)]
102
+ results << self[md.begin(0)..md.end(0)-1]
90
103
  end
91
104
  end
92
105
  results
93
106
  end
94
107
 
95
108
  def slice(index, length=nil)
109
+ return ANSIString.new("") if length == 0
96
110
  range = nil
97
111
  index = index.without_ansi if index.is_a?(ANSIString)
98
112
  index = Regexp.new Regexp.escape(index) if index.is_a?(String)
99
113
  if index.is_a?(Integer)
100
- length = index unless length
101
- range = (index...index+length)
114
+ length ||= 1
115
+ range = (index..index+length-1)
102
116
  elsif index.is_a?(Range)
103
117
  range = index
104
118
  elsif index.is_a?(Regexp)
@@ -106,7 +120,7 @@ class ANSIString
106
120
  capture_group_index = length || 0
107
121
  if md
108
122
  capture_group = md.offset(capture_group_index)
109
- range = (capture_group.first...capture_group.last)
123
+ range = (capture_group.first..capture_group.last-1)
110
124
  end
111
125
  else
112
126
  raise(ArgumentError, "Must pass in at least an index or a range.")
@@ -0,0 +1,62 @@
1
+ namespace :bump do
2
+ namespace :version do
3
+ class ProjectVersion
4
+ FILE = File.dirname(__FILE__) + '/../terminal_layout/version.rb'
5
+ PATTERN = /VERSION\s*=\s*"(\d+)\.(\d+)\.(\d+)"/m
6
+
7
+ def initialize(file=FILE, pattern=PATTERN)
8
+ @file = file
9
+ @pattern = pattern
10
+ end
11
+
12
+ def bump(major:nil, minor:nil, patch:nil)
13
+ version = nil
14
+ contents.sub!(@pattern) do
15
+ _major = major.call($1) if major
16
+ _minor = minor.call($2) if minor
17
+ _patch = patch.call($3) if patch
18
+ version = "#{_major}.#{_minor}.#{_patch}"
19
+ results = %|VERSION = "#{version}"|
20
+ end
21
+ File.write(@file, contents)
22
+ system "bundle"
23
+ system "git add #{ProjectVersion::FILE} && git commit -m 'Bumping version to #{version}'"
24
+ system "git tag v#{version}"
25
+ end
26
+
27
+ private
28
+
29
+ def contents
30
+ @contents ||= File.read(@file)
31
+ end
32
+ end
33
+
34
+ desc "Increments the patch number by 1 for the project"
35
+ task :patch do
36
+ ProjectVersion.new.bump(
37
+ major: ->(major){ major },
38
+ minor: ->(minor){ minor },
39
+ patch: ->(patch){ patch.succ }
40
+ )
41
+ end
42
+
43
+ desc "Increments the minor number by 1 for the project"
44
+ task :minor do
45
+ ProjectVersion.new.bump(
46
+ major: ->(major){ major },
47
+ minor: ->(minor){ minor.succ },
48
+ patch: ->(patch){ 0 }
49
+ )
50
+ end
51
+
52
+ desc "Increments the major number by 1 for the project"
53
+ task :major do
54
+ ProjectVersion.new.bump(
55
+ major: ->(major){ major.succ },
56
+ minor: ->(minor){ 0 },
57
+ patch: ->(patch){ 0 }
58
+ )
59
+ end
60
+
61
+ end
62
+ end
@@ -335,8 +335,8 @@ module TerminalLayout
335
335
  emit :child_changed
336
336
  end
337
337
 
338
- child.on(:cursor_position_changed) do |*args|
339
- emit :cursor_position_changed
338
+ child.on(:position_changed) do |*args|
339
+ emit :position_changed
340
340
  end
341
341
  end
342
342
  end
@@ -402,12 +402,17 @@ module TerminalLayout
402
402
 
403
403
 
404
404
  class InputBox < Box
405
+ # cursor_position is the actual coordinates on the screen of where then
406
+ # cursor is rendered
405
407
  attr_accessor :cursor_position
406
408
 
409
+ # position is the desired X-position of the cursor if everything was
410
+ # displayed on a single line
411
+ attr_accessor :position
412
+
407
413
  def initialize(*args)
408
414
  super
409
415
  @computed = { x: 0, y: 0 }
410
- @cursor_offset_x = 0
411
416
  @cursor_position = OpenStruct.new(x: 0, y: 0)
412
417
  @position = 0
413
418
  end
@@ -429,20 +434,21 @@ module TerminalLayout
429
434
  end
430
435
  end
431
436
 
432
- def position=(position)
433
- @cursor_offset_x = position
434
- @cursor_position.x = @cursor_offset_x + @computed[:x]
435
- emit :cursor_position_changed, nil, @cursor_position.x
437
+ def position=(new_position)
438
+ old_position = @position
439
+ @position = new_position
440
+ emit :position_changed, old_position, @position
436
441
  end
437
442
 
438
443
  def update_computed(style)
439
- @computed.merge!(style)
440
- if style[:y] > 0
441
- @cursor_position.x = @computed[:width] #@computed[:width] - (style[:x] + @cursor_offset_x)
442
- else
443
- @cursor_position.x = style[:x] + @cursor_offset_x
444
+ # if the style being updated has a y greater than 0
445
+ # then it's because the renderable content for the input box
446
+ # spans multiple lines. We do not want to update the x/y position(s)
447
+ # in this instance. We want to keep the original starting x/y.
448
+ if style[:y] && style[:y] > 0
449
+ style = style.dup.delete_if { |k,_| [:x, :y].include?(k) }
444
450
  end
445
- @cursor_position.y = style[:y]
451
+ @computed.merge!(style)
446
452
  end
447
453
  end
448
454
 
@@ -466,17 +472,32 @@ module TerminalLayout
466
472
  move_up_n_rows @y
467
473
  move_to_beginning_of_row
468
474
 
475
+ position = input_box.position
476
+
469
477
  cursor_position = input_box.cursor_position
470
478
  cursor_x = cursor_position.x
471
479
  cursor_y = cursor_position.y
472
480
 
473
- # TODO: make this work when lines wrap
474
- if cursor_x < 0 && cursor_y == 0
475
- cursor_x = terminal_width
476
- cursor_y -= 1
477
- elsif cursor_x >= terminal_width
478
- cursor_y = cursor_x / terminal_width
479
- cursor_x -= terminal_width
481
+ relative_position_on_row = position
482
+ initial_offset_x = input_box.computed[:x] + (input_box.computed[:y] * terminal_width)
483
+ cursor_x = 0
484
+ cursor_y = 0
485
+
486
+ absolute_position_on_row = relative_position_on_row + initial_offset_x
487
+ loop do
488
+ if absolute_position_on_row >= terminal_width
489
+ # reset offset
490
+ initial_offset_x = 0
491
+
492
+ absolute_position_on_row -= terminal_width
493
+
494
+ # move down a line
495
+ cursor_y += 1
496
+ else
497
+ # we fit on the current line
498
+ cursor_x = absolute_position_on_row
499
+ break
500
+ end
480
501
  end
481
502
 
482
503
  if @y < cursor_y
@@ -0,0 +1,3 @@
1
+ module TerminalLayout
2
+ VERSION = "0.3.0"
3
+ end
@@ -105,6 +105,32 @@ describe 'ANSIString' do
105
105
  end
106
106
  end
107
107
 
108
+ describe "#insert (see Ruby's String#insert for intent)" do
109
+ it "insert a string into the ANSIString" do
110
+ ansi_string = ANSIString.new "az"
111
+ ansi_string.insert 1, "thru"
112
+ expect(ansi_string).to eq ANSIString.new("athruz")
113
+
114
+ ansi_string.insert 0, "_"
115
+ expect(ansi_string).to eq ANSIString.new("_athruz")
116
+
117
+ ansi_string.insert ansi_string.length, "_"
118
+ expect(ansi_string).to eq ANSIString.new("_athruz_")
119
+ end
120
+
121
+ it "insert an ANSIString into an ANSIString" do
122
+ ansi_string = ANSIString.new blue("az")
123
+ ansi_string.insert 1, yellow("thru")
124
+ expect(ansi_string).to eq ANSIString.new("\e[34ma\e[33mthru\e[0mz\e[0m")
125
+ end
126
+
127
+ it "inserts from the end with a negative position" do
128
+ ansi_string = ANSIString.new blue("az")
129
+ ansi_string.insert -2, yellow("thru")
130
+ expect(ansi_string).to eq ANSIString.new("\e[34ma\e[33mthru\e[0mz\e[0m")
131
+ end
132
+ end
133
+
108
134
  describe "#length" do
109
135
  subject(:ansi_string){ ANSIString.new blue(string) }
110
136
  let(:string){ "this is blue" }
@@ -540,6 +566,7 @@ describe 'ANSIString' do
540
566
 
541
567
  it "returns a substring of characters of N length given a start index and max length N" do
542
568
  ansi_string = ANSIString.new("a#{blue('b')}c")
569
+ expect(ansi_string.slice(0, 0)).to eq ANSIString.new("")
543
570
  expect(ansi_string.slice(0, 2)).to eq ANSIString.new("a#{blue('b')}")
544
571
  expect(ansi_string.slice(1, 2)).to eq ANSIString.new("#{blue('b')}c")
545
572
 
@@ -1,10 +1,11 @@
1
1
  # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'terminal_layout/version'
4
5
 
5
6
  Gem::Specification.new do |spec|
6
7
  spec.name = "terminal-layout"
7
- spec.version = "0.2.0"
8
+ spec.version = TerminalLayout::VERSION
8
9
  spec.authors = ["Zach Dennis"]
9
10
  spec.email = ["zach.dennis@gmail.com"]
10
11
  spec.summary = %q{A terminal layout manager}
@@ -17,12 +18,11 @@ Gem::Specification.new do |spec|
17
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
19
  spec.require_paths = ["lib"]
19
20
 
20
- spec.add_dependency "ruby-terminfo", "~> 0.1.1"
21
- spec.add_dependency "ruby-termios", "~> 0.9.6"
22
- spec.add_dependency "highline"
21
+ spec.add_dependency "ruby-terminfo", "~> 0.1.1"
22
+ spec.add_dependency "ruby-termios", "~> 0.9.6"
23
+ spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8'
23
24
 
24
25
  spec.add_development_dependency "bundler", "~> 1.7"
25
26
  spec.add_development_dependency "rake", "~> 10.0"
26
27
  spec.add_development_dependency "rspec", "~> 3.2"
27
- spec.add_development_dependency "pry"
28
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terminal-layout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2016-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-terminfo
@@ -42,16 +42,22 @@ dependencies:
42
42
  name: highline
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.7'
45
48
  - - ">="
46
49
  - !ruby/object:Gem::Version
47
- version: '0'
50
+ version: 1.7.8
48
51
  type: :runtime
49
52
  prerelease: false
50
53
  version_requirements: !ruby/object:Gem::Requirement
51
54
  requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.7'
52
58
  - - ">="
53
59
  - !ruby/object:Gem::Version
54
- version: '0'
60
+ version: 1.7.8
55
61
  - !ruby/object:Gem::Dependency
56
62
  name: bundler
57
63
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +100,6 @@ dependencies:
94
100
  - - "~>"
95
101
  - !ruby/object:Gem::Version
96
102
  version: '3.2'
97
- - !ruby/object:Gem::Dependency
98
- name: pry
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
103
  description: A terminal layout manager
112
104
  email:
113
105
  - zach.dennis@gmail.com
@@ -116,13 +108,17 @@ extensions: []
116
108
  extra_rdoc_files: []
117
109
  files:
118
110
  - ".rspec"
111
+ - ".ruby-version"
119
112
  - ".travis.yml"
120
113
  - Gemfile
121
114
  - Gemfile.lock
122
115
  - README.md
116
+ - Rakefile
123
117
  - block-flow.rb
124
118
  - lib/ansi_string.rb
119
+ - lib/tasks/gem.rake
125
120
  - lib/terminal_layout.rb
121
+ - lib/terminal_layout/version.rb
126
122
  - spec/ansi_string_spec.rb
127
123
  - spec/spec_helper.rb
128
124
  - spec/terminal_layout_spec.rb