twterm 1.3.0 → 2.0.0.beta1

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.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -18
  3. data/bin/twterm +1 -1
  4. data/lib/twterm/app.rb +120 -30
  5. data/lib/twterm/client.rb +10 -13
  6. data/lib/twterm/completion_mamanger.rb +11 -6
  7. data/lib/twterm/direct_message.rb +6 -28
  8. data/lib/twterm/direct_message_composer.rb +10 -5
  9. data/lib/twterm/direct_message_manager.rb +5 -6
  10. data/lib/twterm/event/notification/abstract_notification.rb +27 -0
  11. data/lib/twterm/event/notification/error.rb +13 -0
  12. data/lib/twterm/event/notification/info.rb +13 -0
  13. data/lib/twterm/event/notification/success.rb +13 -0
  14. data/lib/twterm/event/notification/warning.rb +13 -0
  15. data/lib/twterm/event_dispatcher.rb +1 -1
  16. data/lib/twterm/extensions/array.rb +5 -0
  17. data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
  18. data/lib/twterm/extensions/string.rb +0 -4
  19. data/lib/twterm/friendship.rb +1 -85
  20. data/lib/twterm/image/between.rb +31 -0
  21. data/lib/twterm/image/blank_line.rb +21 -0
  22. data/lib/twterm/image/bold.rb +31 -0
  23. data/lib/twterm/image/brackets.rb +21 -0
  24. data/lib/twterm/image/color.rb +45 -0
  25. data/lib/twterm/image/empty.rb +21 -0
  26. data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
  27. data/lib/twterm/image/parens.rb +21 -0
  28. data/lib/twterm/image/string_image.rb +38 -0
  29. data/lib/twterm/image/vertical_sequential_image.rb +43 -0
  30. data/lib/twterm/image.rb +107 -0
  31. data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
  32. data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
  33. data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
  34. data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
  35. data/lib/twterm/key_mapper/no_such_command.rb +20 -0
  36. data/lib/twterm/key_mapper/no_such_key.rb +16 -0
  37. data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
  38. data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
  39. data/lib/twterm/key_mapper.rb +127 -0
  40. data/lib/twterm/list.rb +0 -31
  41. data/lib/twterm/notifier.rb +7 -7
  42. data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
  43. data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
  44. data/lib/twterm/repository/abstract_repository.rb +64 -0
  45. data/lib/twterm/repository/direct_message_repository.rb +14 -0
  46. data/lib/twterm/repository/friendship_repository.rb +108 -0
  47. data/lib/twterm/repository/hashtag_repository.rb +39 -0
  48. data/lib/twterm/repository/list_repository.rb +14 -0
  49. data/lib/twterm/repository/status_repository.rb +36 -0
  50. data/lib/twterm/repository/user_repository.rb +22 -0
  51. data/lib/twterm/rest_client.rb +107 -63
  52. data/lib/twterm/screen.rb +21 -15
  53. data/lib/twterm/search_query_window.rb +139 -0
  54. data/lib/twterm/status.rb +14 -108
  55. data/lib/twterm/streaming_client.rb +13 -12
  56. data/lib/twterm/tab/base.rb +48 -8
  57. data/lib/twterm/tab/direct_message/conversation.rb +53 -52
  58. data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
  59. data/lib/twterm/tab/dumpable.rb +3 -3
  60. data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
  61. data/lib/twterm/tab/loadable.rb +20 -0
  62. data/lib/twterm/tab/new/list.rb +32 -43
  63. data/lib/twterm/tab/new/search.rb +31 -44
  64. data/lib/twterm/tab/new/start.rb +44 -55
  65. data/lib/twterm/tab/new/user.rb +15 -12
  66. data/lib/twterm/tab/rate_limit_status.rb +84 -0
  67. data/lib/twterm/tab/scrollable.rb +39 -19
  68. data/lib/twterm/tab/searchable.rb +133 -0
  69. data/lib/twterm/tab/statuses/base.rb +139 -129
  70. data/lib/twterm/tab/statuses/conversation.rb +26 -15
  71. data/lib/twterm/tab/statuses/favorites.rb +10 -8
  72. data/lib/twterm/tab/statuses/home.rb +10 -9
  73. data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
  74. data/lib/twterm/tab/statuses/mentions.rb +17 -11
  75. data/lib/twterm/tab/statuses/search.rb +8 -5
  76. data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
  77. data/lib/twterm/tab/user_list_management.rb +109 -0
  78. data/lib/twterm/tab/user_tab.rb +125 -126
  79. data/lib/twterm/tab/users/base.rb +39 -41
  80. data/lib/twterm/tab/users/followers.rb +9 -6
  81. data/lib/twterm/tab/users/friends.rb +9 -6
  82. data/lib/twterm/tab_manager.rb +64 -40
  83. data/lib/twterm/tweetbox.rb +18 -13
  84. data/lib/twterm/uri_opener.rb +2 -1
  85. data/lib/twterm/user.rb +2 -110
  86. data/lib/twterm/version.rb +1 -1
  87. data/lib/twterm/view.rb +30 -0
  88. data/lib/twterm.rb +3 -9
  89. data/spec/fixtures/status.json +107 -0
  90. data/spec/fixtures/user.json +102 -0
  91. data/spec/spec_helper.rb +7 -0
  92. data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
  93. data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
  94. data/spec/twterm/friendship_spec.rb +0 -102
  95. data/spec/twterm/image/blank_line_spec.rb +11 -0
  96. data/spec/twterm/image/brackets_spec.rb +12 -0
  97. data/spec/twterm/image/color_spec.rb +22 -0
  98. data/spec/twterm/image/empry_spec.rb +11 -0
  99. data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
  100. data/spec/twterm/image/parens_spec.rb +12 -0
  101. data/spec/twterm/image/string_image_spec.rb +12 -0
  102. data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
  103. data/spec/twterm/image_spec.rb +65 -0
  104. data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
  105. data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
  106. data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
  107. data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
  108. data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
  109. data/spec/twterm/status_spec.rb +58 -0
  110. data/spec/twterm/user_spec.rb +94 -0
  111. data/twterm.gemspec +13 -10
  112. metadata +129 -35
  113. data/lib/twterm/event/notification.rb +0 -33
  114. data/lib/twterm/extensions/integer.rb +0 -5
  115. data/lib/twterm/filter_query_window.rb +0 -91
  116. data/lib/twterm/filterable_list.rb +0 -41
  117. data/lib/twterm/history/base.rb +0 -21
  118. data/lib/twterm/history/hashtag.rb +0 -13
  119. data/lib/twterm/history/savable.rb +0 -37
  120. data/lib/twterm/history/screen_name.rb +0 -11
  121. data/lib/twterm/promise.rb +0 -143
@@ -9,15 +9,10 @@ module Twterm
9
9
 
10
10
  attr_reader :status, :from, :to
11
11
 
12
- @@instances = []
13
- @@user_ids = Set.new
14
-
15
12
  def initialize(status, from, to)
16
- fail ArgumentError,
17
- '' unless STATUSES.include? status
13
+ fail ArgumentError, '`status` must be one of the following: :blocking, :follwing, :following_requested, or :muting' unless STATUSES.include? status
18
14
 
19
15
  @status, @from, @to = status, from, to
20
- @@instances << self
21
16
  end
22
17
 
23
18
  def blocking?
@@ -36,85 +31,6 @@ module Twterm
36
31
  status?(:muting)
37
32
  end
38
33
 
39
- def self.already_looked_up?(user_id)
40
- @@user_ids.include?(user_id)
41
- end
42
-
43
- def self.block(from, to)
44
- new(:blocking, from, to)
45
- end
46
-
47
- def self.blocking?(from, to)
48
- !find(:blocking, from, to).nil?
49
- end
50
-
51
- def self.cancel_follow_request(from, to)
52
- new(:following_requested, from, to)
53
- end
54
-
55
- def self.delete(status, from, to)
56
- cond = -> f { f.status == status && f.from == from && f.to == to }
57
- @@instances.delete_if(&cond)
58
- end
59
- private_class_method :delete
60
-
61
- def self.find(status, from, to)
62
- cond = -> f { f.status == status && f.from == from && f.to == to }
63
- @@instances.find(&cond)
64
- end
65
- private_class_method :find
66
-
67
- def self.follow(from, to)
68
- new(:following, from, to)
69
- end
70
-
71
- def self.following?(from, to)
72
- !find(:following, from, to).nil?
73
- end
74
-
75
- def self.following_not_requested(from, to)
76
- delete(:following_requested, from, to)
77
- end
78
-
79
- def self.following_requested(from, to)
80
- new(:following_requested, from, to)
81
- end
82
-
83
- def self.following_requested?(from, to)
84
- !find(:following_requested, from, to).nil?
85
- end
86
-
87
- def self.looked_up!(user_id)
88
- @@user_ids << user_id
89
- user_id
90
- end
91
-
92
- def self.mute(from, to)
93
- new(:muting, from, to)
94
- end
95
-
96
- def self.muting?(from, to)
97
- !find(:muting, from, to).nil?
98
- end
99
-
100
- def self.new(status, from, to)
101
- instance = find(status, from, to)
102
- instance.nil? ? super : instance
103
- end
104
- private_class_method :new
105
-
106
- def self.unblock(from, to)
107
- delete(:blocking, from, to)
108
- end
109
-
110
- def self.unfollow(from, to)
111
- delete(:following, from, to)
112
- end
113
-
114
- def self.unmute(from, to)
115
- delete(:muting, from, to)
116
- end
117
-
118
34
  private
119
35
 
120
36
  def status?(status)
@@ -0,0 +1,31 @@
1
+ class Twterm::Image
2
+ class Between < Twterm::Image
3
+ def initialize(image, open, close)
4
+ @image, @open, @close = image, open, close
5
+ end
6
+
7
+ def height
8
+ 1
9
+ end
10
+
11
+ def render(window)
12
+ open.at(line, column).render(window)
13
+ image.at(line, column + open.width).render(window)
14
+ close.at(line, column + open.width + image.width).render(window)
15
+
16
+ self
17
+ end
18
+
19
+ def to_s
20
+ "#{open}#{image}#{close}"
21
+ end
22
+
23
+ def width
24
+ [open, image, close].map(&:width).reduce(0, :+)
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :open, :close, :image
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ module Twterm
2
+ class Image
3
+ class BlankLine < Twterm::Image
4
+ def height
5
+ 1
6
+ end
7
+
8
+ def render(_)
9
+ self
10
+ end
11
+
12
+ def to_s
13
+ "\n"
14
+ end
15
+
16
+ def width
17
+ 0
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ module Twterm
2
+ class Image
3
+ class Bold < Twterm::Image
4
+ def initialize(image)
5
+ @image = image
6
+ end
7
+
8
+ def height
9
+ image.height
10
+ end
11
+
12
+ def render(window)
13
+ window.attron(Curses::A_BOLD)
14
+ image.at(line, column).render(window)
15
+ window.attroff(Curses::A_BOLD)
16
+ end
17
+
18
+ def to_s
19
+ "\e[1m#{image}\e[0m"
20
+ end
21
+
22
+ def width
23
+ image.width
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :image
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ require 'twterm/image/between'
2
+
3
+ module Twterm
4
+ class Image
5
+ class Brackets < Twterm::Image::Between
6
+ def initialize(image)
7
+ super(image, open, close)
8
+ end
9
+
10
+ private
11
+
12
+ def open
13
+ StringImage.new('[')
14
+ end
15
+
16
+ def close
17
+ StringImage.new(']')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ module Twterm
2
+ class Image
3
+ class Color < Twterm::Image
4
+ def initialize(image, fg, bg = :transparent)
5
+ @image, @fg, @bg = image, fg, bg
6
+ end
7
+
8
+ def height
9
+ image.height
10
+ end
11
+
12
+ def render(window)
13
+ window.attron(Curses.color_pair(color_pair_index))
14
+ image.at(line, column).render(window)
15
+ window.attroff(Curses.color_pair(color_pair_index))
16
+ end
17
+
18
+ def to_s
19
+ fg_colors = {
20
+ black: 30, red: 31, green: 32, yellow: 33,
21
+ blue: 34, magenta: 35, cyan: 36, white: 37
22
+ }
23
+ bg_colors = {
24
+ black: 40, red: 41, green: 42, yellow: 43,
25
+ blur: 44, magenta: 45, cyan: 46, white: 47
26
+ }
27
+
28
+ str = "\e[#{fg_colors[@fg]}m#{image}\e[0m"
29
+ @bg == :transparent ? str : "\e[#{bg_colors[@bg]}m#{str}"
30
+ end
31
+
32
+ def width
33
+ image.width
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :image
39
+
40
+ def color_pair_index
41
+ Twterm::ColorManager.instance.get_color_pair_index(@fg, @bg)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,21 @@
1
+ module Twterm
2
+ class Image
3
+ class Empty < Twterm::Image
4
+ def height
5
+ 0
6
+ end
7
+
8
+ def render(_)
9
+ self
10
+ end
11
+
12
+ def to_s
13
+ ''
14
+ end
15
+
16
+ def width
17
+ 0
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,48 @@
1
+ module Twterm
2
+ class Image
3
+ class HorizontalSequentialImage < Twterm::Image
4
+ def initialize(images)
5
+ @images = images
6
+ end
7
+
8
+ def -(other)
9
+ append(other)
10
+ end
11
+
12
+ def append(image)
13
+ if image.is_a?(self.class)
14
+ @images += image.images
15
+ else
16
+ images << image
17
+ end
18
+
19
+ self
20
+ end
21
+
22
+ def height
23
+ images.map(&:height).max
24
+ end
25
+
26
+ def render(window)
27
+ window.setpos(line, column)
28
+ images
29
+ .zip(images.lazy.map(&:width).scan(column, :+))
30
+ .each { |r, c| r.at(line, c).render(window) }
31
+
32
+ self
33
+ end
34
+
35
+ def to_s
36
+ images.map(&:to_s).join
37
+ end
38
+
39
+ def width
40
+ images.map(&:width).reduce(0, :+)
41
+ end
42
+
43
+ protected
44
+
45
+ attr_reader :images
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ require 'twterm/image/between'
2
+
3
+ module Twterm
4
+ class Image
5
+ class Parens < Twterm::Image::Between
6
+ def initialize(image)
7
+ super(image, open, close)
8
+ end
9
+
10
+ private
11
+
12
+ def open
13
+ StringImage.new('(')
14
+ end
15
+
16
+ def close
17
+ StringImage.new(')')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ module Twterm
2
+ class Image
3
+ class StringImage < Twterm::Image
4
+ def initialize(string)
5
+ @string = string
6
+ end
7
+
8
+ def -(other)
9
+ if other.is_a?(self.class)
10
+ self.class.new(string + other.string)
11
+ else
12
+ super
13
+ end
14
+ end
15
+
16
+ def height
17
+ 1
18
+ end
19
+
20
+ def render(window)
21
+ window.setpos(line, column)
22
+ window.addstr(string)
23
+ end
24
+
25
+ def to_s
26
+ @string.dup
27
+ end
28
+
29
+ def width
30
+ string.width
31
+ end
32
+
33
+ protected
34
+
35
+ attr_reader :string
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,43 @@
1
+ module Twterm
2
+ class Image
3
+ class VerticalSequentialImage < Twterm::Image
4
+ def initialize(images)
5
+ @images = images
6
+ end
7
+
8
+ def |(other)
9
+ append(other)
10
+ end
11
+
12
+ def append(image)
13
+ images << image
14
+ self
15
+ end
16
+
17
+ def height
18
+ images.map(&:height).reduce(0, :+)
19
+ end
20
+
21
+ def render(window)
22
+ window.setpos(line, column)
23
+ images
24
+ .zip(images.lazy.map(&:height).scan(line, :+))
25
+ .each { |r, l| r.at(l, column).render(window) }
26
+
27
+ self
28
+ end
29
+
30
+ def to_s
31
+ images.map(&:to_s).join("\n")
32
+ end
33
+
34
+ def width
35
+ images.map(&:width).max
36
+ end
37
+
38
+ protected
39
+
40
+ attr_reader :images
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,107 @@
1
+ require 'twterm/image/between'
2
+ require 'twterm/image/blank_line'
3
+ require 'twterm/image/bold'
4
+ require 'twterm/image/brackets'
5
+ require 'twterm/image/color'
6
+ require 'twterm/image/empty'
7
+ require 'twterm/image/horizontal_sequential_image'
8
+ require 'twterm/image/parens'
9
+ require 'twterm/image/string_image'
10
+ require 'twterm/image/vertical_sequential_image'
11
+
12
+ class Twterm::Image
13
+ def initialize(column: 0, line: 0)
14
+ @column, @line = column, line
15
+ end
16
+
17
+ def !
18
+ bold
19
+ end
20
+
21
+ def |(other)
22
+ VerticalSequentialImage.new([self, other])
23
+ end
24
+
25
+ def -(other)
26
+ HorizontalSequentialImage.new([self, other])
27
+ end
28
+
29
+ def at(line, column)
30
+ @line, @column = line, column
31
+
32
+ self
33
+ end
34
+
35
+ def self.blank_line
36
+ BlankLine.new
37
+ end
38
+
39
+ def bold
40
+ Bold.new(self)
41
+ end
42
+
43
+ def brackets
44
+ Brackets.new(self)
45
+ end
46
+
47
+ def self.checkbox(checked)
48
+ string(checked ? 'x' : ' ').brackets
49
+ end
50
+
51
+ def color(fg, bg = :transparent)
52
+ Color.new(self, fg, bg)
53
+ end
54
+
55
+ def column
56
+ @column || 0
57
+ end
58
+
59
+ def self.cursor(height, current)
60
+ color = current ? [:black, :magenta] : [:black]
61
+ VerticalSequentialImage.new([whitespace] * height).color(*color)
62
+ end
63
+
64
+ def self.empty
65
+ Empty.new
66
+ end
67
+
68
+ def self.remaining_resource(remaining, total, length)
69
+ ratio = remaining * 100 / total
70
+ color =
71
+ if ratio >= 40
72
+ :green
73
+ elsif ratio >= 20
74
+ :yellow
75
+ else
76
+ :red
77
+ end
78
+
79
+ bars = string(('|' * (remaining * length / total)).ljust(length)).color(color)
80
+
81
+ Between.new(bars, !string('['), !string(']'))
82
+ end
83
+
84
+ def line
85
+ @line || 0
86
+ end
87
+
88
+ def self.number(n)
89
+ string(n.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\1,'))
90
+ end
91
+
92
+ def parens
93
+ Parens.new(self)
94
+ end
95
+
96
+ def self.plural(n, singular, plural = "#{singular}s")
97
+ string(n == 1 ? singular : plural)
98
+ end
99
+
100
+ def self.string(str)
101
+ StringImage.new(str)
102
+ end
103
+
104
+ def self.whitespace
105
+ string(' ')
106
+ end
107
+ end
@@ -0,0 +1,51 @@
1
+ require 'curses'
2
+ require 'twterm/key_mapper/no_such_command'
3
+ require 'twterm/key_mapper/no_such_key'
4
+
5
+ module Twterm
6
+ class KeyMapper
7
+ class AbstractKeyMapper
8
+ def initialize(mappings)
9
+ commands = self.class.commands
10
+
11
+ mappings.keys.each do |k|
12
+ raise NoSuchCommand.new(self.class.category, k) unless commands.include?(k)
13
+ end
14
+
15
+ @mappings = Hash[mappings.map { |k, v| [k, translate(v)] }]
16
+ end
17
+
18
+ def [](key)
19
+ raise NoSuchCommand.new(self.class.category, key) unless @mappings.keys.include?(key)
20
+ @mappings[key]
21
+ end
22
+
23
+ private
24
+
25
+ def translate(key)
26
+ case key
27
+ when '!'..'}' then key
28
+ when /\A\^([A-Z]?)\Z/ then $1.ord - 'A'.ord + 1
29
+ when 'F1' then Curses::Key::F1
30
+ when 'F2' then Curses::Key::F2
31
+ when 'F3' then Curses::Key::F3
32
+ when 'F4' then Curses::Key::F4
33
+ when 'F5' then Curses::Key::F5
34
+ when 'F6' then Curses::Key::F6
35
+ when 'F7' then Curses::Key::F7
36
+ when 'F8' then Curses::Key::F8
37
+ when 'F9' then Curses::Key::F9
38
+ when 'F10' then Curses::Key::F10
39
+ when 'F11' then Curses::Key::F11
40
+ when 'F12' then Curses::Key::F12
41
+ else
42
+ raise NoSuchKey.new(key)
43
+ end
44
+ end
45
+
46
+ def self.commands
47
+ self::DEFAULT_MAPPINGS.keys
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/key_mapper/abstract_key_mapper'
2
+
3
+ class Twterm::KeyMapper::AppKeyMapper < Twterm::KeyMapper::AbstractKeyMapper
4
+ DEFAULT_MAPPINGS = {
5
+ cheatsheet: 'F1',
6
+ me: 'm',
7
+ quit: 'F10',
8
+ }.freeze
9
+
10
+ def self.category
11
+ 'app'.freeze
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'twterm/key_mapper/abstract_key_mapper'
2
+
3
+ class Twterm::KeyMapper::CursorKeyMapper < Twterm::KeyMapper::AbstractKeyMapper
4
+ DEFAULT_MAPPINGS = {
5
+ bottom_of_window: 'L',
6
+ middle_of_window: 'M',
7
+ top_of_window: 'H',
8
+ }.freeze
9
+
10
+ def self.category
11
+ 'cursor'.freeze
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require 'twterm/key_mapper/abstract_key_mapper'
2
+
3
+ class Twterm::KeyMapper::GeneralKeyMapper < Twterm::KeyMapper::AbstractKeyMapper
4
+ DEFAULT_MAPPINGS = {
5
+ bottom: 'G',
6
+ down: 'j',
7
+ left: 'h',
8
+ page_down: 'd',
9
+ page_up: 'u',
10
+ right: 'l',
11
+ top: 'g',
12
+ up: 'k',
13
+ }.freeze
14
+
15
+ def self.category
16
+ 'general'.freeze
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ module Twterm
2
+ class KeyMapper
3
+ class NoSuchCommand < StandardError
4
+ attr_reader :category, :command
5
+
6
+ def initialize(category, command)
7
+ @category, @command = category, command
8
+ super(message)
9
+ end
10
+
11
+ def full_command
12
+ "#{category}.#{command}"
13
+ end
14
+
15
+ def message
16
+ "No such command: #{full_command}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module Twterm
2
+ class KeyMapper
3
+ class NoSuchKey < StandardError
4
+ attr_reader :key
5
+
6
+ def initialize(key)
7
+ @key = key
8
+ super(message)
9
+ end
10
+
11
+ def message
12
+ "No such key: #{key}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ require 'twterm/key_mapper/abstract_key_mapper'
2
+
3
+ class Twterm::KeyMapper::StatusKeyMapper < Twterm::KeyMapper::AbstractKeyMapper
4
+ DEFAULT_MAPPINGS = {
5
+ compose: '^N',
6
+ conversation: 'c',
7
+ destroy: 'D',
8
+ like: 'L',
9
+ open_link: 'o',
10
+ reply: 'r',
11
+ retweet: 'R',
12
+ user: 'U',
13
+ }.freeze
14
+
15
+ def self.category
16
+ 'status'.freeze
17
+ end
18
+ end