niklas-vimmate 0.8.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.
- data/.autotest +10 -0
- data/CHANGELOG +108 -0
- data/COPYING +20 -0
- data/README +221 -0
- data/Rakefile +97 -0
- data/TODO +21 -0
- data/bin/vimmate +95 -0
- data/config/environment.rb +33 -0
- data/controllers/file_filter_controller.rb +85 -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.rb +8 -0
- data/lib/active_window/active_column.rb +218 -0
- data/lib/active_window/active_tree_store.rb +13 -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/application.rb +133 -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 +114 -0
- data/lib/active_window/listed_item.rb +127 -0
- data/lib/active_window/signal.rb +46 -0
- data/lib/config_window.rb +90 -0
- data/lib/file_tree_store.rb +73 -0
- data/lib/filtered_file_tree_store.rb +34 -0
- data/lib/gtk_thread_helper.rb +73 -0
- data/lib/listed_directory.rb +43 -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 +36 -0
- data/lib/vim/netbeans.rb +156 -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.rb +6 -0
- data/lib/vim_mate/plugins/inotify/init.rb +4 -0
- data/lib/vim_mate/plugins/inotify/lib/INotify.rb +206 -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/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 +150 -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 +308 -0
- data/vimmate.gemspec +131 -0
- metadata +168 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
class FilteredFileTreeStore < ActiveWindow::FilteredActiveTreeStore
|
2
|
+
# Fuzzy search by String
|
3
|
+
# 'foo' => matches la/lu/foo, f/lala/o/gaga/o
|
4
|
+
# 'foo/bar' => matches la/afoo/gnarz/barz, but not the above
|
5
|
+
def iter_visible?(iter)
|
6
|
+
case iter[OBJECT]
|
7
|
+
when ListedDirectory; false
|
8
|
+
when ListedFile
|
9
|
+
iter[filter_column] =~ filter_regexp
|
10
|
+
else
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def filter_string=(new_filter_string)
|
16
|
+
@filter_regexp = nil
|
17
|
+
@filter_column = nil
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def filter_regexp
|
23
|
+
@filter_regexp ||= Regexp.new(
|
24
|
+
filter_string.split('/').map { |t|
|
25
|
+
Regexp.escape(t).split(//).join('.*')
|
26
|
+
}.join('.*/.*')
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def filter_column
|
31
|
+
@filter_column ||= filter_string =~ %r~/~ ? FULL_PATH : NAME
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# From http://ruby-gnome2.sourceforge.jp/hiki.cgi?tips_threads
|
2
|
+
#
|
3
|
+
# This is a crucial "tip," and in fact qualifies, I believe, as a major warning
|
4
|
+
# or fix for using Ruby with the Gtk library.
|
5
|
+
#
|
6
|
+
# The warning is this: If you call Gtk methods from outside of Gtk's main thread,
|
7
|
+
# there is a chance that the Ruby interpreter (not merely your Ruby application!)
|
8
|
+
# will crash with a segmentation fault (seg fault) error, seemingly at random.
|
9
|
+
# This is not an exception you can catch. It is fatal and crippling, and very
|
10
|
+
# difficult to debug.
|
11
|
+
#
|
12
|
+
# You might be using Ruby threads even without knowing! For example, if you
|
13
|
+
# receive events or callbacks to your Ruby methods or blocks from another library
|
14
|
+
# or service, these calls may very well be occurring on other threads. If that's
|
15
|
+
# the case, and you call Gtk from within your callbacks, you risk a seg fault.
|
16
|
+
#
|
17
|
+
# Otherwise you might have your own worker thread in the background doing some
|
18
|
+
# work, which occasionally needs to call Gtk to update a widget.
|
19
|
+
#
|
20
|
+
# (Side note: If you are using Ruby threads, be sure to protect your
|
21
|
+
# thread-shared resources with either a Monitor or a Mutex! The difference:
|
22
|
+
# monitors are safer, in that they are re-entrable from the same thread;
|
23
|
+
# mutexes aren't, but perform better.)
|
24
|
+
#
|
25
|
+
# Usage is very simple:
|
26
|
+
|
27
|
+
# Start your Gtk application by calling Gtk.main_with_queue rather than
|
28
|
+
# Gtk.main. The "timeout" argument is in milliseconds, and it is the maximum
|
29
|
+
# time that can pass until queued blocks get called: 100 should be fine.
|
30
|
+
#
|
31
|
+
# Whenever you need to queue a call, use Gtk.queue. For example:
|
32
|
+
# def my_event_callback
|
33
|
+
# Gtk.queue do
|
34
|
+
# @image.pixbuf = Gdk::Pixbuf.new @image_path, width, height
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Issues:
|
39
|
+
# 1. Keep your queued blocks lean. Do all your CPU-intensive work outside of
|
40
|
+
# the queued block. This will help keep Gtk responsive.
|
41
|
+
|
42
|
+
require 'monitor'
|
43
|
+
module Gtk
|
44
|
+
GTK_PENDING_BLOCKS = []
|
45
|
+
GTK_PENDING_BLOCKS_LOCK = ::Monitor.new
|
46
|
+
|
47
|
+
GTK_MAX_PENDING_BLOCKS_PER_ITERATION = 42
|
48
|
+
|
49
|
+
def Gtk.queue &block
|
50
|
+
if Thread.current == Thread.main
|
51
|
+
block.call
|
52
|
+
else
|
53
|
+
GTK_PENDING_BLOCKS_LOCK.synchronize do
|
54
|
+
GTK_PENDING_BLOCKS << block
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def Gtk.main_with_queue timeout = 100
|
60
|
+
Gtk.timeout_add timeout do
|
61
|
+
GTK_PENDING_BLOCKS_LOCK.synchronize do
|
62
|
+
length = GTK_PENDING_BLOCKS.length
|
63
|
+
if length > GTK_MAX_PENDING_BLOCKS_PER_ITERATION
|
64
|
+
GTK_PENDING_BLOCKS.shift(GTK_MAX_PENDING_BLOCKS_PER_ITERATION).each(&:call)
|
65
|
+
elsif length > 0
|
66
|
+
GTK_PENDING_BLOCKS.each(&:call).clear
|
67
|
+
end
|
68
|
+
end
|
69
|
+
true
|
70
|
+
end
|
71
|
+
Gtk.main
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class ListedDirectory < ListedFile
|
2
|
+
def sort
|
3
|
+
"1-#{name}-1"
|
4
|
+
end
|
5
|
+
def icon_name
|
6
|
+
'folder'
|
7
|
+
end
|
8
|
+
def file?
|
9
|
+
false # yeah..!
|
10
|
+
end
|
11
|
+
def directory?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
def exists?
|
15
|
+
full_path && ::File.directory?(full_path)
|
16
|
+
end
|
17
|
+
def refresh
|
18
|
+
super
|
19
|
+
#remove_not_existing_files
|
20
|
+
add_new_files
|
21
|
+
end
|
22
|
+
|
23
|
+
def children_paths
|
24
|
+
children_names.map {|n| File.join(full_path, n)}
|
25
|
+
end
|
26
|
+
|
27
|
+
def children_names
|
28
|
+
Dir.entries(full_path).select {|p| p !~ /^\./ }
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Find files to add
|
33
|
+
def add_new_files
|
34
|
+
begin
|
35
|
+
children_paths.each do |file_path|
|
36
|
+
tree << file_path
|
37
|
+
end
|
38
|
+
rescue Errno::ENOENT
|
39
|
+
end
|
40
|
+
@traversed = true
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
data/lib/listed_file.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class ListedFile < ActiveWindow::ListedItem
|
2
|
+
attr_accessor :full_path, :name, :status
|
3
|
+
|
4
|
+
def self.create(opts = {})
|
5
|
+
if fp = opts[:full_path]
|
6
|
+
if File.directory?(fp)
|
7
|
+
ListedDirectory.new opts
|
8
|
+
elsif File.file?(fp)
|
9
|
+
ListedFile.new opts
|
10
|
+
else
|
11
|
+
raise ArgumentError, "does not exist: #{fp}"
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise ArgumentError, "please give a :full_path, not only #{opts.inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(opts = {})
|
19
|
+
super
|
20
|
+
if fp = opts[:full_path]
|
21
|
+
self.full_path = fp
|
22
|
+
self.status = "normal" if VimMate::Config[:files_show_status]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
def icon_name
|
26
|
+
'file'
|
27
|
+
end
|
28
|
+
def refresh
|
29
|
+
Gtk.queue do
|
30
|
+
self.icon = VimMate::Icons.by_name icon_name
|
31
|
+
self.status = "normal" if VimMate::Config[:files_show_status]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# sets #name AND #fullpath
|
36
|
+
def full_path=(new_full_path)
|
37
|
+
unless new_full_path.empty?
|
38
|
+
@full_path = File.expand_path new_full_path
|
39
|
+
self.name = File.basename new_full_path
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def sort
|
43
|
+
"2-#{name}-1"
|
44
|
+
end
|
45
|
+
def file?
|
46
|
+
true
|
47
|
+
end
|
48
|
+
def directory?
|
49
|
+
false
|
50
|
+
end
|
51
|
+
def exists?
|
52
|
+
full_path && ::File.file?(full_path)
|
53
|
+
end
|
54
|
+
def file_or_directory?
|
55
|
+
file? || directory?
|
56
|
+
end
|
57
|
+
|
58
|
+
def show!
|
59
|
+
i = iter
|
60
|
+
while i = i.parent
|
61
|
+
i[VISIBLE] = true
|
62
|
+
end
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
data/lib/try.rb
ADDED
data/lib/vim/buffers.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
module Vim
|
4
|
+
module Integration
|
5
|
+
|
6
|
+
Password = 'donthasslethehoff'
|
7
|
+
|
8
|
+
include Buffers
|
9
|
+
include Netbeans
|
10
|
+
|
11
|
+
private
|
12
|
+
def listen
|
13
|
+
Thread.new do
|
14
|
+
while true
|
15
|
+
send_function(0, 'getCursor')
|
16
|
+
sleep 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
Thread.new do
|
20
|
+
while true
|
21
|
+
if data = vim.gets
|
22
|
+
interpret_message(data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def exec_gvim(command)
|
29
|
+
`gvim --servername #{@vim_server_name} #{command}`
|
30
|
+
end
|
31
|
+
|
32
|
+
def remote_send(command)
|
33
|
+
exec_gvim %Q~--remote-send '#{command.gsub(%q~'~,%q~\\'~)}'~
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/vim/netbeans.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
module Vim
|
2
|
+
module Netbeans
|
3
|
+
|
4
|
+
SERVER_MUTEX = Mutex.new
|
5
|
+
|
6
|
+
class Message
|
7
|
+
attr_reader :message
|
8
|
+
def initialize(message)
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
@message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
class Event < Message
|
17
|
+
attr_reader :buffer, :name, :value, :rest
|
18
|
+
def initialize(message)
|
19
|
+
super
|
20
|
+
if match = message.match(/^(\d+):(\w+)=(\d)\s*/)
|
21
|
+
@buffer = match[1].to_i
|
22
|
+
@name = match[2]
|
23
|
+
@value = match[3]
|
24
|
+
@rest = match.post_match.split(/\s/)
|
25
|
+
@rest = @rest.map do |arg|
|
26
|
+
case arg
|
27
|
+
when /^"(.*)"$/
|
28
|
+
$1
|
29
|
+
when 'T'
|
30
|
+
true
|
31
|
+
when 'F'
|
32
|
+
false
|
33
|
+
when /^\d+$/
|
34
|
+
arg.to_i
|
35
|
+
else
|
36
|
+
arg
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
def to_s
|
42
|
+
%Q~#{@buffer}:#{@name}=#{@value} #{@rest.inspect}~
|
43
|
+
end
|
44
|
+
end
|
45
|
+
class Reply < Message
|
46
|
+
attr_reader :seqno, :value
|
47
|
+
def initialize(message)
|
48
|
+
super
|
49
|
+
@seqno, @value = message.split(/\s/)
|
50
|
+
@seqno = @seqno.to_i
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def replies
|
55
|
+
@replies ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def remember_reply(reply)
|
59
|
+
replies[reply.seqno] = reply
|
60
|
+
end
|
61
|
+
|
62
|
+
def interpret_message(mess)
|
63
|
+
if mess.index ':'
|
64
|
+
event = Event.new(mess)
|
65
|
+
case event.name
|
66
|
+
when 'fileOpened'
|
67
|
+
path = event.rest.first
|
68
|
+
if event.buffer == 0
|
69
|
+
send_command(new_buffer(path), 'putBufferNumber', path)
|
70
|
+
send_command(last_buffer, 'startDocumentListen')
|
71
|
+
else
|
72
|
+
@buffers[event.buffer] = path
|
73
|
+
send_command(event.buffer, 'startDocumentListen')
|
74
|
+
end
|
75
|
+
else
|
76
|
+
mess
|
77
|
+
end
|
78
|
+
event
|
79
|
+
else
|
80
|
+
reply = Reply.new(mess)
|
81
|
+
remember_reply reply
|
82
|
+
reply
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
attr_reader :port
|
87
|
+
def server
|
88
|
+
if @server
|
89
|
+
@server
|
90
|
+
else
|
91
|
+
@server = TCPServer.open('localhost', 0)
|
92
|
+
@port = @server.addr[1]
|
93
|
+
@server
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def vim
|
98
|
+
begin
|
99
|
+
@vim_session ||= server.accept_nonblock
|
100
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, Errno::ECONNABORTED, Errno::EPROTO, Errno::EINTR
|
101
|
+
IO.select([server])
|
102
|
+
retry
|
103
|
+
end
|
104
|
+
return @vim_session
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :seqno
|
108
|
+
def new_seqno
|
109
|
+
if @seqno
|
110
|
+
@seqno += 1
|
111
|
+
else
|
112
|
+
@seqno = 1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def send_command(buf,name,*args)
|
116
|
+
command = %Q~#{buf}:#{name}!#{new_seqno}~
|
117
|
+
unless args.empty?
|
118
|
+
command << ' ' + args.map do |arg|
|
119
|
+
case arg
|
120
|
+
when String
|
121
|
+
%Q~"#{arg.gsub('"','\\"')}"~
|
122
|
+
when Array # lnum/col
|
123
|
+
arg.length == 2 ? arg.join('/') : arg.join('-')
|
124
|
+
when true
|
125
|
+
'T'
|
126
|
+
when false
|
127
|
+
'F'
|
128
|
+
else
|
129
|
+
arg
|
130
|
+
end
|
131
|
+
end.join(' ')
|
132
|
+
end
|
133
|
+
send_message command
|
134
|
+
end
|
135
|
+
|
136
|
+
# TODO timeout
|
137
|
+
def send_function(buf,name)
|
138
|
+
seq = new_seqno
|
139
|
+
send_message %Q~#{buf}:#{name}/#{seq}~
|
140
|
+
while not reply = replies[seq]
|
141
|
+
sleep 0.005
|
142
|
+
end
|
143
|
+
replies.delete(seq)
|
144
|
+
reply
|
145
|
+
end
|
146
|
+
|
147
|
+
def send_message(message)
|
148
|
+
STDERR.puts "--- NOT sending #{message}"
|
149
|
+
return
|
150
|
+
SERVER_MUTEX.synchronize do
|
151
|
+
vim.puts message
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|