vimmate 0.8.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.
- data/.autotest +10 -0
- data/CHANGELOG +108 -0
- data/COPYING +20 -0
- data/README +221 -0
- data/Rakefile +31 -0
- data/TODO +21 -0
- data/bin/vimmate +105 -0
- data/config/environment.rb +35 -0
- data/controllers/file_filter_controller.rb +101 -0
- data/controllers/file_popup_menu_controller.rb +40 -0
- data/controllers/vim_controller.rb +28 -0
- data/controllers/vim_mate_controller.rb +76 -0
- data/images/file.png +0 -0
- data/images/file_green.png +0 -0
- data/images/file_orange.png +0 -0
- data/images/file_red.png +0 -0
- data/images/folder.png +0 -0
- data/images/folder_green.png +0 -0
- data/images/folder_orange.png +0 -0
- data/images/folder_red.png +0 -0
- data/images/processing.png +0 -0
- data/images/svn_added.png +0 -0
- data/images/svn_conflict.png +0 -0
- data/images/svn_deleted.png +0 -0
- data/images/svn_locked.png +0 -0
- data/images/svn_modified.png +0 -0
- data/images/svn_normal.png +0 -0
- data/images/svn_readonly.png +0 -0
- data/images/vimmate16.png +0 -0
- data/images/vimmate32.png +0 -0
- data/images/vimmate48.png +0 -0
- data/lib/active_window/active_column.rb +218 -0
- data/lib/active_window/active_tree_store/columns.rb +88 -0
- data/lib/active_window/active_tree_store/extentions.rb +81 -0
- data/lib/active_window/active_tree_store/index.rb +53 -0
- data/lib/active_window/active_tree_store.rb +26 -0
- data/lib/active_window/application.rb +137 -0
- data/lib/active_window/controller.rb +58 -0
- data/lib/active_window/dot_file.rb +29 -0
- data/lib/active_window/filtered_active_tree_store.rb +113 -0
- data/lib/active_window/listed_item.rb +127 -0
- data/lib/active_window/signal.rb +46 -0
- data/lib/active_window.rb +8 -0
- data/lib/config_window.rb +90 -0
- data/lib/file_tree_store.rb +74 -0
- data/lib/filtered_file_tree_store.rb +34 -0
- data/lib/gtk_thread_helper.rb +73 -0
- data/lib/listed_directory.rb +45 -0
- data/lib/listed_file.rb +67 -0
- data/lib/try.rb +9 -0
- data/lib/vim/buffers.rb +18 -0
- data/lib/vim/integration.rb +38 -0
- data/lib/vim/netbeans.rb +154 -0
- data/lib/vim/source.vim +18 -0
- data/lib/vim_mate/config.rb +132 -0
- data/lib/vim_mate/dummy_window.rb +14 -0
- data/lib/vim_mate/files_menu.rb +110 -0
- data/lib/vim_mate/icons.rb +156 -0
- data/lib/vim_mate/nice_singleton.rb +53 -0
- data/lib/vim_mate/plugins/inotify/init.rb +4 -0
- data/lib/vim_mate/plugins/inotify/lib/INotify.rb +208 -0
- data/lib/vim_mate/plugins/inotify/lib/directory.rb +58 -0
- data/lib/vim_mate/plugins/subversion/init.rb +7 -0
- data/lib/vim_mate/plugins/subversion/lib/file.rb +59 -0
- data/lib/vim_mate/plugins/subversion/lib/menu.rb +96 -0
- data/lib/vim_mate/plugins/subversion/lib/subversion.rb +157 -0
- data/lib/vim_mate/plugins.rb +6 -0
- data/lib/vim_mate/requirer.rb +68 -0
- data/lib/vim_mate/search_window.rb +227 -0
- data/lib/vim_mate/tags_window.rb +167 -0
- data/lib/vim_mate/terminals_window.rb +163 -0
- data/lib/vim_mate/version.rb +29 -0
- data/lib/vim_mate/vim_widget.rb +143 -0
- data/spec/active_window/active_column_spec.rb +41 -0
- data/spec/active_window/active_tree_store_spec.rb +312 -0
- data/spec/active_window/controller_spec.rb +6 -0
- data/spec/lib/file_tree_store_spec.rb +40 -0
- data/spec/lib/listed_directory_spec.rb +26 -0
- data/spec/lib/listed_file_spec.rb +53 -0
- data/spec/nice_singleton_spec.rb +23 -0
- data/spec/spec.opts +6 -0
- data/spec/spec_helper.rb +10 -0
- data/views/vim_mate.glade +500 -0
- data/vimmate.gemspec +138 -0
- 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,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
|