2 CommandError = require './command-error'
4 VimOption = require './vim-option'
7 deferred = Promise.defer()
13 if error.message.endsWith('is a directory')
14 atom.notifications.addWarning("Unable to save file: #{error.message}")
16 if error.code is 'EACCES'
18 .addWarning("Unable to save file: Permission denied '#{error.path}'")
19 else if error.code in ['EPERM', 'EBUSY', 'UNKNOWN', 'EEXIST']
20 atom.notifications.addWarning("Unable to save file '#{error.path}'",
21 detail: error.message)
22 else if error.code is 'EROFS'
23 atom.notifications.addWarning(
24 "Unable to save file: Read-only file system '#{error.path}'")
26 /ENOTDIR, not a directory '([^']+)'/.exec(error.message))
27 fileName = errorMatch[1]
28 atom.notifications.addWarning("Unable to save file: A directory in the "+
29 "path '#{fileName}' could not be written to")
35 saveAs = (filePath) ->
36 editor = atom.workspace.getActiveTextEditor()
37 fs.writeFileSync(filePath, editor.getText())
39 getFullPath = (filePath) ->
40 filePath = fs.normalize(filePath)
42 if path.isAbsolute(filePath)
44 else if atom.project.getPaths().length == 0
45 path.join(fs.normalize('~'), filePath)
47 path.join(atom.project.getPaths()[0], filePath)
49 replaceGroups = (groups, string) ->
52 while (char = string[0])?
54 if char is '\\' and not escaped
56 else if /\d/.test(char) and escaped
58 group = groups[parseInt(char)]
71 @registerCommand: (name, func) =>
72 @singleton()[name] = func
75 atom.workspace.getActivePane().destroyActiveItem()
79 tabedit: (range, args) =>
80 if args.trim() isnt ''
85 tabe: (args...) => @tabedit(args...)
87 tabnew: (range, args) =>
93 tabclose: (args...) => @quit(args...)
98 pane = atom.workspace.getActivePane()
99 pane.activateNextItem()
104 pane = atom.workspace.getActivePane()
105 pane.activatePreviousItem()
107 tabp: => @tabprevious()
109 edit: (range, filePath) ->
110 filePath = filePath.trim()
111 if filePath[0] is '!'
113 filePath = filePath[1..].trim()
117 editor = atom.workspace.getActiveTextEditor()
118 if editor.isModified() and not force
119 throw new CommandError('No write since last change (add ! to override)')
120 if filePath.indexOf(' ') isnt -1
121 throw new CommandError('Only one file name allowed')
123 if filePath.length isnt 0
124 fullPath = getFullPath(filePath)
125 if fullPath is editor.getPath()
126 editor.getBuffer().reload()
128 atom.workspace.open(fullPath)
131 editor.getBuffer().reload()
133 throw new CommandError('No file name')
135 e: (args...) => @edit(args...)
138 buffer = atom.workspace.getActiveTextEditor().buffer
139 buffer.setPath(undefined)
142 write: (range, filePath) ->
143 if filePath[0] is '!'
145 filePath = filePath[1..]
149 filePath = filePath.trim()
150 if filePath.indexOf(' ') isnt -1
151 throw new CommandError('Only one file name allowed')
153 deferred = Promise.defer()
155 editor = atom.workspace.getActiveTextEditor()
157 if filePath.length isnt 0
158 fullPath = getFullPath(filePath)
159 if editor.getPath()? and (not fullPath? or editor.getPath() == fullPath)
160 # Use editor.save when no path is given or the path to the file is given
161 trySave(-> editor.save()).then(deferred.resolve)
163 else if not fullPath?
164 fullPath = atom.showSaveDialogSync()
166 if not saved and fullPath?
167 if not force and fs.existsSync(fullPath)
168 throw new CommandError("File exists (add ! to override)")
169 trySave(-> saveAs(fullPath)).then(deferred.resolve)
177 @write(args...).then => @quit()
179 xit: (args...) => @wq(args...)
182 atom.workspace.saveAll()
184 split: (range, args) ->
186 filePaths = args.split(' ')
187 filePaths = undefined if filePaths.length is 1 and filePaths[0] is ''
188 pane = atom.workspace.getActivePane()
189 if filePaths? and filePaths.length > 0
190 newPane = pane.splitUp()
191 for file in filePaths
193 atom.workspace.openURIInPane file, newPane
195 pane.splitUp(copyActiveItem: true)
197 sp: (args...) => @split(args...)
199 substitute: (range, args) ->
200 args = args.trimLeft()
202 if /[a-z]/i.test(delim)
203 throw new CommandError(
204 "Regular expressions can't be delimited by letters")
205 delimRE = new RegExp("[^\\\\]#{delim}")
208 while (i = args_.search(delimRE)) isnt -1
210 args_ = args_[i + 2..]
211 if args_.length is 0 and spl.length is 3
212 throw new CommandError('Trailing characters')
213 else if args_.length isnt 0
216 throw new CommandError('Trailing characters')
219 notDelimRE = new RegExp("\\\\#{delim}", 'g')
220 spl[0] = spl[0].replace(notDelimRE, delim)
221 spl[1] = spl[1].replace(notDelimRE, delim)
224 pattern = new RegExp(spl[0], spl[2])
226 if e.message.indexOf('Invalid flags supplied to RegExp constructor') is 0
227 # vim only says 'Trailing characters', but let's be more descriptive
228 throw new CommandError("Invalid flags: #{e.message[45..]}")
229 else if e.message.indexOf('Invalid regular expression: ') is 0
230 throw new CommandError("Invalid RegEx: #{e.message[27..]}")
234 buffer = atom.workspace.getActiveTextEditor().buffer
235 atom.workspace.getActiveTextEditor().transact ->
236 for line in [range[0]..range[1]]
237 buffer.scanInRange(pattern,
238 [[line, 0], [line, buffer.lines[line].length]],
239 ({match, matchText, range, stop, replace}) ->
240 replace(replaceGroups(match[..], spl[1]))
243 s: (args...) => @substitute(args...)
245 vsplit: (range, args) ->
247 filePaths = args.split(' ')
248 filePaths = undefined if filePaths.length is 1 and filePaths[0] is ''
249 pane = atom.workspace.getActivePane()
250 if filePaths? and filePaths.length > 0
251 newPane = pane.splitLeft()
252 for file in filePaths
254 atom.workspace.openURIInPane file, newPane
256 pane.splitLeft(copyActiveItem: true)
258 vsp: (args...) => @vsplit(args...)
261 range = [[range[0], 0], [range[1] + 1, 0]]
262 atom.workspace.getActiveTextEditor().buffer.setTextInRange(range, '')
264 set: (range, args) ->
267 throw new CommandError("No option specified")
268 options = args.split(' ')
269 for option in options
271 if option.includes("=")
272 nameValPair = option.split("=")
273 if (nameValPair.length != 2)
274 throw new CommandError("Wrong option format. [name]=[value] format is expected")
275 optionName = nameValPair[0]
276 optionValue = nameValPair[1]
277 optionProcessor = VimOption.singleton()[optionName]
278 if not optionProcessor?
279 throw new CommandError("No such option: #{optionName}")
280 optionProcessor(optionValue)
282 optionProcessor = VimOption.singleton()[option]
283 if not optionProcessor?
284 throw new CommandError("No such option: #{option}")