vimmate 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/.autotest +10 -0
  2. data/CHANGELOG +108 -0
  3. data/COPYING +20 -0
  4. data/README +221 -0
  5. data/Rakefile +31 -0
  6. data/TODO +21 -0
  7. data/bin/vimmate +105 -0
  8. data/config/environment.rb +35 -0
  9. data/controllers/file_filter_controller.rb +101 -0
  10. data/controllers/file_popup_menu_controller.rb +40 -0
  11. data/controllers/vim_controller.rb +28 -0
  12. data/controllers/vim_mate_controller.rb +76 -0
  13. data/images/file.png +0 -0
  14. data/images/file_green.png +0 -0
  15. data/images/file_orange.png +0 -0
  16. data/images/file_red.png +0 -0
  17. data/images/folder.png +0 -0
  18. data/images/folder_green.png +0 -0
  19. data/images/folder_orange.png +0 -0
  20. data/images/folder_red.png +0 -0
  21. data/images/processing.png +0 -0
  22. data/images/svn_added.png +0 -0
  23. data/images/svn_conflict.png +0 -0
  24. data/images/svn_deleted.png +0 -0
  25. data/images/svn_locked.png +0 -0
  26. data/images/svn_modified.png +0 -0
  27. data/images/svn_normal.png +0 -0
  28. data/images/svn_readonly.png +0 -0
  29. data/images/vimmate16.png +0 -0
  30. data/images/vimmate32.png +0 -0
  31. data/images/vimmate48.png +0 -0
  32. data/lib/active_window/active_column.rb +218 -0
  33. data/lib/active_window/active_tree_store/columns.rb +88 -0
  34. data/lib/active_window/active_tree_store/extentions.rb +81 -0
  35. data/lib/active_window/active_tree_store/index.rb +53 -0
  36. data/lib/active_window/active_tree_store.rb +26 -0
  37. data/lib/active_window/application.rb +137 -0
  38. data/lib/active_window/controller.rb +58 -0
  39. data/lib/active_window/dot_file.rb +29 -0
  40. data/lib/active_window/filtered_active_tree_store.rb +113 -0
  41. data/lib/active_window/listed_item.rb +127 -0
  42. data/lib/active_window/signal.rb +46 -0
  43. data/lib/active_window.rb +8 -0
  44. data/lib/config_window.rb +90 -0
  45. data/lib/file_tree_store.rb +74 -0
  46. data/lib/filtered_file_tree_store.rb +34 -0
  47. data/lib/gtk_thread_helper.rb +73 -0
  48. data/lib/listed_directory.rb +45 -0
  49. data/lib/listed_file.rb +67 -0
  50. data/lib/try.rb +9 -0
  51. data/lib/vim/buffers.rb +18 -0
  52. data/lib/vim/integration.rb +38 -0
  53. data/lib/vim/netbeans.rb +154 -0
  54. data/lib/vim/source.vim +18 -0
  55. data/lib/vim_mate/config.rb +132 -0
  56. data/lib/vim_mate/dummy_window.rb +14 -0
  57. data/lib/vim_mate/files_menu.rb +110 -0
  58. data/lib/vim_mate/icons.rb +156 -0
  59. data/lib/vim_mate/nice_singleton.rb +53 -0
  60. data/lib/vim_mate/plugins/inotify/init.rb +4 -0
  61. data/lib/vim_mate/plugins/inotify/lib/INotify.rb +208 -0
  62. data/lib/vim_mate/plugins/inotify/lib/directory.rb +58 -0
  63. data/lib/vim_mate/plugins/subversion/init.rb +7 -0
  64. data/lib/vim_mate/plugins/subversion/lib/file.rb +59 -0
  65. data/lib/vim_mate/plugins/subversion/lib/menu.rb +96 -0
  66. data/lib/vim_mate/plugins/subversion/lib/subversion.rb +157 -0
  67. data/lib/vim_mate/plugins.rb +6 -0
  68. data/lib/vim_mate/requirer.rb +68 -0
  69. data/lib/vim_mate/search_window.rb +227 -0
  70. data/lib/vim_mate/tags_window.rb +167 -0
  71. data/lib/vim_mate/terminals_window.rb +163 -0
  72. data/lib/vim_mate/version.rb +29 -0
  73. data/lib/vim_mate/vim_widget.rb +143 -0
  74. data/spec/active_window/active_column_spec.rb +41 -0
  75. data/spec/active_window/active_tree_store_spec.rb +312 -0
  76. data/spec/active_window/controller_spec.rb +6 -0
  77. data/spec/lib/file_tree_store_spec.rb +40 -0
  78. data/spec/lib/listed_directory_spec.rb +26 -0
  79. data/spec/lib/listed_file_spec.rb +53 -0
  80. data/spec/nice_singleton_spec.rb +23 -0
  81. data/spec/spec.opts +6 -0
  82. data/spec/spec_helper.rb +10 -0
  83. data/views/vim_mate.glade +500 -0
  84. data/vimmate.gemspec +138 -0
  85. metadata +146 -0
@@ -0,0 +1,110 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'fileutils'
25
+ require 'set'
26
+ module VimMate
27
+
28
+ # The pop-up menu used in the file tree
29
+ class FilesMenu
30
+
31
+ # Open a dialog to enter a new folder name to create
32
+ def menu_new_folder
33
+ dialog = Gtk::FileChooserDialog.new("New folder",
34
+ @parent_window.gtk_window,
35
+ Gtk::FileChooser::ACTION_CREATE_FOLDER,
36
+ nil,
37
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
38
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
39
+ dialog.set_icon_list(Icons.window_icons)
40
+ dialog.current_folder = if File.directory? @last_path
41
+ @last_path
42
+ else
43
+ File.dirname(@last_path)
44
+ end
45
+ dialog.run
46
+ dialog.destroy
47
+ menu_refresh
48
+ end
49
+
50
+ # Open a dialog to enter a new name for a file or directory
51
+ def menu_rename
52
+ dialog = Gtk::FileChooserDialog.new("Rename #{File.basename(@last_path)}",
53
+ @parent_window.gtk_window,
54
+ Gtk::FileChooser::ACTION_SAVE,
55
+ nil,
56
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
57
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
58
+ dialog.set_icon_list(Icons.window_icons)
59
+ dialog.current_folder = File.dirname(@last_path)
60
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
61
+ begin
62
+ File.rename(@last_path, dialog.filename)
63
+ rescue SystemCallError
64
+ $stderr.puts "Cannot rename from #{@last_path} to #{dialog.filename}"
65
+ end
66
+ end
67
+ dialog.destroy
68
+ menu_refresh
69
+ end
70
+
71
+ # Open a dialog and ask the user if he really wants to delete the target
72
+ # file or directory. Note that for safety, directories can only be removed
73
+ # if they are empty.
74
+ def menu_delete
75
+ name = File.basename(@last_path)
76
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
77
+ Gtk::MessageDialog::Flags::MODAL,
78
+ Gtk::MessageDialog::Type::QUESTION,
79
+ Gtk::MessageDialog::ButtonsType::YES_NO,
80
+ if File.directory? @last_path
81
+ "Delete directory #{name} ?"
82
+ else
83
+ "Delete file #{name} ?"
84
+ end)
85
+ dialog.set_icon_list(Icons.window_icons)
86
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
87
+ begin
88
+ if File.directory? @last_path
89
+ FileUtils.rmdir(@last_path)
90
+ else
91
+ FileUtils.rm(@last_path)
92
+ end
93
+ rescue
94
+ $stderr.puts "Cannot remove #{@last_path}"
95
+ end
96
+ end
97
+ dialog.destroy
98
+ menu_refresh
99
+ end
100
+
101
+ # Signals that the file tree must be refreshed
102
+ def menu_refresh
103
+ @refresh_signals.each do |signal|
104
+ signal.call
105
+ end
106
+ end
107
+
108
+ end
109
+ end
110
+
@@ -0,0 +1,156 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ module VimMate
25
+
26
+ # Manages the icons that can be loaded from the disk
27
+ class Icons
28
+ include NiceSingleton
29
+
30
+ # The filenames for the icons of the windows
31
+ WINDOW_ICON_FILENAME = 'vimmate%d.png'.freeze
32
+ # The size for the icons of the windows
33
+ WINDOW_ICON_SIZES = [16, 32, 48].freeze
34
+
35
+ Overlays = %w(scm progress type)
36
+
37
+ # Create the Icons class. Cannot be called directly
38
+ def initialize
39
+ @gtk_window_icons = []
40
+ end
41
+
42
+ # Get an array of icons for the windows
43
+ def window_icons
44
+ # Load them
45
+ load_window_icons
46
+ @gtk_window_icons.freeze
47
+ # Once loaded, we only need a reader
48
+ self.class.send(:define_method, :window_icons) do
49
+ @gtk_window_icons
50
+ end
51
+ # Return the value
52
+ window_icons
53
+ end
54
+
55
+ def method_missing(meth, *args, &block)
56
+ if meth.to_s =~ /_overlayed_with_/
57
+ overlay_icon(meth, *args)
58
+ elsif meth.to_s =~ /_icon$/
59
+ build_icon(meth)
60
+ else
61
+ raise NoMethodError, "method not found: #{meth}"
62
+ end
63
+ end
64
+
65
+ def free_position
66
+ @free_overlays ||= Overlays.dup
67
+ @free_overlays.pop
68
+ end
69
+
70
+ def by_name(icon_name)
71
+ send (icon_name =~ /_icon$/) ? icon_name : "#{icon_name}_icon"
72
+ end
73
+ private
74
+
75
+ # Auto-define a method with _icon for each icon's name
76
+ def build_icon(meth)
77
+ if meth.to_s =~ /^(.*)_icon$/
78
+ name = $1
79
+ path = File.join(Config.images_path, "#{name}.png")
80
+ if File.exists? path
81
+ begin
82
+ icon = Gdk::Pixbuf.new(path)
83
+ icon.freeze
84
+ # Once loaded, we only need a reader
85
+ self.class.send(:define_method, meth) do
86
+ icon
87
+ end
88
+ return icon
89
+ rescue StandardError => e
90
+ $stderr.puts e.to_s
91
+ $stderr.puts "Problem loading #{name} icon #{path}"
92
+ raise e
93
+ end
94
+ else
95
+ raise "Icon not found: #{path}"
96
+ end
97
+ end
98
+ end
99
+
100
+ def overlay_with(original_name,overlay_name=nil,position='south')
101
+ if overlay_name.nil?
102
+ original_name
103
+ else
104
+ "#{original_name}_#{position}_overlayed_with_#{overlay_name}"
105
+ end
106
+ end
107
+
108
+ def overlay_icon(meth)
109
+ if meth.to_s =~ /^(.*)_(#{Overlays.join('|')})_overlayed_with_(.*)$/
110
+ original = $1
111
+ original_icon = by_name original
112
+ where = $2
113
+ overlay = $3
114
+ overlay_icon = by_name overlay
115
+ case where
116
+ when 'progress'
117
+ x = y = 1
118
+ when 'tr'
119
+ x = 7; y = 1
120
+ when 'scm'
121
+ x = 1; y = 7
122
+ when 'br'
123
+ x = y = 7
124
+ end
125
+ overlayed = original_icon.dup
126
+ overlayed.composite!(
127
+ overlay_icon,
128
+ x, y, # start region to render
129
+ 8, 8, # width / height
130
+ x, y, # offset
131
+ 0.5, 0.5, # scale
132
+ Gdk::Pixbuf::INTERP_BILINEAR, # interpolation
133
+ 255 # alpha
134
+ )
135
+ self.class.send(:define_method, meth) do
136
+ overlayed
137
+ end
138
+ return overlayed
139
+ end
140
+ end
141
+
142
+ # Load the icons for the windows
143
+ def load_window_icons
144
+ WINDOW_ICON_SIZES.each do |size|
145
+ file = File.join(Config.lib_path, WINDOW_ICON_FILENAME % [size])
146
+ begin
147
+ @gtk_window_icons << Gdk::Pixbuf.new(file) if File.exist? file
148
+ rescue StandardError => e
149
+ $stderr.puts e.to_s
150
+ $stderr.puts "Problem loading window icon #{file}"
151
+ end
152
+ end
153
+ end
154
+
155
+ end
156
+ end
@@ -0,0 +1,53 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'singleton'
25
+
26
+ module VimMate
27
+
28
+ # A nicer singleton implementation. When a class mixes this module,
29
+ # it becomes a singleton and you don't have to use 'instance' to
30
+ # access the singleton's class method. For example:
31
+ # class Hello
32
+ # include VimMate::NiceSingleton
33
+ #
34
+ # def hello
35
+ # "hello"
36
+ # end
37
+ # end
38
+ #
39
+ # Hello.hello # => "hello"
40
+ #
41
+ module NiceSingleton
42
+ def self.included(other)
43
+ if other.class == Class
44
+ other.send(:include, Singleton)
45
+ class << other
46
+ def method_missing(method, *args, &block)
47
+ self.instance.send(method, *args)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,4 @@
1
+ require_dependency 'lib/INotify'
2
+ require_dependency 'lib/directory'
3
+ ListedDirectory.class_eval { include VimMate::Plugin::INotifyDirectory }
4
+
@@ -0,0 +1,208 @@
1
+ # Version 0.3.0 (2005-09-27) by James Le Cuirot <chewi@ffaura.com>
2
+ # masks updated
3
+ # syscalls instead of /dev/inotify for linux-2.6.13 (are the archs correct?)
4
+ # start/stop methods added for threading
5
+ # ignore_dir_recursively method added
6
+ # Events class removed : not necessary
7
+ # (wd <=> dir) hashed both ways : needed for ignore
8
+ # default watch mask is IN_ALL_EVENTS
9
+ # UnsupportedPlatformError class added to deal with unsupported CPUs and OSes
10
+ #
11
+ # Version 0.2.3 (2005-01-18) by oxman
12
+ # function ignore_dir : was added
13
+ #
14
+ # Version 0.2.2 (2005-01-18) by oxman
15
+ # cleaning code (big thanks to gnome at #ruby-lang)
16
+ # rename next_event in each_event (thanks kig)
17
+ #
18
+ # Version 0.2.1 (2005-01-18) by oxman
19
+ # class Events : use real mask
20
+ #
21
+ # Version 0.2.0 (2005-01-18) by oxman
22
+ # function watch_dir : only watch
23
+ # function next_event : was added
24
+ # function watch_dir_recursively : was added
25
+ #
26
+ # Version 0.1.1 (2005-01-17) by oxman
27
+ # Correct IN_ var for inotify 0.18
28
+
29
+ module INotify
30
+ require 'rbconfig'
31
+
32
+ class UnsupportedPlatformError < RuntimeError
33
+ end
34
+
35
+ case Config::CONFIG["arch"]
36
+
37
+ when /i[3-6]86-linux/
38
+ INOTIFY_INIT = 291
39
+ INOTIFY_ADD_WATCH = 292
40
+ INOTIFY_RM_WATCH = 293
41
+
42
+ when /x86_64-linux/
43
+ INOTIFY_INIT = 253
44
+ INOTIFY_ADD_WATCH = 254
45
+ INOTIFY_RM_WATCH = 255
46
+
47
+ when /powerpc(64)?-linux/
48
+ INOTIFY_INIT = 275
49
+ INOTIFY_ADD_WATCH = 276
50
+ INOTIFY_RM_WATCH = 277
51
+
52
+ when /ia64-linux/
53
+ INOTIFY_INIT = 1277
54
+ INOTIFY_ADD_WATCH = 1278
55
+ INOTIFY_RM_WATCH = 1279
56
+
57
+ when /s390-linux/
58
+ INOTIFY_INIT = 284
59
+ INOTIFY_ADD_WATCH = 285
60
+ INOTIFY_RM_WATCH = 286
61
+
62
+ when /alpha-linux/
63
+ INOTIFY_INIT = 444
64
+ INOTIFY_ADD_WATCH = 445
65
+ INOTIFY_RM_WATCH = 446
66
+
67
+ when /sparc(64)?-linux/
68
+ INOTIFY_INIT = 151
69
+ INOTIFY_ADD_WATCH = 152
70
+ INOTIFY_RM_WATCH = 156
71
+
72
+ when /arm-linux/
73
+ INOTIFY_INIT = 316
74
+ INOTIFY_ADD_WATCH = 317
75
+ INOTIFY_RM_WATCH = 318
76
+
77
+ when /sh-linux/
78
+ INOTIFY_INIT = 290
79
+ INOTIFY_ADD_WATCH = 291
80
+ INOTIFY_RM_WATCH = 292
81
+
82
+ else raise UnsupportedPlatformError, Config::CONFIG["arch"]
83
+
84
+ end
85
+
86
+ Mask = Struct::new(:value, :name)
87
+
88
+ Masks = {
89
+ :IN_ACCESS => Mask::new(0x00000001, 'access'),
90
+ :IN_MODIFY => Mask::new(0x00000002, 'modify'),
91
+ :IN_ATTRIB => Mask::new(0x00000004, 'attrib'),
92
+ :IN_CLOSE_WRITE => Mask::new(0x00000008, 'close_write'),
93
+ :IN_CLOSE_NOWRITE => Mask::new(0x00000010, 'close_nowrite'),
94
+ :IN_OPEN => Mask::new(0x00000020, 'open'),
95
+ :IN_MOVED_FROM => Mask::new(0x00000040, 'moved_from'),
96
+ :IN_MOVED_TO => Mask::new(0x00000080, 'moved_to'),
97
+ :IN_CREATE => Mask::new(0x00000100, 'create'),
98
+ :IN_DELETE => Mask::new(0x00000200, 'delete'),
99
+ :IN_DELETE_SELF => Mask::new(0x00000400, 'delete_self'),
100
+ :IN_UNMOUNT => Mask::new(0x00002000, 'unmount'),
101
+ :IN_Q_OVERFLOW => Mask::new(0x00004000, 'q_overflow'),
102
+ :IN_IGNORED => Mask::new(0x00008000, 'ignored'),
103
+ }
104
+
105
+ Masks.each {|key, value|
106
+ const_set(key, value)
107
+ }
108
+
109
+ OrMasks = {
110
+ :IN_CLOSE => Mask::new(IN_CLOSE_WRITE.value | IN_CLOSE_NOWRITE.value, 'close'),
111
+ :IN_MOVE => Mask::new(IN_MOVED_FROM.value | IN_MOVED_TO.value, 'moved'),
112
+ :IN_ALL_EVENTS => Mask::new(IN_ACCESS.value | IN_MODIFY.value | IN_ATTRIB.value | IN_CLOSE_WRITE.value | IN_CLOSE_NOWRITE.value | IN_OPEN.value | IN_MOVED_FROM.value | IN_MOVED_TO.value | IN_DELETE.value | IN_CREATE.value | IN_DELETE_SELF.value, 'all_events')
113
+ }
114
+
115
+ OrMasks.each {|key, value|
116
+ const_set(key, value)
117
+ }
118
+
119
+ AllMasks = Masks.merge OrMasks
120
+
121
+ require 'find'
122
+
123
+ class INotify
124
+ def initialize
125
+ @wd_dir = Hash.new
126
+ @dir_wd = Hash.new
127
+ @io = IO.open(syscall(INOTIFY_INIT))
128
+ end
129
+
130
+ def close
131
+ @io.close
132
+ end
133
+
134
+ def watch_dir (dir, option = IN_ALL_EVENTS)
135
+ wd = syscall(INOTIFY_ADD_WATCH, @io.fileno, dir, option.value)
136
+
137
+ if wd >= 0
138
+ @dir_wd[dir] = wd
139
+ @wd_dir[wd] = dir
140
+ end
141
+
142
+ return wd
143
+ rescue Errno::EACCES => e
144
+ STDERR.puts e.message
145
+ end
146
+
147
+ def ignore_dir (dir)
148
+ syscall(INOTIFY_RM_WATCH, @io.fileno, @dir_wd[dir])
149
+ end
150
+
151
+ def watch_dir_recursively (dir, option = IN_ALL_EVENTS)
152
+ Find.find(dir) { |sub_dir| watch_dir(sub_dir, option) if (File::directory?(sub_dir) == true) }
153
+ end
154
+
155
+ def ignore_dir_recursively (dir)
156
+ Find.find(dir) { |sub_dir| ignore_dir(sub_dir) if (File::directory?(sub_dir) == true) }
157
+ end
158
+
159
+ def next_events
160
+ begin
161
+ read_cnt = @io.read(16)
162
+ wd, mask, cookie, len = read_cnt.unpack('lLLL')
163
+ read_cnt = @io.read(len)
164
+ filename = read_cnt.unpack('Z*')
165
+ end while (mask & IN_Q_OVERFLOW.value) != 0
166
+
167
+ events = Array.new
168
+
169
+ AllMasks.each_value do |m|
170
+ next if m.value == IN_ALL_EVENTS.value
171
+ events.push Event.new(@wd_dir[wd].to_s, filename.to_s, m.name.to_s, cookie) if (m.value & mask) != 0
172
+ end
173
+
174
+ return events
175
+ end
176
+
177
+ def each_event
178
+ loop { next_events.each { |event| yield event } }
179
+ end
180
+
181
+ def start
182
+ @thread = Thread.new { loop { next_events.each { |event| yield event } } }
183
+ end
184
+
185
+ def stop
186
+ @thread.exit
187
+ end
188
+ end
189
+
190
+ class Event
191
+ attr_reader :path, :filename, :type, :cookie
192
+
193
+ def initialize (path, filename, type, cookie)
194
+ @path = path
195
+ @filename = filename
196
+ @type = type
197
+ @cookie = cookie
198
+ end
199
+
200
+ def dump
201
+ "path: " + @path.to_s + ", filename: " + @filename.to_s + ", type: " + @type.to_s + ", cookie: " + @cookie.to_s
202
+ end
203
+
204
+ def to_s
205
+ dump
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,58 @@
1
+ module VimMate
2
+ module Plugin
3
+ module INotifyDirectory
4
+ Mask = INotify::Mask.new(
5
+ INotify::IN_MODIFY.value |
6
+ INotify::IN_DELETE.value |
7
+ INotify::IN_CREATE.value |
8
+ INotify::IN_MOVED_TO.value |
9
+ INotify::IN_MOVED_FROM.value |
10
+ 0, 'filechange')
11
+
12
+ Exclusions = [ /(swp|~|rej|orig)$/, /\/\.?#/, /^\./ ]
13
+ def self.included(base)
14
+ base.class_eval do
15
+ include InstanceMethods
16
+ extend ClassMethods
17
+ alias_method_chain :initialize, :inotify
18
+ start_inotify_watcher
19
+ end
20
+
21
+ end
22
+
23
+ module InstanceMethods
24
+ def initialize_with_inotify(*args)
25
+ initialize_without_inotify(*args)
26
+ if directory?
27
+ self.class.inotify_watcher.watch_dir(full_path, Mask)
28
+ end
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+ def inotify_watcher
34
+ @@inotify_watcher ||= INotify::INotify.new
35
+ end
36
+
37
+ def start_inotify_watcher
38
+ inotify_watcher.start do |event|
39
+ next if ignore_file_changes? event.filename
40
+ path = File.join(event.path, event.filename)
41
+ case event.type
42
+ when 'modify'
43
+ ActiveWindow::Signal.emit_file_modified(path)
44
+ when /^delete|moved_from$/
45
+ ActiveWindow::Signal.emit_file_deleted(path)
46
+ when /^create|moved_to$/
47
+ ActiveWindow::Signal.emit_file_created(path)
48
+ end
49
+ end
50
+ end
51
+
52
+ def ignore_file_changes?(filename)
53
+ Exclusions.any? { |exclusion| filename =~ exclusion }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ #VimMate::Requirer.require_if('lib/subversion') do
2
+ # require 'lib/file'
3
+ # require 'lib/menu'
4
+ # VimMate::ListedFile.class_eval { include VimMate::Plugin::SubversionFile }
5
+ # VimMate::ListedDirectory.class_eval { include VimMate::Plugin::SubversionFile }
6
+ # VimMate::FilesMenu.class_eval { include VimMate::Plugin::SubversionMenu }
7
+ #end
@@ -0,0 +1,59 @@
1
+ # All stuff for SVN handling of files
2
+
3
+ module VimMate
4
+ module Plugin
5
+ module SubversionFile
6
+ def self.included(base)
7
+ base.class_eval do
8
+ include InstanceMethods
9
+ modify_icon :svn do |file|
10
+ Icons.overlay_with file.icon_name_without_svn, file.svn_icon, 'scm'
11
+ end
12
+ end
13
+ end
14
+ module InstanceMethods
15
+ # Refresh the file. If the file status has changed, send a refresh
16
+ # signal
17
+ def refresh
18
+ status = Subversion.status(full_path)
19
+ if @last_status != status
20
+ @last_status = status
21
+ ListedTree.refreshed self
22
+ end
23
+ self
24
+ end
25
+
26
+
27
+ # Return the icon for this file depending on the file status
28
+ def svn_icon
29
+ status = Subversion.status(full_path)
30
+ if @last_status != status
31
+ @last_status = status
32
+ end
33
+ case status
34
+ when Subversion::UNVERSIONED, Subversion::EXTERNAL,
35
+ Subversion::IGNORED, Subversion::UNKNOWN
36
+ nil
37
+ when Subversion::NONE, Subversion::NORMAL
38
+ "svn_normal"
39
+ when Subversion::ADDED, Subversion::REPLACED
40
+ 'svn_added'
41
+ when Subversion::DELETED, Subversion::MISSING
42
+ 'svn_deleted'
43
+ when Subversion::MODIFIED
44
+ 'svn_modified'
45
+ when Subversion::CONFLICTED
46
+ 'svn_conflict'
47
+ when Subversion::MERGED, Subversion::OBSTRUCTED, Subversion::INCOMPLETE
48
+ 'svn_readonly' # FIXME for now, have no better
49
+ end
50
+ end
51
+
52
+ # Return the status text for this file depending on the file status
53
+ def status
54
+ Subversion.status_text(full_path)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end