3 -- XXX: in Lua 5.2 unpack() was moved into table
4 local unpack
= unpack
or table.unpack
6 local function startof(node
) return node
.start
end
7 local function finishof(node
) return node
.finish
end
8 local function is_comment(node
) return node
.is_comment
end
10 function M
.new(parser
, walker
, fmt
, write, delete
)
12 local function normalize_spacing(start
, delta
, list
)
14 table.insert(list
, {start
+ delta
, -delta
})
16 table.insert(list
, {start
, -delta
})
21 local function refmt_list(parent
, base_indent
, padj
, deltas
, keep_electric_space
)
23 local pstart
= parent
.start
+ (parent
.p
and #parent
.p
or 0) + #parent
.d
24 if parent
.is_empty
then
25 normalize_spacing(pstart
, parent
.finish
- pstart
, deltas
)
28 for i
, s
in ipairs(parent
) do
30 adj
= s
.indent
and 0 or adj
31 local prev
= parent
[i
- 1]
32 if not s
.indent
and not (prev
and (s
.d
== "|" or prev
.d
== "|")) then
33 -- remove/add leading spaces
34 local off
= prev
and prev
.finish
+ 1 or pstart
35 adj
= adj
+ normalize_spacing(off
, s
.start
- off
- (prev
and 1 or 0), deltas
)
37 local nxt
= parent
[i
+ 1]
38 local is_last
= not nxt
39 if (is_last
and not keep_electric_space
) or nxt
and nxt
.indent
then
40 -- clean up trailing spaces
41 local has_eol
= s
.is_comment
and parser
.opposite
[s
.d
] == "\n"
42 local off
= is_last
and parent
.finish
- (has_eol
and i
< #parent
and 1 or 0) or nxt
.start
- nxt
.indent
- 1
43 local finish
= s
.finish
+ (has_eol
and i
< #parent
and 0 or 1)
44 normalize_spacing(finish
, off
- finish
, deltas
)
47 delta
= base_indent
- s
.indent
48 local last_distinguished
= fmt
:last_distinguished(parent
)
49 if last_distinguished
then
51 if i
- 1 <= last_distinguished
then
55 -- remove leading space, if any
56 delta
= -(s
.start
- pstart
)
57 elseif -- align further arguments below the second one
58 parent
.d
== "(" -- [] and {} contain data, so no arguments
59 and not parent
[1].is_string
-- a string can't have arguments
60 --and not parent[1].is_list -- wrong, GNU Emacs compatible behaviour
62 if i
> 2 and not parent
[2].indent
then
63 delta
= base_indent
+ parent
[2].start
- pstart
- s
.indent
65 if delta
< 0 then delta
= math
.max(-s
.indent
, delta
) end
68 table.insert(deltas
, {s
.start
, delta
})
73 local nearest_indented
= s
.indent
and s
or parent
.find_before(s
, function(t
) return t
.indent
end)
74 local parent_column
= nearest_indented
and
75 nearest_indented
.indent
+ (s
.start
+ (s
.p
and #s
.p
or 0) + #s
.d
) - nearest_indented
.start
76 or base_indent
+ (s
.start
+ (s
.p
and #s
.p
or 0) + #s
.d
) - pstart
77 refmt_list(s
, parent_column
- adj
, padj
+ adj
, deltas
, keep_electric_space
)
83 local function refmt_at(scope
, range
, keep_electric_space
)
84 if not range
or not scope
or scope
.is_root
then return end
85 local parent
= walker
.sexp_at(scope
, true)
86 if not (parent
and parent
.is_list
) then return end
87 local _
, parent_at
, m
= walker
.sexp_at(range
, true)
89 _
, m
= parent_at
.after(range
.start
, startof
)
94 local base
= parent_at
[m
] or parent_at
95 local path
= walker
.sexp_path(base
)
96 local after_start
, at_pfinish
98 local s
= parent_at
[#parent_at
]
99 local has_eol
= s
.is_comment
and parser
.opposite
[s
.d
] == "\n"
100 if range
.start
>= s
.finish
+ 1 + (has_eol
and 1 or 0) then
103 after_start
= range
.start
< base
.start
and 0 or range
.start
- base
.start
106 after_start
= (parent_at
.p
and #parent_at
.p
or 0) + #parent_at
.d
108 local indented_parent
= parent
.indent
and parent
or parent
.is_list
and walker
.indented_before(parent
)
109 local parent_column
= indented_parent
and (indented_parent
.indent
+ parent
.start
- indented_parent
.start
+
110 (parent
.p
and #parent
.p
or 0) + #parent
.d
) or
112 local deltas
= refmt_list(parent
, parent_column
, 0, {}, keep_electric_space
)
113 table.sort(deltas
, function(d1
, d2
) return d1
[1] > d2
[1] end)
114 for _
, pair
in ipairs(deltas
) do
115 local offset
, delta
= unpack(pair
)
117 write(offset
, string.rep(" ", delta
))
118 elseif delta
< 0 then
119 delete(offset
+ delta
, -delta
)
122 parser
.tree
.rewind(parent
.start
or 0)
124 local sexp
, parentng
= walker
.goto_path(path
)
127 return parentng
.finish
129 return sexp
.start
+ after_start
136 local function splice(pos
, sexps
, skip
, backwards
, action
)
138 local sexp
= walker
.sexp_at(skip
, true)
139 local start
= sexp
.start
+ (sexp
.p
and #sexp
.p
or 0)
140 local tosplice
= action
.splice
or action
.wrap
or sexp
.is_empty
141 local opening
= (sexp
.p
or '')..sexp
.d
142 local closing
= parser
.opposite
[sexp
.d
]
143 local real_start
= tosplice
and sexp
.start
or start
+ #sexp
.d
144 local splice_closing
= closing
~= "\n" or sexp
.is_empty
145 local real_finish
= sexp
.finish
+ 1 - (tosplice
and splice_closing
and 0 or #closing
)
146 local first
= backwards
and
147 {start
= real_start
, finish
= math
.max(pos
, start
+ #sexp
.d
)} or
148 {start
= real_start
, finish
= sexp
.is_empty
and pos
or start
+ #sexp
.d
}
149 local second
= backwards
and
150 {start
= sexp
.is_empty
and pos
or sexp
.finish
+ 1 - #closing
, finish
= real_finish
} or
151 {start
= math
.min(pos
, sexp
.finish
+ 1 - #closing
), finish
= real_finish
}
156 local ndeleted
= first
.finish
- first
.start
+ second
.finish
- second
.start
158 sexps
.rewind(sexp
.start
)
161 return first
.finish
- first
.start
, spliced
, opening
, closing
164 local function pick_out(range
, pos
, action
)
165 local sexps
= parser
.tree
166 local skips
= sexps
.unbalanced_delimiters(range
)
167 -- handle splice and kill-splice of forms and strings:
169 local sexp
= walker
.sexp_at(skips
[1], true)
170 local backward_splice
= skips
[1].opening
and pos
>= sexp
.start
+ (sexp
.p
and #sexp
.p
or 0) + #sexp
.d
171 and range
.start
>= sexp
.start
172 local forward_splice
= skips
[1].closing
and pos
<= sexp
.finish
+ 1 - #parser
.opposite
[sexp
.d
]
173 and range
.finish
<= sexp
.finish
+ 1
174 if backward_splice
or forward_splice
then
175 return splice(backward_splice
and range
.finish
or range
.start
, sexps
, sexp
, backward_splice
, action
)
178 local node
, parent
= walker
.sexp_at({start
= range
.finish
, finish
= range
.finish
})
179 local drop_eol
= node
and node
.finish
+ 1 == range
.finish
and node
.is_comment
and parser
.opposite
[node
.d
] == "\n"
180 table.sort(skips
, function(a
, b
) return a
.start
< b
.start
end)
181 table.insert(skips
, {start
= range
.finish
- (drop_eol
and 1 or 0)})
182 table.insert(skips
, 1, {finish
= range
.start
})
183 local ndeleted
= drop_eol
and 1 or 0
184 for i
= #skips
- 1, 1, -1 do
185 local region
= {start
= skips
[i
].finish
, finish
= skips
[i
+ 1].start
}
186 if skips
[i
].closing
and skips
[i
+ 1].opening
then
187 -- leave out some of the space between adjacent lists
188 local _
, rparent
= walker
.sexp_at(region
)
189 local nxt
= rparent
.after(region
.start
, startof
)
190 region
.start
= nxt
and nxt
.start
or region
.start
194 ndeleted
= ndeleted
+ (region
.finish
- region
.start
)
197 -- if parent[#parent + 1] is nil, we are at EOF
198 if ndeleted
> 0 and (not parent
.is_root
or parent
.is_parsed(range
.start
) or parent
[#parent
+ 1]) then
199 sexps
.rewind(range
.start
)
204 local function raise_sexp(range
, pos
)
205 local sexp
, parent
= walker
.sexp_at(range
, true)
206 if sexp
and parent
and parent
.is_list
then
207 delete(sexp
.finish
+ 1, parent
.finish
- sexp
.finish
)
208 delete(parent
.start
, sexp
.start
- parent
.start
)
209 parser
.tree
.rewind(parent
.start
)
210 range
.start
= parent
.start
+ pos
- sexp
.start
211 range
.finish
= range
.start
212 local _
, nodes
= walker
.sexp_path(range
)
213 local grandparent
= nodes
[#nodes
- 2]
214 return grandparent
and refmt_at(grandparent
, range
) or range
.start
218 local function slurp_sexp(range
, forward
)
219 local _
, parent
= walker
.sexp_at(range
, true)
220 local seeker
= forward
and walker
.finish_after
or walker
.start_before
221 if not parent
or not parent
.is_list
then return range
.start
end
222 local r
= {start
= parent
.start
, finish
= parent
.finish
+ 1}
223 local newpos
= seeker(r
, is_comment
)
224 if not newpos
then return range
.start
end
225 local opening
= (parent
.p
or '')..parent
.d
226 local closing
= parser
.opposite
[parent
.d
]
227 local delimiter
= forward
and closing
or opening
229 write(newpos
, delimiter
)
231 delete(forward
and parent
.finish
or parent
.start
, #delimiter
)
233 write(newpos
, delimiter
)
235 parser
.tree
.rewind(math
.min(parent
.start
, newpos
))
236 local _
, parentng
= walker
.sexp_at(range
, true)
237 return refmt_at(parentng
, range
)
240 local function barf_sexp(range
, forward
)
241 local _
, parent
, m
= walker
.sexp_at(range
, true)
242 local seeker
= forward
and walker
.finish_before
or walker
.start_after
243 -- TODO: barfing out of strings requires calling the parser on them
244 if not parent
or not parent
.is_list
then return range
.start
end
245 local opening
= (parent
.p
or '')..parent
.d
246 local pstart
= parent
.start
+ #opening
247 local r
= {start
= forward
and parent
.finish
- 1 or pstart
, finish
= forward
and parent
.finish
or pstart
+ 1}
248 local newpos
= seeker(r
, is_comment
) or forward
and pstart
or parent
.finish
249 if not newpos
then return range
.start
end
250 local closing
= parser
.opposite
[parent
.d
]
251 local delimiter
= forward
and closing
or opening
253 write(newpos
, delimiter
)
255 delete(forward
and parent
.finish
or parent
.start
, #delimiter
)
257 write(newpos
, delimiter
)
259 parser
.tree
.rewind(math
.min(parent
.start
, newpos
))
260 local barfed_cursor_backward
= m
== 1 and not forward
261 local barfed_cursor_forward
= m
== #parent
and forward
262 range
.start
= range
.start
+ #delimiter
* (barfed_cursor_backward
and -1 or barfed_cursor_forward
and 1 or 0)
263 local barfed_cursor
= barfed_cursor_forward
or barfed_cursor_backward
264 local _
, nodes
= walker
.sexp_path(range
)
265 local parentng
, grandparent
= nodes
[#nodes
- 1], nodes
[#nodes
- 2]
266 local scope
= barfed_cursor
and parentng
and not parentng
.is_root
and parentng
or grandparent
267 return refmt_at(scope
, range
) or range
.start
270 local function splice_sexp(range
, _
)
271 local _
, parent
= walker
.sexp_at(range
)
272 if not parent
or not parent
.d
then return end
273 local opening
= (parent
.p
or '')..parent
.d
274 local closing
= parser
.opposite
[parent
.d
]
275 local finish
= parent
.finish
+ 1 - #closing
276 if closing
~= "\n" then
277 delete(finish
, #closing
)
279 -- TODO: (un)escape special characters, if necessary
280 delete(parent
.start
, parent
.is_empty
and (finish
- parent
.start
) or #opening
)
281 parser
.tree
.rewind(parent
.start
)
282 range
.start
= range
.start
- #opening
283 range
.finish
= range
.start
284 local _
, parentng
= walker
.sexp_at(range
, true)
285 return refmt_at(parentng
, range
)
288 local function rewrap(parent
, kind
)
289 local pstart
= parent
.start
+ #((parent
.p
or '')..parent
.d
) - 1
290 delete(parent
.finish
, 1)
291 write(parent
.finish
, parser
.opposite
[kind
])
292 delete(pstart
, #parent
.d
)
294 parser
.tree
.rewind(parent
.start
)
297 local function cycle_wrap(range
, pos
)
298 local _
, parent
= walker
.sexp_at(range
)
299 if not parent
or not parent
.is_list
then return end
300 local next_kind
= {["("] = "[", ["["] = "{", ["{"] = "("}
301 rewrap(parent
, next_kind
[parent
.d
])
305 local function split_sexp(range
)
306 local _
, parent
= walker
.sexp_at(range
)
307 if not (parent
and parent
.d
) then return end
308 local new_finish
, new_start
309 if parent
.is_list
then
310 local prev
= parent
.before(range
.start
, finishof
, is_comment
)
311 new_finish
= prev
and prev
.finish
+ 1
312 -- XXX: do not skip comments here, so they end up in the second list
313 -- and are not separated from their target expression:
314 local nxt
= new_finish
and parent
.after(new_finish
, startof
)
315 new_start
= nxt
and nxt
.start
317 new_start
= range
.start
318 new_finish
= range
.start
320 if not (new_start
and new_finish
) then return end
321 local opening
= (parent
.p
or '')..parent
.d
322 local closing
= parser
.opposite
[parent
.d
]
323 write(new_start
, opening
)
324 local sep
= parser
.opposite
[parent
.d
] == "\n" and "" -- line comments already have a separator
325 or new_finish
== new_start
and " " -- only add a separator if there was none before
327 write(new_finish
, closing
..sep
)
328 parser
.tree
.rewind(parent
.start
)
329 range
.start
= new_start
+ (parent
.is_list
and 0 or #opening
+ #closing
)
330 range
.finish
= range
.start
331 local _
, nodes
= walker
.sexp_path(range
)
332 local parentng
, grandparent
= nodes
[#nodes
- 1], nodes
[#nodes
- 2]
333 local scope
= parentng
and not parentng
.is_root
and parentng
or grandparent
334 return refmt_at(scope
, range
) or range
.start
337 local function join_sexps(range
)
338 local node
, parent
= walker
.sexp_at(range
, true)
339 local first
= node
and node
.finish
+ 1 == range
.start
and node
or parent
.before(range
.start
, finishof
)
340 local second
= first
~= node
and node
or parent
.after(range
.start
, startof
)
341 if not (first
and second
and first
.d
and
342 (first
.d
== second
.d
or
343 -- join line comments even when their delimiters differ slightly
344 -- (different number of semicolons, existence/lack of a space after them)
345 parser
.opposite
[first
.d
] == parser
.opposite
[second
.d
])) then
348 local opening
= (second
.p
or '')..second
.d
349 local closing
= parser
.opposite
[first
.d
]
351 if not first
.is_list
then
352 pos
= first
.finish
+ 1 - #closing
353 delete(pos
, second
.start
+ #opening
- pos
)
355 delete(second
.start
, #opening
)
356 delete(first
.finish
, #closing
)
357 pos
= second
.start
- #closing
359 parser
.tree
.rewind(first
.start
)
361 range
.finish
= range
.start
362 local _
, nodes
= walker
.sexp_path(range
)
363 local parentng
, grandparent
= nodes
[#nodes
- 1], nodes
[#nodes
- 2]
364 local scope
= parentng
and not parentng
.is_root
and parentng
or grandparent
365 return refmt_at(scope
, range
) or range
.start
368 local function delete_splicing(range
, pos
, splicing
, delete_and_yank
)
369 local action
= {kill
= true, wrap
= splicing
, splice
= splicing
, func
= delete_and_yank
}
370 local sexp
, parent
, n
= walker
.sexp_at(range
, true)
371 local ndeleted
, spliced
= pick_out(range
, pos
, action
)
372 local closing
= spliced
and parser
.opposite
[sexp
.d
]
373 local inner_list_len
= spliced
and sexp
.finish
- sexp
.start
+ 1 - #sexp
.d
- #closing
374 local range_len
= range
.finish
- range
.start
375 local backwards
= pos
== range
.finish
376 local whole_object
= sexp
and
377 (sexp
.start
== range
.start
and sexp
.finish
+ 1 == range
.finish
378 or spliced
and (inner_list_len
<= (backwards
and range_len
+ ndeleted
or range_len
)))
379 local in_head_atom
= sexp
and not sexp
.d
and n
== 1 and #parent
> 1
380 local in_whitespace
= not sexp
381 if whole_object
or in_whitespace
or in_head_atom
then
382 local cur
= whole_object
and sexp
.start
or range
.start
383 -- if parent[#parent + 1] is nil, we are at EOF
384 if not parent
.is_root
or parent
.is_parsed(cur
) or parent
[#parent
+ 1] then
385 parser
.tree
.rewind(cur
)
387 local r
= {start
= cur
, finish
= cur
}
388 local _
, parentng
= walker
.sexp_at(r
, true)
389 local newpos
= refmt_at(parentng
, r
)
392 return spliced
and (backwards
and sexp
.start
or range
.start
- ndeleted
)
393 or not backwards
and ndeleted
<= 0 and range
.finish
- ndeleted
397 local function transpose(range
, first
, second
)
398 if not (first
and second
) then return end
399 local copy1
= first
.text
400 local copy2
= second
.text
401 delete(second
.start
, second
.finish
+ 1 - second
.start
)
402 write(second
.start
, copy1
)
403 delete(first
.start
, first
.finish
+ 1 - first
.start
)
404 write(first
.start
, copy2
)
405 parser
.tree
.rewind(first
.start
)
406 range
.start
= second
.finish
+ 1
407 range
.finish
= range
.start
408 local _
, parentng
= walker
.sexp_at(range
, true)
409 return refmt_at(parentng
, range
) or range
.start
412 local function transpose_sexps(range
)
413 local node
, parent
= walker
.sexp_at(range
, true)
414 local first
= node
and node
.finish
+ 1 == range
.start
and node
or parent
.before(range
.start
, finishof
)
415 local second
= first
~= node
and node
or parent
.after(range
.start
, startof
)
416 return transpose(range
, first
, second
)
419 local function transpose_words(range
)
420 local _
, first
= walker
.start_float_before(range
)
421 local _
, second
= walker
.finish_float_after(range
)
422 if first
and second
and first
.start
== second
.start
then
423 _
, first
= walker
.start_float_before(first
)
425 return transpose(range
, first
, second
)
428 local function transpose_chars(range
)
429 local node
, parent
, i
= walker
.sexp_at(range
)
430 local nxt
= i
and parent
[i
+ 1]
431 local pstart
= not parent
.is_root
and parent
.start
+ (parent
.p
and #parent
.p
or 0) + #parent
.d
432 local pfinish
= not parent
.is_root
and parent
.finish
433 local npref
= node
and node
.p
and node
.start
+ #node
.p
434 -- only allow transposing while inside atoms/words and prefixes
435 if node
and ((npref
and (range
.start
<= npref
and range
.start
> node
.start
) or
436 node
.d
and range
.start
> node
.finish
+ 1) or not node
.d
and (not pstart
or range
.start
> pstart
)) then
437 local start
= range
.start
-
438 ((range
.start
== pfinish
or range
.start
== npref
or
439 range
.start
== node
.finish
+ 1 and (parent
.is_list
or parent
.is_root
) and (not nxt
or nxt
.indent
)) and 1 or 0)
440 local str_start
= start
- node
.start
+ 1
441 local char
= node
.text
:sub(str_start
, str_start
)
443 write(start
- 1, #char
> 0 and char
or " ")
444 parser
.tree
.rewind(start
)
445 local in_head_atom
= i
== 1 and #parent
> 1
446 return parent
.is_list
and in_head_atom
447 and refmt_at(parent
, {start
= start
+ 1, finish
= start
+ 1})
452 local function delete_nonsplicing(range
, pos
, delete_maybe_yank
)
453 local action
= {kill
= true, wrap
= false, splice
= false, func
= delete_maybe_yank
}
454 local ndeleted
, spliced
, opening
= pick_out(range
, pos
, action
)
455 local backwards
= pos
== range
.finish
458 return pos
- ndeleted
460 if ndeleted
== 0 then
461 local closing
= parser
.opposite
[opening
]
462 if closing
== "\n" then
463 local sexp
= walker
.sexp_at(range
)
464 if pos
== sexp
.start
+ #sexp
.d
then
465 return join_sexps(range
) or pos
466 elseif pos
== sexp
.finish
then
467 local r
= {start
= pos
+ #closing
, finish
= pos
+ #closing
}
468 return join_sexps(r
) or pos
+ #closing
472 return backwards
and (range
.finish
- ndeleted
) or range
.start
475 return backwards
and range
.start
or (range
.finish
- ndeleted
)
479 local function make_wrap(kind
)
480 return function(range
, pos
, auto_square
)
483 local node
, parent
= walker
.sexp_at(range
, true)
484 if parent
.is_root
then
485 -- FIXME: don't do that at the end of a defun
488 local nxt
= parent
.after(range
.finish
, startof
)
489 if not (nxt
and nxt
.indent
and node
and (node
.finish
+ 1 <= range
.start
)) then
494 local function _wrap(r
)
495 local indices
, nodes
= walker
.sexp_path(r
)
496 local delimiter
, closing
= opening
, parser
.opposite
[opening
]
497 local squarewords
= fmt
.squarewords
498 if squarewords
and (auto_square
or squarewords
.not_optional
)
499 and not fmt
:adjust_bracket_p(indices
, nodes
, r
) then
500 delimiter
, closing
= "[", "]"
502 write(r
.finish
, closing
)
503 write(r
.start
, delimiter
)
505 local action
= {kill
= false, wrap
= false, splice
= false, func
= _wrap
}
506 pick_out(range
, pos
, action
)
507 parser
.tree
.rewind(range
.start
)
508 local _
, parentng
= walker
.sexp_at(range
, true)
509 range
.start
= range
.start
+ #opening
510 return refmt_at(parentng
, range
) or range
.start
514 local function newline(parent
, range
)
515 if not parent
.is_list
then
516 if parent
.d
and parser
.opposite
[parent
.d
] == "\n" and range
.start
< parent
.finish
+ 1 then
517 local newpos
= split_sexp(range
)
522 -- if parent[#parent + 1] is nil, we are at EOF
523 if not parent
.is_root
or parent
.is_parsed(range
.start
) or parent
[#parent
+ 1] then
524 parser
.tree
.rewind(parent
.start
or range
.start
)
528 local last_nonblank_in_list
= parent
[#parent
] and parent
[#parent
].finish
or parent
.start
529 local nxt
= parent
.is_list
and parent
.after(range
.start
, startof
)
530 local last_on_line
= nxt
and nxt
.indent
and nxt
.start
> range
.start
531 local after_last
= range
.start
> last_nonblank_in_list
532 local placeholder
= "asdf"
533 write(range
.start
, "\n"..((after_last
or last_on_line
) and placeholder
or ""))
534 parser
.tree
.rewind(parent
.start
or range
.start
)
535 -- move the cursor onto the placeholder, so refmt_at can restore the position:
536 nxt
= parent
.is_list
and walker
.start_after(range
) or range
.start
+ 1
537 local rangeng
= {start
= nxt
, finish
= nxt
}
538 local newpos
= refmt_at(parent
, rangeng
) or rangeng
.start
540 local _
, parentng
= walker
.sexp_at({start
= newpos
, finish
= newpos
}, true)
541 local autoindent
= parentng
[#parentng
].indent
542 write(parentng
.finish
, "\n"..string.rep(" ", autoindent
or 0))
544 if after_last
or last_on_line
then
545 delete(newpos
, #placeholder
)
547 parser
.tree
.rewind(newpos
)
551 local function close_and_newline(range
)
552 local _
, parent
= walker
.sexp_at(range
)
553 if parent
and not parent
.is_root
then
554 local r
= {start
= parent
.finish
, finish
= parent
.finish
}
555 local newpos
= refmt_at(parent
, r
)
556 r
= {start
= (newpos
or r
.finish
) + 1, finish
= (newpos
or r
.finish
) + 1}
557 local list
, parentng
= walker
.sexp_at(r
)
558 newpos
= newline(parentng
, {start
= list
.finish
+ 1, finish
= list
.finish
+ 1})
560 newpos
= list
.finish
+ 1
569 delete_splicing
= delete_splicing
,
570 delete_nonsplicing
= delete_nonsplicing
,
573 raise_sexp
= raise_sexp
,
574 slurp_sexp
= slurp_sexp
,
575 barf_sexp
= barf_sexp
,
576 splice_sexp
= splice_sexp
,
577 wrap_round
= make_wrap("("),
578 meta_doublequote
= make_wrap('"'),
579 comment_dwim
= make_wrap(";"),
581 close_and_newline
= close_and_newline
,
582 cycle_wrap
= cycle_wrap
,
583 split_sexp
= split_sexp
,
584 join_sexps
= join_sexps
,
585 transpose_sexps
= transpose_sexps
,
586 transpose_words
= transpose_words
,
587 transpose_chars
= transpose_chars
,