twterm 2.5.0 → 2.9.0

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