terminal-layout 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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