twterm 2.7.0 → 2.10.2
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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +62 -0
- data/.gitattributes +4 -0
- data/.gitignore +1 -0
- data/Gemfile +7 -0
- data/Makefile +21 -0
- data/README.md +52 -6
- data/bin/twterm +1 -3
- data/default.nix +21 -0
- data/gemset.nix +5130 -0
- data/lib/twterm/app.rb +13 -8
- data/lib/twterm/color_manager.rb +8 -9
- data/lib/twterm/image.rb +31 -0
- data/lib/twterm/image/attr.rb +42 -0
- data/lib/twterm/image/bold.rb +7 -21
- data/lib/twterm/image/color.rb +9 -15
- data/lib/twterm/image/dim.rb +13 -0
- data/lib/twterm/image/underlined.rb +17 -0
- data/lib/twterm/image_builder/user_name_image_builder.rb +1 -0
- data/lib/twterm/key_mapper.rb +6 -8
- data/lib/twterm/key_mapper/abstract_key_mapper.rb +2 -2
- data/lib/twterm/list.rb +36 -1
- data/lib/twterm/message_window.rb +4 -13
- data/lib/twterm/persistable_configuration_proxy.rb +6 -6
- data/lib/twterm/preferences.rb +8 -1
- data/lib/twterm/screen.rb +103 -25
- data/lib/twterm/search_query_window.rb +5 -13
- data/lib/twterm/status.rb +10 -0
- data/lib/twterm/tab/abstract_tab.rb +30 -16
- data/lib/twterm/tab/new/search.rb +2 -2
- data/lib/twterm/tab/new/user.rb +2 -2
- data/lib/twterm/tab/preferences/control.rb +77 -0
- data/lib/twterm/tab/preferences/index.rb +6 -0
- data/lib/twterm/tab/scrollable.rb +1 -1
- data/lib/twterm/tab/searchable.rb +6 -4
- data/lib/twterm/tab/status_tab.rb +10 -0
- data/lib/twterm/tab/statuses/abstract_statuses_tab.rb +11 -6
- data/lib/twterm/tab_manager.rb +77 -10
- data/lib/twterm/tweetbox.rb +2 -3
- data/lib/twterm/user.rb +1 -0
- data/lib/twterm/version.rb +1 -1
- data/nix/Gemfile +3 -0
- data/nix/Gemfile.lock +77 -0
- data/nix/gemset.nix +325 -0
- data/shell.nix +40 -0
- data/spec/twterm/image/bold_spec.rb +30 -0
- data/spec/twterm/image/color_spec.rb +16 -0
- data/spec/twterm/image/dim_spec.rb +30 -0
- data/twterm.gemspec +7 -14
- metadata +35 -108
- data/.travis.yml +0 -12
- data/lib/twterm/event/screen/resize.rb +0 -13
- 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.
|
67
|
-
MessageWindow.
|
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
|
-
|
185
|
+
lines, cols = `stty size`.split(' ').map(&:to_i)
|
186
|
+
|
187
|
+
Readline.set_screen_size(lines, cols)
|
181
188
|
|
182
|
-
lines
|
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
|
data/lib/twterm/color_manager.rb
CHANGED
@@ -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
|
data/lib/twterm/image/bold.rb
CHANGED
@@ -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
|
-
|
23
|
-
image.width
|
24
|
-
end
|
10
|
+
protected
|
25
11
|
|
26
|
-
|
27
|
-
|
28
|
-
|
12
|
+
def attr
|
13
|
+
Curses::A_BOLD
|
14
|
+
end
|
29
15
|
end
|
30
16
|
end
|
31
17
|
end
|
data/lib/twterm/image/color.rb
CHANGED
@@ -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
|
-
|
6
|
-
end
|
7
|
-
|
8
|
-
def height
|
9
|
-
image.height
|
10
|
-
end
|
7
|
+
super(image)
|
11
8
|
|
12
|
-
|
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
|
-
|
33
|
-
|
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
|
data/lib/twterm/key_mapper.rb
CHANGED
@@ -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 =
|
109
|
-
rescue
|
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
|
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 =
|
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
|
-
|
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
|
-
|
12
|
-
|
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
|