mireru 0.2.1 → 0.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.
- checksums.yaml +4 -4
- data/NEWS.md +21 -0
- data/README.md +33 -17
- data/lib/mireru.rb +1 -1
- data/lib/mireru/command/mireru.rb +33 -55
- data/lib/mireru/navigator.rb +166 -0
- data/lib/mireru/version.rb +1 -1
- data/lib/mireru/widget.rb +18 -12
- data/lib/mireru/widget/binary.rb +16 -22
- data/lib/mireru/widget/image.rb +11 -7
- data/lib/mireru/widget/pdf.rb +38 -20
- data/lib/mireru/widget/svg.rb +20 -16
- data/lib/mireru/widget/text.rb +22 -24
- data/lib/mireru/widget/video.rb +35 -34
- data/lib/mireru/window.rb +149 -90
- data/mireru.gemspec +3 -2
- data/test/test-logger.rb +2 -1
- data/test/test-mireru.rb +4 -53
- data/test/test-window.rb +3 -16
- data/test/widget/test-binary.rb +3 -3
- data/test/widget/test-pdf.rb +3 -3
- data/test/widget/test-svg.rb +3 -3
- data/test/widget/test-text.rb +10 -6
- data/test/widget/test-video.rb +3 -3
- data/website/locales/en.yml +8 -7
- data/website/locales/ja.yml +5 -4
- data/website/source/localizable/index.haml +2 -2
- data/website/source/localizable/usage.html.erb +11 -10
- metadata +6 -11
- data/lib/mireru/container.rb +0 -38
- data/lib/mireru/widget/thumbnail.rb +0 -43
- data/test/test-container.rb +0 -52
- data/test/widget/test-thumbnail.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdbbb02cb56552275b740544a7156e7b155bd126
|
4
|
+
data.tar.gz: efb1f67b291ec5733cf9499f6ca71cb4969251cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d73f9d68826bb2dc43fa3a9719e1b1d053bfe119a33c194660c26dfbdb7223ebfd5a3b6a292239a6f30e4841066ec552313be858edc719d72e10dba6e09a970d
|
7
|
+
data.tar.gz: 55021cc099d4abef5652d11fef73e72cd170dd71c1b29291c90bfa7e1b0c9f0df4f406b3c174e9aa8f69089edb5e79734a0a216bed20523a2d479046622c02fa
|
data/NEWS.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
# NEWS
|
2
2
|
|
3
|
+
## 0.9.0: 2014-07-13
|
4
|
+
|
5
|
+
Now we have TreeView, and many problems are resolved.
|
6
|
+
|
7
|
+
### Changes
|
8
|
+
|
9
|
+
* Improvements
|
10
|
+
* Improve scrolling movements.
|
11
|
+
* Save CPU and memory for distinction between text and binary.
|
12
|
+
* Improve help messages.
|
13
|
+
* Remove thumbnail function.
|
14
|
+
* pdf: Support multiple pages.
|
15
|
+
* Fit a parent widget (PDF, SVG and Video).
|
16
|
+
* Support music files.
|
17
|
+
* Add key bindings.
|
18
|
+
* Introduce Navigator as Gtk::TreeView.
|
19
|
+
|
20
|
+
* Fixes
|
21
|
+
* image: Enable animation for image files such as animated GIF.
|
22
|
+
* video: Fix a bug that destroyed object is called.
|
23
|
+
|
3
24
|
## 0.2.1: 2014-05-29
|
4
25
|
|
5
26
|
### Changes
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Mireru [](http://travis-ci.org/myokoym/mireru)
|
2
2
|
|
3
|
-
|
3
|
+
Mireru is a keyboard friendly file viewer by Ruby/GTK3.
|
4
4
|
|
5
|
-
|
5
|
+
It can handle a variety of file types (Picture, Text, PDF, Video and etc.).
|
6
6
|
|
7
7
|
## Requirements
|
8
8
|
|
9
|
-
* Ruby/GTK3, Ruby/GtkSourceView3, Ruby/ClutterGTK, Ruby/ClutterGStreamer
|
10
|
-
|
9
|
+
* Ruby/GTK3, Ruby/GtkSourceView3, Ruby/ClutterGTK, Ruby/ClutterGStreamer,
|
10
|
+
Ruby/Poppler and Ruby/RSVG2 in
|
11
11
|
[Ruby-GNOME2](http://ruby-gnome2.sourceforge.jp/)
|
12
12
|
* [hexdump](https://github.com/postmodern/hexdump)
|
13
13
|
|
@@ -19,28 +19,36 @@ A friend of a keyboard.
|
|
19
19
|
|
20
20
|
### Launch
|
21
21
|
|
22
|
-
$ mireru [OPTION]... [
|
22
|
+
$ mireru [OPTION]... [FILE_OR_DIRECTORY]...
|
23
23
|
|
24
|
-
If no argument, then
|
24
|
+
If no argument, then open the current directory.
|
25
25
|
|
26
26
|
### Options
|
27
27
|
|
28
|
-
-
|
29
|
-
|
28
|
+
-h, --help<br />
|
29
|
+
show this help message
|
30
30
|
|
31
31
|
-f, --font NAME<br />
|
32
|
-
set font such as "Monospace 16"
|
32
|
+
set a font such as "Monospace 16"
|
33
33
|
|
34
|
-
###
|
34
|
+
### Key bindings
|
35
35
|
|
36
36
|
#### Common
|
37
37
|
|
38
38
|
n: next<br />
|
39
39
|
p: prev<br />
|
40
|
+
e: expand/collpse<br />
|
40
41
|
r: reload<br />
|
41
|
-
e: expand path<br />
|
42
42
|
q: quit<br />
|
43
43
|
|
44
|
+
#### Control key mask
|
45
|
+
|
46
|
+
Ctrl+n: 10 tiles next<br />
|
47
|
+
Ctrl+p: 10 tiles prev<br />
|
48
|
+
Ctrl+e: expand all/collpse even if cursor on file<br />
|
49
|
+
Ctrl+h: move position of partition to left<br />
|
50
|
+
Ctrl+l: move position of partition to right<br />
|
51
|
+
|
44
52
|
#### Scroll
|
45
53
|
|
46
54
|
h: left<br />
|
@@ -48,19 +56,22 @@ j: down<br />
|
|
48
56
|
k: up<br />
|
49
57
|
l: right<br />
|
50
58
|
|
59
|
+
Shift+h: 100 times left<br />
|
60
|
+
Shift+j: 100 times down<br />
|
61
|
+
Shift+k: 100 times up<br />
|
62
|
+
Shift+l: 100 times right<br />
|
63
|
+
|
64
|
+
Shift+g: down to bottom<br />
|
65
|
+
|
51
66
|
#### Scale
|
52
67
|
|
53
68
|
+: larger<br />
|
54
69
|
-: smaller<br />
|
55
70
|
|
56
|
-
#### Special
|
57
|
-
|
58
|
-
T: thumbnail
|
59
|
-
|
60
71
|
#### Image
|
61
72
|
|
62
|
-
f:
|
63
|
-
o: original size<br />
|
73
|
+
f: fit window size<br />
|
74
|
+
o: scale to the original size<br />
|
64
75
|
|
65
76
|
#### Text
|
66
77
|
|
@@ -70,6 +81,11 @@ f: change font (at random)<br />
|
|
70
81
|
|
71
82
|
space: play/pause<br />
|
72
83
|
|
84
|
+
#### PDF
|
85
|
+
|
86
|
+
j: next page<br />
|
87
|
+
k: prev page<br />
|
88
|
+
|
73
89
|
## License
|
74
90
|
|
75
91
|
Copyright (c) 2013-2014 Masafumi Yokoyama <myokoym@gmail.com>
|
data/lib/mireru.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
require "gtk3"
|
2
1
|
require "mireru/logger"
|
3
2
|
require "mireru/window"
|
4
|
-
require "mireru/container"
|
5
3
|
require "mireru/version"
|
6
4
|
|
7
5
|
module Mireru
|
8
6
|
module Command
|
9
7
|
class Mireru
|
10
|
-
USAGE = "Usage: mireru [OPTION]... [
|
8
|
+
USAGE = "Usage: mireru [OPTION]... [FILE_OR_DIRECTORY]..."
|
11
9
|
|
12
10
|
class << self
|
13
11
|
def run(*arguments)
|
@@ -31,44 +29,17 @@ module Mireru
|
|
31
29
|
font = purge_option(arguments, /\A(-f|--font)\z/, true)
|
32
30
|
|
33
31
|
files = files_from_arguments(arguments)
|
34
|
-
file_container = ::Mireru::Container.new(files)
|
35
32
|
|
36
|
-
|
37
|
-
write_empty_message
|
38
|
-
exit(false)
|
39
|
-
end
|
40
|
-
|
41
|
-
window = ::Mireru::Window.new
|
33
|
+
window = ::Mireru::Window.new(files)
|
42
34
|
window.font = font if font
|
43
|
-
window.add_container(file_container)
|
44
35
|
|
45
|
-
|
36
|
+
window.run
|
46
37
|
end
|
47
38
|
|
48
39
|
private
|
49
40
|
def files_from_arguments(arguments)
|
50
41
|
if arguments.empty?
|
51
|
-
files = Dir.
|
52
|
-
elsif purge_option(arguments, /\A(-R|--recursive|-d|--deep)\z/)
|
53
|
-
if arguments.empty?
|
54
|
-
files = Dir.glob("**/*")
|
55
|
-
else
|
56
|
-
files = []
|
57
|
-
arguments.each do |f|
|
58
|
-
if File.directory?(f)
|
59
|
-
files << Dir.glob("#{f}/**/*")
|
60
|
-
else
|
61
|
-
files << f
|
62
|
-
end
|
63
|
-
end
|
64
|
-
files.flatten!
|
65
|
-
end
|
66
|
-
elsif arguments.all? {|v| File.directory?(v) }
|
67
|
-
files = []
|
68
|
-
arguments.each do |f|
|
69
|
-
files << Dir.glob("#{f}/*")
|
70
|
-
end
|
71
|
-
files.flatten!
|
42
|
+
files = [Dir.pwd]
|
72
43
|
else
|
73
44
|
files = arguments
|
74
45
|
end
|
@@ -89,38 +60,59 @@ module Mireru
|
|
89
60
|
def write_help_message
|
90
61
|
message = <<-EOM
|
91
62
|
#{USAGE}
|
92
|
-
If no argument, then
|
63
|
+
If no argument, then open the current directory.
|
64
|
+
|
93
65
|
Options:
|
94
|
-
-
|
95
|
-
|
66
|
+
-h, --help
|
67
|
+
show this help message
|
68
|
+
|
96
69
|
-f, --font NAME
|
97
|
-
set font such as "Monospace 16"
|
98
|
-
|
70
|
+
set a font such as "Monospace 16"
|
71
|
+
|
72
|
+
Key bindings:
|
99
73
|
n: next
|
100
74
|
p: prev
|
75
|
+
e: expand/collpse
|
101
76
|
r: reload
|
102
|
-
e: expand path
|
103
77
|
q: quit
|
104
78
|
|
79
|
+
Control key mask:
|
80
|
+
Ctrl+n: 10 tiles next
|
81
|
+
Ctrl+p: 10 tiles prev
|
82
|
+
Ctrl+e: expand all / collpse even if cursor on file
|
83
|
+
Ctrl+h: move position of partition to left
|
84
|
+
Ctrl+l: move position of partition to right
|
85
|
+
|
105
86
|
scroll:
|
106
87
|
h: left
|
107
88
|
j: down
|
108
89
|
k: up
|
109
90
|
l: right
|
110
91
|
|
92
|
+
Shift+h: 100 times left
|
93
|
+
Shift+j: 100 times down
|
94
|
+
Shift+k: 100 times up
|
95
|
+
Shift+l: 100 times right
|
96
|
+
|
97
|
+
Shift+g: down to bottom
|
98
|
+
|
111
99
|
scale:
|
112
100
|
+: larger
|
113
101
|
-: smaller
|
114
102
|
|
115
103
|
image:
|
116
|
-
f:
|
117
|
-
o: original size
|
104
|
+
f: fit window size
|
105
|
+
o: scale to the original size
|
118
106
|
|
119
107
|
text:
|
120
108
|
f: change font (at random)
|
121
109
|
|
122
110
|
video:
|
123
111
|
space: play/pause
|
112
|
+
|
113
|
+
PDF:
|
114
|
+
j: next page
|
115
|
+
k: prev page
|
124
116
|
EOM
|
125
117
|
@logger.info(message)
|
126
118
|
end
|
@@ -131,20 +123,6 @@ Keybind:
|
|
131
123
|
EOM
|
132
124
|
@logger.info(message)
|
133
125
|
end
|
134
|
-
|
135
|
-
def write_empty_message
|
136
|
-
message = <<-EOM
|
137
|
-
Warning: file not found.
|
138
|
-
#{USAGE}
|
139
|
-
If no argument, then search current directory.
|
140
|
-
Options:
|
141
|
-
-R, --recursive
|
142
|
-
recursive search as "**/*"
|
143
|
-
-f, --font NAME
|
144
|
-
set font such as "Monospace 16"
|
145
|
-
EOM
|
146
|
-
@logger.error(message)
|
147
|
-
end
|
148
126
|
end
|
149
127
|
end
|
150
128
|
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "gtk3"
|
2
|
+
|
3
|
+
module Mireru
|
4
|
+
class Navigator < Gtk::ScrolledWindow
|
5
|
+
PATH_COLUMN, FILENAME_COLUMN, ICON_COLUMN = 0, 1, 2
|
6
|
+
|
7
|
+
def initialize(window, files)
|
8
|
+
super()
|
9
|
+
@window = window
|
10
|
+
@files = files
|
11
|
+
@dir_iters = {}
|
12
|
+
set_policy(:automatic, :automatic)
|
13
|
+
set_size_request(200, -1)
|
14
|
+
@model = Gtk::TreeStore.new(String, String, Gdk::Pixbuf)
|
15
|
+
@tree_view = create_tree(@model)
|
16
|
+
add(@tree_view)
|
17
|
+
end
|
18
|
+
|
19
|
+
def next
|
20
|
+
@tree_view.move_cursor(Gtk::MovementStep::DISPLAY_LINES, 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def prev
|
24
|
+
@tree_view.move_cursor(Gtk::MovementStep::DISPLAY_LINES, -1)
|
25
|
+
end
|
26
|
+
|
27
|
+
def expand_toggle(open_all=false)
|
28
|
+
path = selected_path
|
29
|
+
iter = @model.get_iter(path)
|
30
|
+
file_path = iter.get_value(PATH_COLUMN)
|
31
|
+
if open_all and File.file?(file_path)
|
32
|
+
parent = iter.parent
|
33
|
+
path = @model.get_path(parent)
|
34
|
+
@tree_view.collapse_row(path)
|
35
|
+
elsif @tree_view.row_expanded?(path)
|
36
|
+
@tree_view.collapse_row(path)
|
37
|
+
else
|
38
|
+
if open_all
|
39
|
+
return unless File.directory?(file_path)
|
40
|
+
Dir.glob("#{file_path}/*") do |dir|
|
41
|
+
next unless File.directory?(dir)
|
42
|
+
child_iter = @dir_iters[dir]
|
43
|
+
next unless child_iter
|
44
|
+
load_dir(@model, dir, child_iter, true)
|
45
|
+
@dir_iters.delete(dir)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@tree_view.expand_row(path, open_all)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def selected_path
|
53
|
+
selection = @tree_view.selection
|
54
|
+
selected = selection.selected
|
55
|
+
@model.get_path(selected)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def create_tree(model)
|
60
|
+
tree_view = Gtk::TreeView.new
|
61
|
+
tree_view.set_model(model)
|
62
|
+
tree_view.search_column = FILENAME_COLUMN
|
63
|
+
tree_view.enable_search = false
|
64
|
+
|
65
|
+
selection = tree_view.selection
|
66
|
+
selection.set_mode(:browse)
|
67
|
+
|
68
|
+
@files.each do |file|
|
69
|
+
load_file(model, file)
|
70
|
+
end
|
71
|
+
|
72
|
+
column = Gtk::TreeViewColumn.new
|
73
|
+
if @files.size == 1
|
74
|
+
column.title = File.dirname(@files.first)
|
75
|
+
else
|
76
|
+
column.title = "Selected Files"
|
77
|
+
end
|
78
|
+
tree_view.append_column(column)
|
79
|
+
|
80
|
+
renderer = Gtk::CellRendererPixbuf.new
|
81
|
+
renderer.set_fixed_size(*Gtk::IconSize.lookup(:menu))
|
82
|
+
column.pack_start(renderer, :expand => false)
|
83
|
+
column.add_attribute(renderer, :pixbuf, ICON_COLUMN)
|
84
|
+
|
85
|
+
renderer = Gtk::CellRendererText.new
|
86
|
+
column.pack_start(renderer, :expand => false)
|
87
|
+
column.add_attribute(renderer, :text, FILENAME_COLUMN)
|
88
|
+
|
89
|
+
selection.signal_connect("changed") do |selection|
|
90
|
+
apply_changed(selection)
|
91
|
+
end
|
92
|
+
|
93
|
+
tree_view.expand_all
|
94
|
+
tree_view
|
95
|
+
end
|
96
|
+
|
97
|
+
def apply_changed(selection)
|
98
|
+
iter = selection.selected
|
99
|
+
return unless iter
|
100
|
+
path = iter.get_value(PATH_COLUMN)
|
101
|
+
if File.directory?(path)
|
102
|
+
if @dir_iters[path]
|
103
|
+
load_dir(@model, path, @dir_iters[path])
|
104
|
+
end
|
105
|
+
@dir_iters.delete(path)
|
106
|
+
end
|
107
|
+
return unless File.file?(path)
|
108
|
+
@window.title = path
|
109
|
+
@window.file = path
|
110
|
+
begin
|
111
|
+
GLib::Timeout.add(100) do
|
112
|
+
if @window.file == path
|
113
|
+
begin
|
114
|
+
@window.add_from_file(path)
|
115
|
+
rescue => e
|
116
|
+
$stderr.puts("#{e.class}: #{e.message}")
|
117
|
+
$stderr.puts(e.backtrace)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
false
|
121
|
+
end
|
122
|
+
rescue
|
123
|
+
stock = Gtk::Stock::MISSING_IMAGE
|
124
|
+
size = :dialog
|
125
|
+
pixbuf = Gtk::Image.new.render_icon_pixbuf(stock, size)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def load_dir(model, dir, parent=nil, recursive=false)
|
130
|
+
Dir.glob("#{File.expand_path(dir)}/*") do |child|
|
131
|
+
load_file(model, child, parent, recursive)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def load_file(model, file, parent=nil, recursive=false)
|
136
|
+
iter = model.append(parent)
|
137
|
+
iter.set_value(PATH_COLUMN, file)
|
138
|
+
iter.set_value(FILENAME_COLUMN, File.basename(file))
|
139
|
+
if File.directory?(file)
|
140
|
+
@dir_iters[file] = iter unless recursive
|
141
|
+
dir_icon = self.render_icon_pixbuf(Gtk::Stock::DIRECTORY, :menu)
|
142
|
+
iter.set_value(ICON_COLUMN, dir_icon)
|
143
|
+
load_dir(model, file, iter, recursive) if recursive
|
144
|
+
else
|
145
|
+
file_icon = select_icon(file)
|
146
|
+
iter.set_value(ICON_COLUMN, file_icon)
|
147
|
+
end
|
148
|
+
# TODO: too slow...
|
149
|
+
#icon_width, icon_height = Gtk::IconSize.lookup(:menu)
|
150
|
+
#begin
|
151
|
+
# pixbuf = Gdk::Pixbuf.new(file_path, icon_width, icon_height)
|
152
|
+
#rescue Gdk::PixbufError
|
153
|
+
# pixbuf = file_icon
|
154
|
+
#end
|
155
|
+
#iter.set_value(ICON_COLUMN, pixbuf)
|
156
|
+
end
|
157
|
+
|
158
|
+
def select_icon(file)
|
159
|
+
if Widget.video?(file) or Widget.music?(file)
|
160
|
+
self.render_icon_pixbuf(Gtk::Stock::CDROM, :menu)
|
161
|
+
else
|
162
|
+
self.render_icon_pixbuf(Gtk::Stock::FILE, :menu)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|