clipcellar 0.0.1

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.
@@ -0,0 +1,56 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module Clipcellar
18
+ class GroongaSearcher
19
+ class << self
20
+ def search(database, words, options)
21
+ clipboards = database.clipboards
22
+ selected_clipboards = clipboards.select do |clipboard|
23
+ expression = nil
24
+ words.each do |word|
25
+ sub_expression = (clipboard.text =~ word)
26
+ if expression.nil?
27
+ expression = sub_expression
28
+ else
29
+ expression &= sub_expression
30
+ end
31
+ end
32
+
33
+ if options[:mtime]
34
+ base_date = (Time.now - (options[:mtime] * 60 * 60 * 24))
35
+ mtime_expression = clipboard.date > base_date
36
+ if expression.nil?
37
+ expression = mtime_expression
38
+ else
39
+ expression &= mtime_expression
40
+ end
41
+ end
42
+
43
+ expression
44
+ end
45
+
46
+ order = options[:reverse] ? "ascending" : "descending"
47
+ sorted_clipboards = selected_clipboards.sort([{
48
+ :key => "created_at",
49
+ :order => order,
50
+ }])
51
+
52
+ sorted_clipboards
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,108 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "gtk2"
18
+ require "erb"
19
+
20
+ module Clipcellar
21
+ class TreeView < Gtk::TreeView
22
+ KEY_COLUMN, TEXT_COLUMN, TIME_COLUMN, STRFTIME_COLUMN, LINE_COLUMN, ESCAPED_TEXT_COLUMN = *0..5
23
+
24
+ def initialize(records)
25
+ super()
26
+ @model = Gtk::ListStore.new(String, String, Time, String, String, String)
27
+ create_tree(@model, records)
28
+ end
29
+
30
+ def next
31
+ move_cursor(Gtk::MovementStep::DISPLAY_LINES, 1)
32
+ end
33
+
34
+ def prev
35
+ move_cursor(Gtk::MovementStep::DISPLAY_LINES, -1)
36
+ end
37
+
38
+ def remove_selected_record
39
+ return nil unless selected_iter
40
+ @model.remove(selected_iter)
41
+ end
42
+
43
+ def get_text(path)
44
+ @model.get_iter(path).get_value(TEXT_COLUMN)
45
+ end
46
+
47
+ def selected_key
48
+ return nil unless selected_iter
49
+ selected_iter.get_value(KEY_COLUMN)
50
+ end
51
+
52
+ def selected_text
53
+ return nil unless selected_iter
54
+ selected_iter.get_value(TEXT_COLUMN)
55
+ end
56
+
57
+ def selected_time
58
+ return nil unless selected_iter
59
+ selected_iter.get_value(TIME_COLUMN)
60
+ end
61
+
62
+ def selected_iter
63
+ selection.selected
64
+ end
65
+
66
+ private
67
+ def create_tree(model, records)
68
+ set_model(model)
69
+ self.search_column = TEXT_COLUMN
70
+ self.enable_search = false
71
+ self.rules_hint = true
72
+ self.tooltip_column = ESCAPED_TEXT_COLUMN
73
+
74
+ selection.set_mode(:browse)
75
+
76
+ records.each do |record|
77
+ load_record(model, record)
78
+ end
79
+
80
+ column = Gtk::TreeViewColumn.new
81
+ column.title = "Inserted Time"
82
+ append_column(column)
83
+ renderer = Gtk::CellRendererText.new
84
+ column.pack_start(renderer, :expand => false)
85
+ column.add_attribute(renderer, :text, STRFTIME_COLUMN)
86
+
87
+ column = Gtk::TreeViewColumn.new
88
+ column.title = "Part of a Text (the Full Text appears in a Tooltip)"
89
+ append_column(column)
90
+ renderer = Gtk::CellRendererText.new
91
+ column.pack_start(renderer, :expand => false)
92
+ column.add_attribute(renderer, :text, LINE_COLUMN)
93
+
94
+ expand_all
95
+ end
96
+
97
+ def load_record(model, record)
98
+ iter = model.append
99
+ iter.set_value(KEY_COLUMN, record[:key])
100
+ iter.set_value(TEXT_COLUMN, record[:text])
101
+ iter.set_value(TIME_COLUMN, record[:time])
102
+ iter.set_value(STRFTIME_COLUMN, record[:time].strftime("%Y-%m-%d %H:%M:%S"))
103
+ iter.set_value(LINE_COLUMN, record[:text].gsub(/[\n\t]/, " ")) if record[:text]
104
+ escaped_text = ERB::Util.html_escape(record[:text])
105
+ iter.set_value(ESCAPED_TEXT_COLUMN, escaped_text)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ module Clipcellar
18
+ VERSION = "0.0.1"
19
+ end
@@ -0,0 +1,121 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "gtk2"
18
+ require "clipcellar/tree_view"
19
+ require "clipcellar/clipboard"
20
+ require "clipcellar/command"
21
+
22
+ module Clipcellar
23
+ class Window < Gtk::Window
24
+ attr_accessor :text
25
+ def initialize(records)
26
+ super()
27
+ @records = records
28
+ self.title = "Clipcellar"
29
+ set_default_size(640, 480)
30
+ signal_connect("destroy") do
31
+ Gtk.main_quit
32
+ end
33
+
34
+ @vbox = Gtk::VBox.new
35
+ add(@vbox)
36
+
37
+ @scrolled_window = Gtk::ScrolledWindow.new
38
+ @scrolled_window.set_policy(:automatic, :automatic)
39
+ @vbox.pack_start(@scrolled_window, true, true, 0)
40
+
41
+ @tree_view = TreeView.new(records)
42
+ @scrolled_window.add(@tree_view)
43
+
44
+ @label = Gtk::Label.new
45
+ @label.text = "Double Click or Press Return: Copy to Clipboard / Ctrl+d: Delete from Data Store"
46
+ @vbox.pack_start(@label, false, false, 0)
47
+
48
+ @tree_view.signal_connect("row-activated") do |tree_view, path, column|
49
+ Clipboard.copy_to_clipboard(@tree_view.selected_text)
50
+ end
51
+
52
+ define_key_bindings
53
+ end
54
+
55
+ def run
56
+ show_all
57
+ Gtk.main
58
+ end
59
+
60
+ private
61
+ def define_key_bindings
62
+ signal_connect("key-press-event") do |widget, event|
63
+ handled = false
64
+
65
+ if event.state.control_mask?
66
+ handled = action_from_keyval_with_control_mask(event.keyval)
67
+ else
68
+ handled = action_from_keyval(event.keyval)
69
+ end
70
+
71
+ handled
72
+ end
73
+ end
74
+
75
+ def action_from_keyval(keyval)
76
+ case keyval
77
+ when Gdk::Keyval::GDK_KEY_n
78
+ @tree_view.next
79
+ when Gdk::Keyval::GDK_KEY_p
80
+ @tree_view.prev
81
+ when Gdk::Keyval::GDK_KEY_Return
82
+ Clipboard.copy_to_clipboard(@tree_view.selected_text)
83
+ when Gdk::Keyval::GDK_KEY_h
84
+ @scrolled_window.hadjustment.value -= 17
85
+ when Gdk::Keyval::GDK_KEY_j
86
+ @scrolled_window.vadjustment.value += 17
87
+ when Gdk::Keyval::GDK_KEY_k
88
+ @scrolled_window.vadjustment.value -= 17
89
+ when Gdk::Keyval::GDK_KEY_l
90
+ @scrolled_window.hadjustment.value += 17
91
+ when Gdk::Keyval::GDK_KEY_q
92
+ destroy
93
+ else
94
+ return false
95
+ end
96
+ true
97
+ end
98
+
99
+ def action_from_keyval_with_control_mask(keyval)
100
+ case keyval
101
+ when Gdk::Keyval::GDK_KEY_n
102
+ 10.times { @tree_view.next }
103
+ when Gdk::Keyval::GDK_KEY_p
104
+ 10.times { @tree_view.prev }
105
+ when Gdk::Keyval::GDK_KEY_d
106
+ # TODO: don't want to use Command class.
107
+ GroongaDatabase.new.open(Command.new.database_dir) do |database|
108
+ database.delete(@tree_view.selected_key)
109
+ end
110
+ @tree_view.remove_selected_record
111
+ else
112
+ return false
113
+ end
114
+ true
115
+ end
116
+
117
+ def clipboard
118
+ Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
+
19
+ require "test-unit"
20
+ require "test/unit/notify"
21
+ require "test/unit/rr"
22
+
23
+ base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
24
+ $LOAD_PATH.unshift(File.join(base_dir, "lib"))
25
+ $LOAD_PATH.unshift(File.join(base_dir, "test"))
26
+
27
+ exit Test::Unit::AutoRunner.run(true)
@@ -0,0 +1,53 @@
1
+ # Copyright (C) 2014 Masafumi Yokoyama <myokoym@gmail.com>
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License as published by the Free Software Foundation; either
6
+ # version 2.1 of the License, or (at your option) any later version.
7
+ #
8
+ # This library is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
+ # Lesser General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU Lesser General Public
14
+ # License along with this library; if not, write to the Free Software
15
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+
17
+ require "fileutils"
18
+ require "stringio"
19
+ require "clipcellar/version"
20
+ require "clipcellar/command"
21
+
22
+ class CommandTest < Test::Unit::TestCase
23
+ class << self
24
+ def startup
25
+ @@tmpdir_base = File.join(File.dirname(__FILE__), "tmp")
26
+ @@tmpdir = File.join(@@tmpdir_base, "database")
27
+ FileUtils.rm_rf(@@tmpdir)
28
+ FileUtils.mkdir_p(@@tmpdir)
29
+ @@command = Clipcellar::Command.new
30
+ @@command.instance_variable_set(:@base_dir, @@tmpdir_base)
31
+ @@command.instance_variable_set(:@database_dir, @@tmpdir)
32
+ end
33
+
34
+ def shutdown
35
+ FileUtils.rm_rf(@@tmpdir)
36
+ end
37
+ end
38
+
39
+ def test_version
40
+ s = ""
41
+ io = StringIO.new(s)
42
+ $stdout = io
43
+ @@command.version
44
+ assert_equal("#{Clipcellar::VERSION}\n", s)
45
+ $stdout = STDOUT
46
+ end
47
+
48
+ def test_destroy
49
+ assert_true(File.exist?(@@tmpdir))
50
+ @@command.destroy
51
+ assert_false(File.exist?(@@tmpdir))
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,178 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: clipcellar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Masafumi Yokoyama
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gtk2
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rroonga
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: test-unit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: test-unit-notify
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: test-unit-rr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '1.6'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Clipcellar is a full-text searchable data store for clipboard by GTK+
126
+ (via Ruby/GTK2) and Groonga (via Rroonga).
127
+ email:
128
+ - myokoym@gmail.com
129
+ executables:
130
+ - clipcellar
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - Gemfile
136
+ - LICENSE.txt
137
+ - NEWS.md
138
+ - README.md
139
+ - Rakefile
140
+ - bin/clipcellar
141
+ - clipcellar.gemspec
142
+ - lib/clipcellar.rb
143
+ - lib/clipcellar/clipboard.rb
144
+ - lib/clipcellar/command.rb
145
+ - lib/clipcellar/groonga_database.rb
146
+ - lib/clipcellar/groonga_searcher.rb
147
+ - lib/clipcellar/tree_view.rb
148
+ - lib/clipcellar/version.rb
149
+ - lib/clipcellar/window.rb
150
+ - test/run-test.rb
151
+ - test/test-command.rb
152
+ homepage: https://github.com/myokoym/clipcellar
153
+ licenses:
154
+ - LGPLv2.1 or later
155
+ metadata: {}
156
+ post_install_message:
157
+ rdoc_options: []
158
+ require_paths:
159
+ - lib
160
+ required_ruby_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - '>='
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ required_rubygems_version: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - '>='
168
+ - !ruby/object:Gem::Version
169
+ version: '0'
170
+ requirements: []
171
+ rubyforge_project:
172
+ rubygems_version: 2.0.14
173
+ signing_key:
174
+ specification_version: 4
175
+ summary: Full-Text Searchable Data Store for Clipboard
176
+ test_files:
177
+ - test/run-test.rb
178
+ - test/test-command.rb