redcar 0.12.1 → 0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/CHANGES +18 -0
  2. data/bin/redcar +1 -0
  3. data/lib/redcar.rb +4 -5
  4. data/lib/redcar/usage.rb +0 -1
  5. data/lib/redcar_quick_start.rb +3 -1
  6. data/plugins/application/lib/application.rb +1 -0
  7. data/plugins/application/lib/application/commands/treebook_commands.rb +11 -18
  8. data/plugins/application/lib/application/dialog.rb +1 -1
  9. data/plugins/application/lib/application/dialogs/filter_list_dialog.rb +13 -5
  10. data/plugins/application/lib/application/global_state.rb +21 -0
  11. data/plugins/application/lib/application/menu/item.rb +37 -11
  12. data/plugins/application/lib/application/notebook.rb +12 -0
  13. data/plugins/application/lib/application/tree/mirror.rb +0 -11
  14. data/plugins/application/lib/application/window.rb +32 -7
  15. data/plugins/application_swt/lib/application_swt.rb +1 -1
  16. data/plugins/application_swt/lib/application_swt/dialogs/filter_list_dialog_controller.rb +35 -10
  17. data/plugins/application_swt/lib/application_swt/icon.rb +1 -1
  18. data/plugins/application_swt/lib/application_swt/menu.rb +47 -15
  19. data/plugins/application_swt/lib/application_swt/notebook.rb +11 -2
  20. data/plugins/application_swt/lib/application_swt/window.rb +37 -34
  21. data/plugins/auto_indenter/lib/auto_indenter/analyzer.rb +1 -1
  22. data/plugins/auto_indenter/spec/auto_indenter/analyzer_spec.rb +9 -0
  23. data/plugins/declarations/lib/declarations.rb +31 -66
  24. data/plugins/declarations/lib/declarations/commands.rb +142 -0
  25. data/plugins/declarations/lib/declarations/file.rb +1 -1
  26. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/javascript.js +0 -0
  27. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/nothing_to_see.rb +0 -0
  28. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/one_lonely_class.rb +0 -0
  29. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/similar_names.rb +0 -0
  30. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/something_fancy.rb +0 -0
  31. data/plugins/{outline_view → declarations}/spec/fixtures/some_project/trailing_space.rb +0 -0
  32. data/plugins/edit_view/lib/edit_view.rb +35 -2
  33. data/plugins/edit_view/lib/edit_view/commands/change_language_command.rb +31 -0
  34. data/plugins/edit_view/lib/edit_view/commands/language_settings_commands.rb +45 -0
  35. data/plugins/edit_view/lib/edit_view/document/command.rb +1 -1
  36. data/plugins/edit_view/lib/edit_view/edit_tab.rb +11 -13
  37. data/plugins/key_bindings/lib/key_bindings.rb +6 -2
  38. data/plugins/project/lib/project.rb +27 -32
  39. data/plugins/project/lib/project/commands.rb +3 -88
  40. data/plugins/project/lib/project/dir_controller.rb +12 -18
  41. data/plugins/project/lib/project/dir_mirror.rb +20 -25
  42. data/plugins/project/lib/project/file_mirror.rb +10 -10
  43. data/plugins/project/lib/project/find_file_dialog.rb +20 -18
  44. data/plugins/project/lib/project/find_recent_dialog.rb +6 -3
  45. data/plugins/project/lib/project/{adapters/local.rb → local_filesystem.rb} +35 -35
  46. data/plugins/project/lib/project/manager.rb +21 -75
  47. data/plugins/project/lib/project/sub_project.rb +3 -3
  48. data/plugins/project/plugin.rb +0 -1
  49. data/plugins/project_search/lib/project_search/lucene_refresh.rb +0 -1
  50. data/plugins/redcar/plugin.rb +2 -2
  51. data/plugins/redcar/redcar.rb +34 -42
  52. data/plugins/ruby/lib/ruby/syntax_checker.rb +27 -7
  53. data/plugins/scm/lib/scm.rb +1 -12
  54. data/plugins/sessions/lib/sessions.rb +22 -0
  55. data/plugins/sessions/lib/sessions/cursor_saver.rb +162 -0
  56. data/plugins/sessions/lib/sessions/loader.rb +99 -0
  57. data/plugins/sessions/lib/sessions/memory.rb +59 -0
  58. data/plugins/sessions/plugin.rb +8 -0
  59. data/plugins/strip_trailing_spaces/lib/strip_trailing_spaces.rb +2 -2
  60. data/plugins/syntax_check/lib/syntax_check.rb +2 -2
  61. data/plugins/tree_view_swt/lib/tree_view_swt.rb +1 -3
  62. data/redcar.gemspec +1 -1
  63. metadata +195 -291
  64. data/plugins/connection_manager/lib/connection_manager.rb +0 -57
  65. data/plugins/connection_manager/lib/connection_manager/commands.rb +0 -14
  66. data/plugins/connection_manager/lib/connection_manager/connection_store.rb +0 -87
  67. data/plugins/connection_manager/lib/connection_manager/controller.rb +0 -100
  68. data/plugins/connection_manager/lib/connection_manager/filter_dialog.rb +0 -38
  69. data/plugins/connection_manager/lib/connection_manager/private_key_store.rb +0 -93
  70. data/plugins/connection_manager/plugin.rb +0 -12
  71. data/plugins/connection_manager/views/index.html.erb +0 -284
  72. data/plugins/edit_view/lib/edit_view/info_speedbar.rb +0 -98
  73. data/plugins/outline_view/features/outline_view.feature +0 -79
  74. data/plugins/outline_view/features/project_outline.feature +0 -23
  75. data/plugins/outline_view/features/step_definitions/outline_steps.rb +0 -61
  76. data/plugins/outline_view/lib/outline_view.rb +0 -97
  77. data/plugins/outline_view/lib/outline_view/commands.rb +0 -19
  78. data/plugins/outline_view/plugin.rb +0 -10
  79. data/plugins/outline_view_swt/lib/outline_view_swt.rb +0 -79
  80. data/plugins/outline_view_swt/plugin.rb +0 -7
  81. data/plugins/project/lib/project/adapters/remote.rb +0 -96
  82. data/plugins/project/lib/project/adapters/remote_protocols/ftp.rb +0 -93
  83. data/plugins/project/lib/project/adapters/remote_protocols/protocol.rb +0 -94
  84. data/plugins/project/lib/project/adapters/remote_protocols/sftp.rb +0 -181
@@ -9,16 +9,15 @@ module Redcar
9
9
 
10
10
  class Project
11
11
  class OpenFileCommand < Command
12
- def initialize(path = nil, adapter = Adapters::Local.new)
12
+ def initialize(path = nil)
13
13
  @path = path
14
- @adapter = adapter
15
14
  end
16
15
 
17
16
  def execute
18
17
  path = get_path
19
18
  if path
20
19
  if File.readable? path
21
- Manager.open_file(path, @adapter)
20
+ Manager.open_file(path)
22
21
  else
23
22
  Application::Dialog.message_box(
24
23
  "Can't read #{path}, you don't have the permissions.",
@@ -42,7 +41,7 @@ module Redcar
42
41
  end
43
42
 
44
43
  class FileReloadCommand < EditTabCommand
45
- def initialize(path = nil, adapter = Adapters::Local.new)
44
+ def initialize(path = nil)
46
45
  @path = path
47
46
  end
48
47
 
@@ -62,86 +61,6 @@ module Redcar
62
61
  end
63
62
  end
64
63
 
65
- class OpenRemoteSpeedbar < Redcar::Speedbar
66
-
67
- class << self
68
- attr_accessor :connection
69
-
70
- def connections
71
- ConnectionManager::ConnectionStore.new.connections
72
- end
73
-
74
- def connection_names
75
- if connections && connections.any?
76
- ['Select...', connections.map { |c| c.name }].flatten
77
- end
78
- end
79
- end
80
-
81
- def initialize
82
- connection.items = self.class.connection_names
83
- end
84
-
85
- label :connection_label, 'Connect to:'
86
- combo :connection
87
-
88
- button :connect, "Connect", "Return" do
89
- selected = self.class.connections.find { |c| c.name == connection.value }
90
-
91
- Manager.connect_to_remote(selected[:protocol], selected[:host],
92
- selected[:user], selected[:path], ConnectionManager::PrivateKeyStore.paths)
93
- end
94
-
95
- button :quick, "Quick Connection", "Ctrl+Q" do
96
- @speedbar = QuickOpenRemoteSpeedbar.new
97
- Redcar.app.focussed_window.open_speedbar(@speedbar)
98
- end
99
-
100
- button :manage, "Connections Manager", "Ctrl+M" do
101
- Redcar.app.focussed_window.close_speedbar
102
- Redcar::ConnectionManager::OpenCommand.new.run
103
- end
104
- end
105
-
106
- class QuickOpenRemoteSpeedbar < Redcar::Speedbar
107
- class << self
108
- attr_accessor :host
109
- attr_accessor :user
110
- attr_accessor :password
111
- attr_accessor :path
112
- attr_accessor :protocol
113
- end
114
-
115
- combo :protocol, %w(SFTP FTP), 'SFTP'
116
-
117
- label :host_label, "Host:"
118
- textbox :host
119
-
120
- label :user_label, "User:"
121
- textbox :user
122
-
123
- label :path_label, "Path:"
124
- textbox :path
125
-
126
- button :connect, "Connect", "Return" do
127
- Manager.connect_to_remote(protocol.value, host.value, user.value,
128
- path.value, ConnectionManager::PrivateKeyStore.paths)
129
- end
130
- end
131
-
132
- #class OpenRemoteCommand < Command
133
- # def initialize(url=nil)
134
- # @url = url
135
- # end
136
- #
137
- # def execute
138
- # unless @url
139
- # @speedbar = OpenRemoteSpeedbar.new
140
- # win.open_speedbar(@speedbar)
141
- # end
142
- # end
143
- #end
144
-
145
64
  class SaveFileCommand < EditTabCommand
146
65
  def initialize(tab=nil)
147
66
  @tab = tab
@@ -261,10 +180,6 @@ module Redcar
261
180
  class FindFileCommand < ProjectCommand
262
181
 
263
182
  def execute
264
- if Manager.focussed_project.remote?
265
- Application::Dialog.message_box("Find file doesn't work in remote projects yet :(")
266
- return
267
- end
268
183
  dialog = FindFileDialog.new(Manager.focussed_project)
269
184
  dialog.open
270
185
  end
@@ -3,14 +3,11 @@ module Redcar
3
3
  class Project
4
4
  class DirController
5
5
  include Redcar::Tree::Controller
6
-
7
- def self.adapter(node, tree=nil)
8
- node ? node.adapter : tree.tree_mirror.adapter
9
- end
6
+ include LocalFilesystem
10
7
 
11
8
  def activated(tree, node)
12
9
  if node.leaf?
13
- OpenFileCommand.new(node.path, node.adapter).run
10
+ OpenFileCommand.new(node.path).run
14
11
  end
15
12
  end
16
13
 
@@ -21,6 +18,7 @@ module Redcar
21
18
 
22
19
  class DragController
23
20
  include Redcar::Tree::Controller::DragController
21
+ include LocalFilesystem
24
22
 
25
23
  attr_reader :tree
26
24
 
@@ -43,8 +41,7 @@ module Redcar
43
41
  non_nested_paths.each do |path|
44
42
  dir = target ? target.directory : tree.tree_mirror.path
45
43
  unless File.dirname(path) == dir
46
- adapter = DirController.adapter(target, tree)
47
- adapter.mv(path, dir)
44
+ fs.mv(path, dir)
48
45
  end
49
46
  end
50
47
  tree.refresh
@@ -113,8 +110,7 @@ module Redcar
113
110
  new_file_name = uniq_name(enclosing_dir, "New File")
114
111
  new_file_path = File.join(enclosing_dir, new_file_name)
115
112
 
116
- adapter = DirController.adapter(node, tree)
117
- adapter.touch(new_file_path)
113
+ fs.touch(new_file_path)
118
114
  tree.refresh
119
115
  tree.expand(node)
120
116
  new_file_node = DirMirror::Node.cache[new_file_path]
@@ -125,8 +121,7 @@ module Redcar
125
121
  enclosing_dir = node ? node.directory : tree.tree_mirror.path
126
122
  new_dir_name = uniq_name(enclosing_dir, "New Directory")
127
123
  new_dir_path = File.join(enclosing_dir, new_dir_name)
128
- adapter = DirController.adapter(node, tree)
129
- adapter.mkdir(new_dir_path)
124
+ fs.mkdir(new_dir_path)
130
125
  tree.refresh
131
126
  tree.expand(node)
132
127
  new_dir_node = DirMirror::Node.cache[new_dir_path]
@@ -159,6 +154,7 @@ module Redcar
159
154
 
160
155
  class BulkRenameController
161
156
  include Redcar::HtmlController
157
+ include LocalFilesystem
162
158
 
163
159
  attr_reader :pairs, :match_pattern, :replace_pattern
164
160
 
@@ -168,7 +164,6 @@ module Redcar
168
164
  @pairs = nodes.map {|node| [node, File.basename(node.path)] }
169
165
  @match_pattern = ""
170
166
  @replace_pattern = ""
171
- @adapter = DirController.adapter(nodes.first, tree)
172
167
  end
173
168
 
174
169
  def title
@@ -191,7 +186,7 @@ module Redcar
191
186
  old_name = File.basename(node.path)
192
187
  new_name = transform_name(old_name)
193
188
  new_path = File.join(File.dirname(node.path), new_name)
194
- conflicts = (@adapter.exists?(new_path) and new_name != old_name)
189
+ conflicts = (fs.exists?(new_path) and new_name != old_name)
195
190
  legal = (new_name != "" and legal_path?(new_path))
196
191
  [new_name, conflicts, legal]
197
192
  end
@@ -208,7 +203,7 @@ module Redcar
208
203
  new_name = transform_name(old_name)
209
204
  next if old_name == new_name
210
205
  new_path = File.join(File.dirname(node.path), new_name)
211
- @adapter.mv(node.path, new_path)
206
+ fs.mv(node.path, new_path)
212
207
  end
213
208
  @tab.close
214
209
  @tree.refresh
@@ -240,7 +235,7 @@ module Redcar
240
235
  result = Application::Dialog.message_box(msg, :type => :question, :buttons => :yes_no)
241
236
  if result == :yes
242
237
  nodes.each do |node|
243
- node.adapter.delete(node.path)
238
+ fs.delete(node.path)
244
239
  end
245
240
  tree.refresh
246
241
  end
@@ -250,10 +245,9 @@ module Redcar
250
245
  new_path = File.expand_path(File.join(File.dirname(node.path), text))
251
246
  return if node.path == new_path
252
247
 
253
- adapter = DirController.adapter(node, tree)
254
- adapter.mv(node.path, new_path)
248
+ fs.mv(node.path, new_path)
255
249
  tree.refresh
256
- new_node = DirMirror::Node.create_from_path(adapter, {:fullname => new_path, :type => node.type})
250
+ new_node = DirMirror::Node.create_from_path(:fullname => new_path, :type => node.type)
257
251
  tree.select(new_node)
258
252
  end
259
253
 
@@ -11,11 +11,12 @@ module Redcar
11
11
  end
12
12
 
13
13
  include Redcar::Tree::Mirror
14
- attr_reader :path, :adapter
14
+ include LocalFilesystem
15
+
16
+ attr_reader :path
15
17
 
16
18
  # @param [String] a path to a directory
17
- def initialize(path, adapter=Adapters::Local.new)
18
- @adapter = adapter
19
+ def initialize(path)
19
20
  @changed = true
20
21
  @path = path
21
22
  end
@@ -26,7 +27,7 @@ module Redcar
26
27
 
27
28
  # Does the directory exist?
28
29
  def exists?
29
- @adapter.exists?(@path) && @adapter.directory?(@path)
30
+ fs.exists?(@path) && fs.directory?(@path)
30
31
  end
31
32
 
32
33
  # Have the toplevel nodes changed?
@@ -44,7 +45,7 @@ module Redcar
44
45
  # The files and directories in the top of the directory.
45
46
  def top
46
47
  @changed = false
47
- Node.create_all_from_path(@adapter, @path)
48
+ Node.create_all_from_path(@path)
48
49
  end
49
50
 
50
51
  # We specify a :file data type to take advantage of OS integration.
@@ -56,7 +57,7 @@ module Redcar
56
57
  #
57
58
  # @return [Node]
58
59
  def from_data(path)
59
- Node.create_from_path(@adapter, {:fullname => path})
60
+ Node.create_from_path(:fullname => path)
60
61
  end
61
62
 
62
63
  # Turn the nodes into data.
@@ -64,39 +65,34 @@ module Redcar
64
65
  nodes.map {|node| node.path }
65
66
  end
66
67
 
67
- def refresh_operation(tree)
68
- @adapter.refresh_operation(tree) do
69
- yield
70
- end
71
- end
72
-
73
68
  class Node
74
69
  include Redcar::Tree::Mirror::NodeMirror
70
+ extend LocalFilesystem
75
71
 
76
- attr_reader :path, :adapter
72
+ attr_reader :path
77
73
  attr_accessor :type, :is_empty_directory
78
74
 
79
- def self.create_all_from_path(adapter, path)
80
- fs = adapter.fetch_contents(path)
81
- fs.reject! { |f| [".", ".."].include?(File.basename(f[:fullname])) }
75
+ def self.create_all_from_path(path)
76
+ list = fs.fetch_contents(path)
77
+ list.reject! { |f| [".", ".."].include?(File.basename(f[:fullname])) }
82
78
  unless DirMirror.show_hidden_files?
83
- fs.reject! { |f| f[:type] == :file and Project::FileList.hide_file?(f[:fullname]) }
84
- fs.reject! { |f| f[:type] == :dir and Project::FileList.hide_directory? f[:fullname] }
79
+ list.reject! { |f| f[:type] == :file and Project::FileList.hide_file?(f[:fullname]) }
80
+ list.reject! { |f| f[:type] == :dir and Project::FileList.hide_directory? f[:fullname] }
85
81
  end
86
- fs.sort_by do |f|
82
+ list.sort_by do |f|
87
83
  File.basename(f[:fullname]).downcase
88
84
  end.sort_by do |f|
89
85
  f[:type] == :dir ? -1 : 1
90
- end.map {|f| create_from_path(adapter, f) }
86
+ end.map {|f| create_from_path(f) }
91
87
  end
92
88
 
93
- def self.create_from_path(adapter, f)
89
+ def self.create_from_path(f)
94
90
  if result = cache[f[:fullname]]
95
91
  result.type = f[:type]
96
92
  result.is_empty_directory = f[:empty]
97
93
  result
98
94
  else
99
- cache[f[:fullname]] = Node.new(adapter, f[:fullname], f[:type], f[:empty])
95
+ cache[f[:fullname]] = Node.new(f[:fullname], f[:type], f[:empty])
100
96
  end
101
97
  end
102
98
 
@@ -104,8 +100,7 @@ module Redcar
104
100
  @cache ||= {}
105
101
  end
106
102
 
107
- def initialize(adapter, path, type, is_empty_directory)
108
- @adapter = adapter
103
+ def initialize(path, type, is_empty_directory)
109
104
  @path = path
110
105
  @type = type
111
106
  @is_empty_directory = is_empty_directory
@@ -155,7 +150,7 @@ module Redcar
155
150
  if file? or @is_empty_directory
156
151
  []
157
152
  else
158
- Node.create_all_from_path(adapter, @path)
153
+ Node.create_all_from_path(@path)
159
154
  end
160
155
  end
161
156
 
@@ -9,13 +9,13 @@ module Redcar
9
9
  # which reflects a file.
10
10
  class FileMirror
11
11
  include Redcar::Document::Mirror
12
+ include LocalFilesystem
12
13
 
13
- attr_reader :path, :adapter, :timestamp
14
+ attr_reader :path, :timestamp
14
15
 
15
16
  # @param [String] a path to a file
16
- def initialize(path, adapter=Adapters::Local.new)
17
+ def initialize(path)
17
18
  @path = path
18
- @adapter = adapter
19
19
  end
20
20
 
21
21
  # Load the contents of the file from disk
@@ -24,7 +24,7 @@ module Redcar
24
24
  def read
25
25
  return "" unless exists?
26
26
  contents = load_contents
27
- @timestamp = @adapter.mtime(@path)
27
+ @timestamp = fs.mtime(@path)
28
28
  contents
29
29
  end
30
30
 
@@ -32,7 +32,7 @@ module Redcar
32
32
  #
33
33
  # @return [Boolean]
34
34
  def exists?
35
- @adapter.exists?(@path)
35
+ fs.exists?(@path)
36
36
  end
37
37
 
38
38
  # Has the file changed since the last time it was read or commited?
@@ -41,7 +41,7 @@ module Redcar
41
41
  # @return [Boolean]
42
42
  def changed?
43
43
  begin
44
- !@timestamp or @timestamp < @adapter.mtime(@path)
44
+ !@timestamp or @timestamp < fs.mtime(@path)
45
45
  rescue Errno::ENOENT
46
46
  false
47
47
  end
@@ -49,7 +49,7 @@ module Redcar
49
49
 
50
50
  def changed_since?(time)
51
51
  begin
52
- !@timestamp or (!time and changed?) or (time and time < @adapter.mtime(@path))
52
+ !@timestamp or (!time and changed?) or (time and time < fs.mtime(@path))
53
53
  rescue Errno::ENOENT
54
54
  false
55
55
  end
@@ -61,7 +61,7 @@ module Redcar
61
61
  # @return [unspecified]
62
62
  def commit(contents)
63
63
  save_contents(contents)
64
- @timestamp = @adapter.mtime(@path)
64
+ @timestamp = fs.mtime(@path)
65
65
  end
66
66
 
67
67
  # The filename.
@@ -74,11 +74,11 @@ module Redcar
74
74
  private
75
75
 
76
76
  def load_contents
77
- @adapter.load(@path)
77
+ fs.load(@path)
78
78
  end
79
79
 
80
80
  def save_contents(contents)
81
- @adapter.save(@path, contents)
81
+ fs.save(@path, contents)
82
82
  end
83
83
  end
84
84
  end
@@ -21,34 +21,26 @@ module Redcar
21
21
  paths.uniq
22
22
  end
23
23
 
24
- # search out and expand duplicates in shortened paths to their full length
25
- def expand_duplicates(display_paths, full_paths)
26
- duplicates = duplicates(display_paths)
27
- display_paths.each_with_index do |dp, i|
28
- if duplicates.include? dp
29
- display_paths[i] = display_path(full_paths[i], project.path.split('/')[0..-2].join('/'))
30
- end
31
- end
32
- end
33
-
34
- def update_list(filter)
35
- paths = paths_for filter
36
- @last_list = paths
37
- full_paths = paths
24
+ def update_list(filter)
25
+ full_paths = paths_for(filter)
38
26
  display_paths = full_paths.map { |path| display_path(path) }
39
27
  if display_paths.uniq.length < full_paths.length
40
28
  display_paths = expand_duplicates(display_paths, full_paths)
41
29
  end
42
- display_paths
30
+ result = []
31
+ display_paths.zip(full_paths) do |display_path, full_path|
32
+ result << {:name => display_path, :path => full_path, :icon => :file}
33
+ end
34
+ result
43
35
  end
44
36
 
45
- def selected(text, ix, closing=false)
46
- if @last_list
37
+ def selected(item, ix)
38
+ if item[:path] and File.exist?(item[:path])
47
39
  close
48
40
  if win = Redcar.app.focussed_window and tab = win.focussed_notebook_tab and doc = tab.document
49
41
  Redcar.app.navigation_history.save(doc)
50
42
  end
51
- OpenFileCommand.new(@last_list[ix]).run
43
+ OpenFileCommand.new(item[:path]).run
52
44
  cur_doc = Redcar.app.focussed_window.focussed_notebook_tab.document
53
45
  Redcar.app.navigation_history.save(cur_doc) if cur_doc
54
46
  end
@@ -66,6 +58,16 @@ module Redcar
66
58
  Set[*enum.select {|k| enum.index(k) != enum.rindex(k) }]
67
59
  end
68
60
 
61
+ # search out and expand duplicates in shortened paths to their full length
62
+ def expand_duplicates(display_paths, full_paths)
63
+ duplicates = duplicates(display_paths)
64
+ display_paths.each_with_index do |dp, i|
65
+ if duplicates.include? dp
66
+ display_paths[i] = display_path(full_paths[i], project.path.split('/')[0..-2].join('/'))
67
+ end
68
+ end
69
+ end
70
+
69
71
  def display_path(path, first_remove_this_prefix = nil)
70
72
  n = -3
71
73
  if first_remove_this_prefix and path.index(first_remove_this_prefix) == 0