twterm 2.7.0 → 2.10.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +62 -0
  3. data/.gitattributes +4 -0
  4. data/.gitignore +1 -0
  5. data/Gemfile +7 -0
  6. data/Makefile +21 -0
  7. data/README.md +52 -6
  8. data/bin/twterm +1 -3
  9. data/default.nix +21 -0
  10. data/gemset.nix +5130 -0
  11. data/lib/twterm/app.rb +13 -8
  12. data/lib/twterm/color_manager.rb +8 -9
  13. data/lib/twterm/image.rb +31 -0
  14. data/lib/twterm/image/attr.rb +42 -0
  15. data/lib/twterm/image/bold.rb +7 -21
  16. data/lib/twterm/image/color.rb +9 -15
  17. data/lib/twterm/image/dim.rb +13 -0
  18. data/lib/twterm/image/underlined.rb +17 -0
  19. data/lib/twterm/image_builder/user_name_image_builder.rb +1 -0
  20. data/lib/twterm/key_mapper.rb +6 -8
  21. data/lib/twterm/key_mapper/abstract_key_mapper.rb +2 -2
  22. data/lib/twterm/list.rb +36 -1
  23. data/lib/twterm/message_window.rb +4 -13
  24. data/lib/twterm/persistable_configuration_proxy.rb +6 -6
  25. data/lib/twterm/preferences.rb +8 -1
  26. data/lib/twterm/screen.rb +103 -25
  27. data/lib/twterm/search_query_window.rb +5 -13
  28. data/lib/twterm/status.rb +10 -0
  29. data/lib/twterm/tab/abstract_tab.rb +30 -16
  30. data/lib/twterm/tab/new/search.rb +2 -2
  31. data/lib/twterm/tab/new/user.rb +2 -2
  32. data/lib/twterm/tab/preferences/control.rb +77 -0
  33. data/lib/twterm/tab/preferences/index.rb +6 -0
  34. data/lib/twterm/tab/scrollable.rb +1 -1
  35. data/lib/twterm/tab/searchable.rb +6 -4
  36. data/lib/twterm/tab/status_tab.rb +10 -0
  37. data/lib/twterm/tab/statuses/abstract_statuses_tab.rb +11 -6
  38. data/lib/twterm/tab_manager.rb +77 -10
  39. data/lib/twterm/tweetbox.rb +2 -3
  40. data/lib/twterm/user.rb +1 -0
  41. data/lib/twterm/version.rb +1 -1
  42. data/nix/Gemfile +3 -0
  43. data/nix/Gemfile.lock +77 -0
  44. data/nix/gemset.nix +325 -0
  45. data/shell.nix +40 -0
  46. data/spec/twterm/image/bold_spec.rb +30 -0
  47. data/spec/twterm/image/color_spec.rb +16 -0
  48. data/spec/twterm/image/dim_spec.rb +30 -0
  49. data/twterm.gemspec +7 -14
  50. metadata +35 -108
  51. data/.travis.yml +0 -12
  52. data/lib/twterm/event/screen/resize.rb +0 -13
  53. data/spec/twterm/event/screen/resize_spec.rb +0 -11
data/lib/twterm/app.rb CHANGED
@@ -3,7 +3,6 @@ require 'curses'
3
3
  require 'twterm/completion_manager'
4
4
  require 'twterm/environment'
5
5
  require 'twterm/event/screen/refresh'
6
- require 'twterm/event/screen/resize'
7
6
  require 'twterm/message_window'
8
7
  require 'twterm/notification_dispatcher'
9
8
  require 'twterm/persistable_configuration_proxy'
@@ -24,6 +23,12 @@ module Twterm
24
23
 
25
24
  attr_reader :environment, :preferences, :screen
26
25
 
26
+ # return [Twterm::MessageWindow]
27
+ attr_reader :message_window
28
+
29
+ # return [Twterm::SearchQueryWindow]
30
+ attr_reader :search_query_window
31
+
27
32
  DATA_DIR = "#{ENV['HOME']}/.twterm".freeze
28
33
 
29
34
  def initialize
@@ -63,8 +68,8 @@ module Twterm
63
68
 
64
69
  @screen = Screen.new(self, client)
65
70
 
66
- SearchQueryWindow.instance
67
- MessageWindow.instance
71
+ @search_query_window = SearchQueryWindow.new(screen.search_query_window_window)
72
+ @message_window = MessageWindow.new(screen.message_window_window)
68
73
 
69
74
  @notification_dispatcher = NotificationDispatcher.new(preferences)
70
75
  @photo_viewer = PhotoViewer.new(preferences)
@@ -143,7 +148,7 @@ module Twterm
143
148
  end
144
149
 
145
150
  def tab_manager
146
- @tab_manager ||= TabManager.new(self, client)
151
+ @tab_manager ||= TabManager.new(self, client, screen.tab_manager_window)
147
152
  end
148
153
 
149
154
  def tweetbox
@@ -177,11 +182,11 @@ module Twterm
177
182
  end
178
183
 
179
184
  def on_resize
180
- return if Curses.closed?
185
+ lines, cols = `stty size`.split(' ').map(&:to_i)
186
+
187
+ Readline.set_screen_size(lines, cols)
181
188
 
182
- lines = `tput lines`.to_i
183
- cols = `tput cols`.to_i
184
- publish(Event::Screen::Resize.new(lines, cols))
189
+ screen.resize(lines, cols) unless Curses.closed?
185
190
  end
186
191
  end
187
192
  end
@@ -1,18 +1,17 @@
1
1
  module Twterm
2
2
  class ColorManager
3
3
  include Singleton
4
- include Curses
5
4
 
6
5
  COLORS = [:black, :white, :red, :green, :blue, :yellow, :cyan, :magenta, :transparent]
7
6
  CURSES_COLORS = {
8
- black: COLOR_BLACK,
9
- white: COLOR_WHITE,
10
- red: COLOR_RED,
11
- green: COLOR_GREEN,
12
- blue: COLOR_BLUE,
13
- yellow: COLOR_YELLOW,
14
- cyan: COLOR_CYAN,
15
- magenta: COLOR_MAGENTA,
7
+ black: Curses::COLOR_BLACK,
8
+ white: Curses::COLOR_WHITE,
9
+ red: Curses::COLOR_RED,
10
+ green: Curses::COLOR_GREEN,
11
+ blue: Curses::COLOR_BLUE,
12
+ yellow: Curses::COLOR_YELLOW,
13
+ cyan: Curses::COLOR_CYAN,
14
+ magenta: Curses::COLOR_MAGENTA,
16
15
  transparent: -1
17
16
  }
18
17
 
data/lib/twterm/image.rb CHANGED
@@ -3,10 +3,12 @@ require 'twterm/image/blank_line'
3
3
  require 'twterm/image/bold'
4
4
  require 'twterm/image/brackets'
5
5
  require 'twterm/image/color'
6
+ require 'twterm/image/dim'
6
7
  require 'twterm/image/empty'
7
8
  require 'twterm/image/horizontal_sequential_image'
8
9
  require 'twterm/image/parens'
9
10
  require 'twterm/image/string_image'
11
+ require 'twterm/image/underlined'
10
12
  require 'twterm/image/vertical_sequential_image'
11
13
 
12
14
  class Twterm::Image
@@ -14,6 +16,10 @@ class Twterm::Image
14
16
  @column, @line = column, line
15
17
  end
16
18
 
19
+ def _
20
+ underlined
21
+ end
22
+
17
23
  def !
18
24
  bold
19
25
  end
@@ -44,6 +50,10 @@ class Twterm::Image
44
50
  Brackets.new(self)
45
51
  end
46
52
 
53
+ def dim(on = true)
54
+ on ? Dim.new(self) : self
55
+ end
56
+
47
57
  def self.checkbox(checked)
48
58
  string(checked ? '*' : ' ').brackets
49
59
  end
@@ -101,6 +111,27 @@ class Twterm::Image
101
111
  StringImage.new(str)
102
112
  end
103
113
 
114
+ # @param items [Array<Symbol>]
115
+ # @param selected [Symbol]
116
+ #
117
+ # @return [Image]
118
+ def self.toggle_switch(items, selected)
119
+ items
120
+ .map do |item|
121
+ on = item == selected
122
+ string(item.to_s)
123
+ .bold(on)
124
+ .underlined(on)
125
+ end
126
+ .intersperse(string(' | '))
127
+ .reduce(empty) { |acc, x| acc - x }
128
+ .brackets
129
+ end
130
+
131
+ def underlined(on = true)
132
+ on ? Underlined.new(self) : self
133
+ end
134
+
104
135
  def self.whitespace
105
136
  string(' ')
106
137
  end
@@ -0,0 +1,42 @@
1
+ require 'twterm/image'
2
+
3
+ class Twterm::Image::Attr < Twterm::Image
4
+ # @param image [Twterm::Image]
5
+ def initialize(image)
6
+ super()
7
+
8
+ @image = image
9
+ end
10
+
11
+ def height
12
+ image.height
13
+ end
14
+
15
+ def render(window)
16
+ image, attr =
17
+ if image.is_a?(self.class) # fuse attributes when possible
18
+ [image.image, self.attr | image.attr]
19
+ else
20
+ [self.image, self.attr]
21
+ end
22
+
23
+ window.attron(attr)
24
+ image.at(line, column).render(window)
25
+ window.attroff(attr)
26
+ end
27
+
28
+ def width
29
+ image.width
30
+ end
31
+
32
+ protected
33
+
34
+ attr_reader :image
35
+
36
+ # @abstract
37
+ #
38
+ # @return [Integer]
39
+ def attr
40
+ raise NotImplementedError, '`attr` must be implemented'
41
+ end
42
+ end
@@ -1,31 +1,17 @@
1
+ require 'twterm/image/attr'
2
+
1
3
  module Twterm
2
4
  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
-
5
+ class Bold < Twterm::Image::Attr
18
6
  def to_s
19
7
  "\e[1m#{image}\e[0m"
20
8
  end
21
9
 
22
- def width
23
- image.width
24
- end
10
+ protected
25
11
 
26
- private
27
-
28
- attr_reader :image
12
+ def attr
13
+ Curses::A_BOLD
14
+ end
29
15
  end
30
16
  end
31
17
  end
@@ -1,18 +1,12 @@
1
+ require 'twterm/image/attr'
2
+
1
3
  module Twterm
2
4
  class Image
3
- class Color < Twterm::Image
5
+ class Color < Twterm::Image::Attr
4
6
  def initialize(image, fg, bg = :transparent)
5
- @image, @fg, @bg = image, fg, bg
6
- end
7
-
8
- def height
9
- image.height
10
- end
7
+ super(image)
11
8
 
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))
9
+ @fg, @bg = fg, bg
16
10
  end
17
11
 
18
12
  def to_s
@@ -29,14 +23,14 @@ module Twterm
29
23
  @bg == :transparent ? str : "\e[#{bg_colors[@bg]}m#{str}"
30
24
  end
31
25
 
32
- def width
33
- image.width
26
+ protected
27
+
28
+ def attr
29
+ Curses.color_pair(color_pair_index)
34
30
  end
35
31
 
36
32
  private
37
33
 
38
- attr_reader :image
39
-
40
34
  def color_pair_index
41
35
  Twterm::ColorManager.instance.get_color_pair_index(@fg, @bg)
42
36
  end
@@ -0,0 +1,13 @@
1
+ require 'twterm/image/attr'
2
+
3
+ class Twterm::Image::Dim < Twterm::Image::Attr
4
+ def to_s
5
+ "\e[2m#{image}\e[0m"
6
+ end
7
+
8
+ protected
9
+
10
+ def attr
11
+ Curses::A_DIM
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'twterm/image/attr'
2
+
3
+ module Twterm
4
+ class Image
5
+ class Underlined < Twterm::Image::Attr
6
+ def to_s
7
+ "\e[4m#{image}\e[0m"
8
+ end
9
+
10
+ protected
11
+
12
+ def attr
13
+ Curses::A_UNDERLINE
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,6 +1,7 @@
1
1
  require 'twterm/image'
2
2
 
3
3
  module Twterm
4
+ # @todo Rename to `Presenter`
4
5
  module ImageBuilder
5
6
  class UserNameImageBuilder
6
7
  COLORS = [:red, :blue, :green, :cyan, :yellow, :magenta].freeze
@@ -1,4 +1,4 @@
1
- require 'toml'
1
+ require 'toml-rb'
2
2
  require 'singleton'
3
3
 
4
4
  require 'twterm/app'
@@ -105,14 +105,12 @@ module Twterm
105
105
  end
106
106
 
107
107
  def load_dict_file!
108
- dict = TOML.load_file(dict_file_path, symbolize_keys: true)
109
- rescue TOML::ParseError, TOML::ValueOverwriteError => e
108
+ dict = TomlRB.load_file(dict_file_path, symbolize_keys: true)
109
+ rescue TomlRB::ParseError => e
110
110
  first_line =
111
111
  case e
112
- when TOML::ParseError
113
- "Your key assignments dictionary file (#{dict_file_path}) could not be parsed"
114
- when TOML::ValueOverwriteError
115
- "Command `#{e.key}` is declared more than once"
112
+ when TomlRB::ParseError
113
+ "Your key assignments dictionary file (#{dict_file_path}) could not be parsed:\n#{e.message}"
116
114
  end
117
115
 
118
116
  warn <<-EOS
@@ -132,7 +130,7 @@ Press any key to continue
132
130
  end
133
131
 
134
132
  def save!(mappings)
135
- dict = TOML.dump(mappings).gsub("\n[", "\n\n[")
133
+ dict = TomlRB.dump(mappings).gsub("\n[", "\n\n[")
136
134
  File.open(dict_file_path, 'w', 0644) { |f| f.write(dict) }
137
135
  end
138
136
  end
@@ -35,8 +35,6 @@ module Twterm
35
35
 
36
36
  def translate(key)
37
37
  case key
38
- when '!'..'}' then key
39
- when /\A\^([A-Z]?)\Z/ then $1.ord - 'A'.ord + 1
40
38
  when 'F1' then Curses::Key::F1
41
39
  when 'F2' then Curses::Key::F2
42
40
  when 'F3' then Curses::Key::F3
@@ -49,6 +47,8 @@ module Twterm
49
47
  when 'F10' then Curses::Key::F10
50
48
  when 'F11' then Curses::Key::F11
51
49
  when 'F12' then Curses::Key::F12
50
+ when /\A\^([A-Z]?)\Z/ then $1.ord - 'A'.ord + 1
51
+ when '!'..'}' then key
52
52
  else
53
53
  raise NoSuchKey.new(key)
54
54
  end
data/lib/twterm/list.rb CHANGED
@@ -1,7 +1,41 @@
1
1
  module Twterm
2
+ # A Twitter list
2
3
  class List
3
- attr_reader :id, :name, :slug, :full_name, :mode, :description, :member_count, :subscriber_count, :url
4
+ # Unique ID of the list
5
+ #
6
+ # @return [Integer]
7
+ attr_reader :id
4
8
 
9
+ # @return [String]
10
+ attr_reader :name
11
+
12
+ # @return [String]
13
+ attr_reader :slug
14
+
15
+ # @return [String]
16
+ attr_reader :full_name
17
+
18
+ attr_reader :mode
19
+
20
+ # @return [String]
21
+ attr_reader :description
22
+
23
+ # The number of users that are in this list
24
+ #
25
+ # @return [Integer]
26
+ attr_reader :member_count
27
+
28
+ # The number of users that subscribe this list
29
+ #
30
+ # @return [Integer]
31
+ attr_reader :subscriber_count
32
+
33
+ # @return [String]
34
+ attr_reader :url
35
+
36
+ # @param other [List]
37
+ #
38
+ # @return [Boolean]
5
39
  def ==(other)
6
40
  other.is_a?(self.class) && id == other.id
7
41
  end
@@ -11,6 +45,7 @@ module Twterm
11
45
  update!(list)
12
46
  end
13
47
 
48
+ # @return [self]
14
49
  def update!(list)
15
50
  @name = list.name
16
51
  @slug = list.slug
@@ -1,23 +1,19 @@
1
1
  require 'twterm/subscriber'
2
2
  require 'twterm/event/message/abstract_message'
3
- require 'twterm/event/screen/resize'
4
3
 
5
4
  module Twterm
6
5
  class MessageWindow
7
- include Singleton
8
- include Curses
9
6
  include Subscriber
10
7
 
11
- def initialize
12
- @window = stdscr.subwin(1, stdscr.maxx, stdscr.maxy - 2, 0)
8
+ # @param window [Curses::Window]
9
+ def initialize(window)
10
+ @window = window
13
11
  @queue = Queue.new
14
12
 
15
13
  subscribe(Event::Message::AbstractMessage) do |e|
16
14
  queue(e)
17
15
  end
18
16
 
19
- subscribe(Event::Screen::Resize, :resize)
20
-
21
17
  Thread.new do
22
18
  while message = @queue.pop # rubocop:disable Lint/AssignmentInCondition:
23
19
  show(message)
@@ -34,7 +30,7 @@ module Twterm
34
30
 
35
31
  def show(message = nil)
36
32
  loop do
37
- break unless closed?
33
+ break unless Curses.closed?
38
34
  sleep 0.5
39
35
  end
40
36
 
@@ -72,10 +68,5 @@ module Twterm
72
68
  @queue.push(message)
73
69
  self
74
70
  end
75
-
76
- def resize(_event)
77
- @window.resize(1, stdscr.maxx)
78
- @window.move(stdscr.maxy - 2, 0)
79
- end
80
71
  end
81
72
  end