]> git.r.bdr.sh - rbdr/dotfiles/blob - atom/packages/ex-mode/lib/ex.coffee
Remove vim-snipmate
[rbdr/dotfiles] / atom / packages / ex-mode / lib / ex.coffee
1 path = require 'path'
2 CommandError = require './command-error'
3 fs = require 'fs-plus'
4 VimOption = require './vim-option'
5
6 trySave = (func) ->
7 deferred = Promise.defer()
8
9 try
10 func()
11 deferred.resolve()
12 catch error
13 if error.message.endsWith('is a directory')
14 atom.notifications.addWarning("Unable to save file: #{error.message}")
15 else if error.path?
16 if error.code is 'EACCES'
17 atom.notifications
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}'")
25 else if (errorMatch =
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")
30 else
31 throw error
32
33 deferred.promise
34
35 saveAs = (filePath) ->
36 editor = atom.workspace.getActiveTextEditor()
37 fs.writeFileSync(filePath, editor.getText())
38
39 getFullPath = (filePath) ->
40 filePath = fs.normalize(filePath)
41
42 if path.isAbsolute(filePath)
43 filePath
44 else if atom.project.getPaths().length == 0
45 path.join(fs.normalize('~'), filePath)
46 else
47 path.join(atom.project.getPaths()[0], filePath)
48
49 replaceGroups = (groups, string) ->
50 replaced = ''
51 escaped = false
52 while (char = string[0])?
53 string = string[1..]
54 if char is '\\' and not escaped
55 escaped = true
56 else if /\d/.test(char) and escaped
57 escaped = false
58 group = groups[parseInt(char)]
59 group ?= ''
60 replaced += group
61 else
62 escaped = false
63 replaced += char
64
65 replaced
66
67 class Ex
68 @singleton: =>
69 @ex ||= new Ex
70
71 @registerCommand: (name, func) =>
72 @singleton()[name] = func
73
74 quit: ->
75 atom.workspace.getActivePane().destroyActiveItem()
76
77 q: => @quit()
78
79 tabedit: (range, args) =>
80 if args.trim() isnt ''
81 @edit(range, args)
82 else
83 @tabnew(range, args)
84
85 tabe: (args...) => @tabedit(args...)
86
87 tabnew: (range, args) =>
88 if args.trim() is ''
89 atom.workspace.open()
90 else
91 @tabedit(range, args)
92
93 tabclose: (args...) => @quit(args...)
94
95 tabc: => @tabclose()
96
97 tabnext: ->
98 pane = atom.workspace.getActivePane()
99 pane.activateNextItem()
100
101 tabn: => @tabnext()
102
103 tabprevious: ->
104 pane = atom.workspace.getActivePane()
105 pane.activatePreviousItem()
106
107 tabp: => @tabprevious()
108
109 edit: (range, filePath) ->
110 filePath = filePath.trim()
111 if filePath[0] is '!'
112 force = true
113 filePath = filePath[1..].trim()
114 else
115 force = false
116
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')
122
123 if filePath.length isnt 0
124 fullPath = getFullPath(filePath)
125 if fullPath is editor.getPath()
126 editor.getBuffer().reload()
127 else
128 atom.workspace.open(fullPath)
129 else
130 if editor.getPath()?
131 editor.getBuffer().reload()
132 else
133 throw new CommandError('No file name')
134
135 e: (args...) => @edit(args...)
136
137 enew: ->
138 buffer = atom.workspace.getActiveTextEditor().buffer
139 buffer.setPath(undefined)
140 buffer.load()
141
142 write: (range, filePath) ->
143 if filePath[0] is '!'
144 force = true
145 filePath = filePath[1..]
146 else
147 force = false
148
149 filePath = filePath.trim()
150 if filePath.indexOf(' ') isnt -1
151 throw new CommandError('Only one file name allowed')
152
153 deferred = Promise.defer()
154
155 editor = atom.workspace.getActiveTextEditor()
156 saved = false
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)
162 saved = true
163 else if not fullPath?
164 fullPath = atom.showSaveDialogSync()
165
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)
170
171 deferred.promise
172
173 w: (args...) =>
174 @write(args...)
175
176 wq: (args...) =>
177 @write(args...).then => @quit()
178
179 xit: (args...) => @wq(args...)
180
181 wa: ->
182 atom.workspace.saveAll()
183
184 split: (range, args) ->
185 args = args.trim()
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
192 do ->
193 atom.workspace.openURIInPane file, newPane
194 else
195 pane.splitUp(copyActiveItem: true)
196
197 sp: (args...) => @split(args...)
198
199 substitute: (range, args) ->
200 args = args.trimLeft()
201 delim = args[0]
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}")
206 spl = []
207 args_ = args[1..]
208 while (i = args_.search(delimRE)) isnt -1
209 spl.push args_[..i]
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
214 spl.push args_
215 if spl.length > 3
216 throw new CommandError('Trailing characters')
217 spl[1] ?= ''
218 spl[2] ?= ''
219 notDelimRE = new RegExp("\\\\#{delim}", 'g')
220 spl[0] = spl[0].replace(notDelimRE, delim)
221 spl[1] = spl[1].replace(notDelimRE, delim)
222
223 try
224 pattern = new RegExp(spl[0], spl[2])
225 catch e
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..]}")
231 else
232 throw e
233
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]))
241 )
242
243 s: (args...) => @substitute(args...)
244
245 vsplit: (range, args) ->
246 args = args.trim()
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
253 do ->
254 atom.workspace.openURIInPane file, newPane
255 else
256 pane.splitLeft(copyActiveItem: true)
257
258 vsp: (args...) => @vsplit(args...)
259
260 delete: (range) ->
261 range = [[range[0], 0], [range[1] + 1, 0]]
262 atom.workspace.getActiveTextEditor().buffer.setTextInRange(range, '')
263
264 set: (range, args) ->
265 args = args.trim()
266 if args == ""
267 throw new CommandError("No option specified")
268 options = args.split(' ')
269 for option in options
270 do ->
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)
281 else
282 optionProcessor = VimOption.singleton()[option]
283 if not optionProcessor?
284 throw new CommandError("No such option: #{option}")
285 optionProcessor()
286
287 module.exports = Ex