twterm 2.5.0 → 2.9.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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +62 -0
  3. data/.gitignore +1 -0
  4. data/Makefile +18 -0
  5. data/README.md +30 -4
  6. data/bin/twterm +1 -3
  7. data/default.nix +21 -0
  8. data/gemset.nix +5130 -0
  9. data/lib/twterm/app.rb +0 -18
  10. data/lib/twterm/client.rb +1 -6
  11. data/lib/twterm/color_manager.rb +8 -9
  12. data/lib/twterm/image.rb +26 -0
  13. data/lib/twterm/image/underlined.rb +31 -0
  14. data/lib/twterm/image_builder/user_name_image_builder.rb +1 -0
  15. data/lib/twterm/key_mapper.rb +6 -8
  16. data/lib/twterm/key_mapper/abstract_key_mapper.rb +2 -2
  17. data/lib/twterm/list.rb +36 -1
  18. data/lib/twterm/message_window.rb +4 -5
  19. data/lib/twterm/persistable_configuration_proxy.rb +6 -6
  20. data/lib/twterm/preferences.rb +8 -1
  21. data/lib/twterm/rest_client.rb +0 -33
  22. data/lib/twterm/screen.rb +54 -14
  23. data/lib/twterm/search_query_window.rb +4 -5
  24. data/lib/twterm/status.rb +10 -0
  25. data/lib/twterm/tab/abstract_tab.rb +33 -8
  26. data/lib/twterm/tab/new/index.rb +0 -10
  27. data/lib/twterm/tab/new/list.rb +3 -3
  28. data/lib/twterm/tab/new/search.rb +2 -2
  29. data/lib/twterm/tab/new/user.rb +2 -2
  30. data/lib/twterm/tab/preferences/control.rb +77 -0
  31. data/lib/twterm/tab/preferences/index.rb +6 -0
  32. data/lib/twterm/tab/status_tab.rb +10 -0
  33. data/lib/twterm/tab/statuses/abstract_statuses_tab.rb +4 -4
  34. data/lib/twterm/tab/statuses/home.rb +0 -3
  35. data/lib/twterm/tab/statuses/mentions.rb +1 -0
  36. data/lib/twterm/tab/user_tab.rb +0 -9
  37. data/lib/twterm/tab_manager.rb +77 -5
  38. data/lib/twterm/tweetbox.rb +2 -3
  39. data/lib/twterm/user.rb +1 -0
  40. data/lib/twterm/version.rb +1 -1
  41. data/nix/Gemfile +3 -0
  42. data/nix/Gemfile.lock +70 -0
  43. data/nix/gemset.nix +283 -0
  44. data/shell.nix +40 -0
  45. data/twterm.gemspec +13 -13
  46. metadata +42 -44
  47. data/.travis.yml +0 -12
  48. data/lib/twterm/direct_message.rb +0 -60
  49. data/lib/twterm/direct_message_composer.rb +0 -80
  50. data/lib/twterm/direct_message_manager.rb +0 -51
  51. data/lib/twterm/event/direct_message/fetched.rb +0 -10
  52. data/lib/twterm/event/notification/direct_message.rb +0 -30
  53. data/lib/twterm/event/status/timeline.rb +0 -10
  54. data/lib/twterm/repository/direct_message_repository.rb +0 -14
  55. data/lib/twterm/streaming_client.rb +0 -146
  56. data/lib/twterm/tab/direct_message/conversation.rb +0 -104
  57. data/lib/twterm/tab/direct_message/conversation_list.rb +0 -100
data/lib/twterm/app.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'curses'
2
2
 
3
3
  require 'twterm/completion_manager'
4
- require 'twterm/direct_message_composer'
5
4
  require 'twterm/environment'
6
5
  require 'twterm/event/screen/refresh'
7
6
  require 'twterm/event/screen/resize'
@@ -10,7 +9,6 @@ require 'twterm/notification_dispatcher'
10
9
  require 'twterm/persistable_configuration_proxy'
11
10
  require 'twterm/preferences'
12
11
  require 'twterm/photo_viewer'
13
- require 'twterm/repository/direct_message_repository'
14
12
  require 'twterm/repository/friendship_repository'
15
13
  require 'twterm/repository/hashtag_repository'
16
14
  require 'twterm/repository/list_repository'
@@ -42,14 +40,6 @@ module Twterm
42
40
  @completion_manager ||= CompletionManager.new(self)
43
41
  end
44
42
 
45
- def direct_message_composer
46
- @direct_message_composer ||= DirectMessageComposer.new(self, client)
47
- end
48
-
49
- def direct_message_repository
50
- @direct_messages_repository ||= Repository::DirectMessageRepository.new
51
- end
52
-
53
43
  def friendship_repository
54
44
  @friendship_repository ||= Repository::FriendshipRepository.new
55
45
  end
@@ -89,8 +79,6 @@ module Twterm
89
79
 
90
80
  publish(Event::Screen::Refresh.new)
91
81
 
92
- client.connect_user_stream
93
-
94
82
  reset_interruption_handler
95
83
 
96
84
  Signal.trap(:WINCH) { on_resize }
@@ -105,11 +93,6 @@ module Twterm
105
93
  user_repository.expire(3600)
106
94
  end
107
95
 
108
- direct_message_repository.before_create do |dm|
109
- user_repository.create(dm.recipient)
110
- user_repository.create(dm.sender)
111
- end
112
-
113
96
  user_repository.before_create do |user|
114
97
  client_id = client.user_id
115
98
 
@@ -181,7 +164,6 @@ module Twterm
181
164
  config[:access_token_secret],
182
165
  {
183
166
  friendship: friendship_repository,
184
- direct_message: direct_message_repository,
185
167
  hashtag: hashtag_repository,
186
168
  list: list_repository,
187
169
  status: status_repository,
data/lib/twterm/client.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  require 'twterm/rest_client'
2
- require 'twterm/streaming_client'
3
2
 
4
3
  module Twterm
5
4
  class Client
6
5
  include RESTClient
7
- include StreamingClient
8
6
 
9
7
  attr_reader :user_id, :screen_name
10
8
 
@@ -13,7 +11,6 @@ module Twterm
13
11
  @access_token, @access_token_secret = access_token, access_token_secret
14
12
 
15
13
  @friendship_repository = repositories[:friendship]
16
- @direct_message_repository = repositories[:direct_message]
17
14
  @hashtag_repository = repositories[:hashtag]
18
15
  @list_repository = repositories[:list]
19
16
  @status_repository = repositories[:status]
@@ -29,12 +26,10 @@ module Twterm
29
26
  muted_user_ids.include?(status.retweeted_status.user.id))
30
27
  end
31
28
  end
32
-
33
- direct_message_manager
34
29
  end
35
30
 
36
31
  private
37
32
 
38
- attr_reader :friendship_repository, :direct_message_repository, :hashtag_repository, :list_repository, :status_repository, :user_repository
33
+ attr_reader :friendship_repository, :hashtag_repository, :list_repository, :status_repository, :user_repository
39
34
  end
40
35
  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
@@ -7,6 +7,7 @@ require 'twterm/image/empty'
7
7
  require 'twterm/image/horizontal_sequential_image'
8
8
  require 'twterm/image/parens'
9
9
  require 'twterm/image/string_image'
10
+ require 'twterm/image/underlined'
10
11
  require 'twterm/image/vertical_sequential_image'
11
12
 
12
13
  class Twterm::Image
@@ -14,6 +15,10 @@ class Twterm::Image
14
15
  @column, @line = column, line
15
16
  end
16
17
 
18
+ def _
19
+ underlined
20
+ end
21
+
17
22
  def !
18
23
  bold
19
24
  end
@@ -101,6 +106,27 @@ class Twterm::Image
101
106
  StringImage.new(str)
102
107
  end
103
108
 
109
+ # @param items [Array<Symbol>]
110
+ # @param selected [Symbol]
111
+ #
112
+ # @return [Image]
113
+ def self.toggle_switch(items, selected)
114
+ items
115
+ .map do |item|
116
+ on = item == selected
117
+ string(item.to_s)
118
+ .bold(on)
119
+ .underlined(on)
120
+ end
121
+ .intersperse(string(' | '))
122
+ .reduce(empty) { |acc, x| acc - x }
123
+ .brackets
124
+ end
125
+
126
+ def underlined(on = true)
127
+ on ? Underlined.new(self) : self
128
+ end
129
+
104
130
  def self.whitespace
105
131
  string(' ')
106
132
  end
@@ -0,0 +1,31 @@
1
+ module Twterm
2
+ class Image
3
+ class Underlined < 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_UNDERLINE)
14
+ image.at(line, column).render(window)
15
+ window.attroff(Curses::A_UNDERLINE)
16
+ end
17
+
18
+ def to_s
19
+ "\e[4m#{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
@@ -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
@@ -5,11 +5,10 @@ require 'twterm/event/screen/resize'
5
5
  module Twterm
6
6
  class MessageWindow
7
7
  include Singleton
8
- include Curses
9
8
  include Subscriber
10
9
 
11
10
  def initialize
12
- @window = stdscr.subwin(1, stdscr.maxx, stdscr.maxy - 2, 0)
11
+ @window = Curses.stdscr.subwin(1, Curses.stdscr.maxx, Curses.stdscr.maxy - 1, 0)
13
12
  @queue = Queue.new
14
13
 
15
14
  subscribe(Event::Message::AbstractMessage) do |e|
@@ -34,7 +33,7 @@ module Twterm
34
33
 
35
34
  def show(message = nil)
36
35
  loop do
37
- break unless closed?
36
+ break unless Curses.closed?
38
37
  sleep 0.5
39
38
  end
40
39
 
@@ -74,8 +73,8 @@ module Twterm
74
73
  end
75
74
 
76
75
  def resize(_event)
77
- @window.resize(1, stdscr.maxx)
78
- @window.move(stdscr.maxy - 2, 0)
76
+ @window.resize(1, Curses.stdscr.maxx)
77
+ @window.move(Curses.stdscr.maxy - 1, 0)
79
78
  end
80
79
  end
81
80
  end
@@ -1,4 +1,4 @@
1
- require 'toml'
1
+ require 'toml-rb'
2
2
 
3
3
  module Twterm
4
4
  class PersistableConfigurationProxy
@@ -32,16 +32,16 @@ module Twterm
32
32
  # @param [String] filepath File path to load configuration from
33
33
  # @return [Twterm::PersistableConfigurationProxy] a configuration proxy
34
34
  def self.load_from_file!(klass, filepath)
35
- config = TOML.load_file(filepath, symbolize_keys: true)
35
+ config = TomlRB.load_file(filepath, symbolize_keys: true)
36
36
  new(klass.new(config), filepath).migrate!
37
37
  rescue Errno::ENOENT
38
38
  new(klass.default, filepath)
39
- rescue TOML::ParseError, TOML::ValueOverwriteError => e
39
+ rescue TomlRB::ParseError, TomlRB::ValueOverwriteError => e
40
40
  msg =
41
41
  case e
42
- when TOML::ParseError
42
+ when TomlRB::ParseError
43
43
  "Your configuration file could not be parsed"
44
- when TOML::ValueOverwriteError
44
+ when TomlRB::ValueOverwriteError
45
45
  "`#{e.key}` is declared more than once"
46
46
  end
47
47
 
@@ -75,7 +75,7 @@ Press any key to continue
75
75
  attr_reader :filepath, :instance
76
76
 
77
77
  def persist!
78
- hash = TOML.dump(instance.to_h).gsub("\n[", "\n\n[")
78
+ hash = TomlRB.dump(instance.to_h).gsub("\n[", "\n\n[")
79
79
  File.open(filepath, 'w', 0644) { |f| f.write(hash) }
80
80
  end
81
81
  end
@@ -1,4 +1,4 @@
1
- require 'toml'
1
+ require 'toml-rb'
2
2
 
3
3
  require 'twterm/abstract_persistable_configuration'
4
4
 
@@ -27,6 +27,9 @@ module Twterm
27
27
  # @return [Twterm::Preferences] an instance having the default value
28
28
  def self.default
29
29
  new({
30
+ control: {
31
+ scroll_direction: 'traditional',
32
+ },
30
33
  photo_viewer_backend: {
31
34
  browser: true,
32
35
  imgcat: false,
@@ -48,8 +51,12 @@ module Twterm
48
51
  # @return [Hash]
49
52
  def self.structure
50
53
  bool = -> x { x == true || x == false }
54
+ scroll_direction = -> x { x == 'natural' || x == 'traditional' }
51
55
 
52
56
  {
57
+ control: {
58
+ scroll_direction: scroll_direction
59
+ },
53
60
  photo_viewer_backend: {
54
61
  browser: bool,
55
62
  imgcat: bool,
@@ -1,6 +1,4 @@
1
1
  require 'concurrent'
2
- require 'twterm/direct_message'
3
- require 'twterm/direct_message_manager'
4
2
  require 'twterm/publisher'
5
3
  require 'twterm/event/message/success'
6
4
 
@@ -25,33 +23,6 @@ module Twterm
25
23
  end
26
24
  end
27
25
 
28
- def create_direct_message(recipient, text)
29
- send_request do
30
- rest_client.create_direct_message(recipient.id, text)
31
- end.then do |message|
32
- msg = direct_message_repository.create(message)
33
- direct_message_manager.add(recipient.id, msg)
34
- publish(Event::DirectMessage::Fetched.new)
35
- publish(Event::Message::Success.new('Your message to @%s has been sent' % recipient.screen_name))
36
- end
37
- end
38
-
39
- def direct_message_conversations
40
- direct_message_manager.conversations
41
- end
42
-
43
- def direct_messages_received
44
- send_request do
45
- rest_client.direct_messages(count: 200).map { |dm| direct_message_repository.create(dm) }
46
- end
47
- end
48
-
49
- def direct_messages_sent
50
- send_request do
51
- rest_client.direct_messages_sent(count: 200).map { |dm| direct_message_repository.create(dm) }
52
- end
53
- end
54
-
55
26
  def destroy_status(status)
56
27
  send_request_without_catch do
57
28
  rest_client.destroy_status(status.id)
@@ -424,10 +395,6 @@ module Twterm
424
395
 
425
396
  private
426
397
 
427
- def direct_message_manager
428
- @direct_message_manager ||= DirectMessageManager.new(self)
429
- end
430
-
431
398
  def show_error
432
399
  proc do |e|
433
400
  case e