kill-commands.sl 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % Kill-Commands.SL - NMODE Kill and Delete commands
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 23 August 1982
  8. % Revised: 16 November 1982
  9. %
  10. % 16-Nov-82 Alan Snyder
  11. % Modified C-Y and M-Y to obey comamnd argument.
  12. %
  13. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  14. (CompileTime (load objects fast-vectors fast-int))
  15. (load gsort)
  16. (fluid '(nmode-current-buffer nmode-command-argument
  17. nmode-command-argument-given nmode-command-number-given
  18. nmode-previous-command-killed nmode-command-killed
  19. ))
  20. % Internal static variables:
  21. (fluid '(nmode-kill-ring))
  22. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  23. (de nmode-initialize-kill-ring ()
  24. (setf nmode-kill-ring (ring-buffer-create 16))
  25. (setf nmode-command-killed NIL)
  26. )
  27. (de insert-kill-buffer ()
  28. % Insert the specified "kill buffer" into the buffer at the current location.
  29. (cond
  30. ((<= nmode-command-argument 0)
  31. (Ding))
  32. (nmode-command-number-given
  33. (insert-from-kill-ring (+ (- nmode-command-argument) 1) NIL))
  34. (nmode-command-argument-given
  35. (insert-from-kill-ring 0 T))
  36. (t
  37. (insert-from-kill-ring 0 NIL))
  38. ))
  39. (de insert-from-kill-ring (index flip-positions)
  40. (insert-text-safely (=> nmode-kill-ring fetch index) flip-positions)
  41. )
  42. (de insert-text-safely (text flip-positions)
  43. (cond (text
  44. (=> nmode-current-buffer set-mark-from-point)
  45. (insert-text text)
  46. (when flip-positions (exchange-point-and-mark))
  47. )
  48. (t (Ding))
  49. ))
  50. (de safe-to-unkill ()
  51. % Return T if the current region contains the same text as the current
  52. % kill buffer.
  53. (let ((killed-text (ring-buffer-top nmode-kill-ring))
  54. (region (extract-text NIL (buffer-get-position) (current-mark)))
  55. )
  56. (and killed-text (text-equal killed-text region))
  57. ))
  58. (de unkill-previous ()
  59. % Delete (without saving away) the current region, and then unkill (yank) the
  60. % specified entry in the kill ring. "Ding" if the current region does not
  61. % contain the same text as the current entry in the kill ring.
  62. (cond ((not (safe-to-unkill))
  63. (Ding))
  64. ((= nmode-command-argument 0)
  65. (extract-region T (buffer-get-position) (current-mark)))
  66. (t
  67. (extract-region T (buffer-get-position) (current-mark))
  68. (=> nmode-kill-ring rotate (- nmode-command-argument))
  69. (insert-from-kill-ring 0 NIL)
  70. )
  71. ))
  72. (de update-kill-buffer (kill-info)
  73. % Update the "kill buffer", either appending/prepending to the current
  74. % buffer, or "pushing" the kill ring, as appropriate. kill-info is a pair,
  75. % the car of which is +1 if the text was "forward killed", and -1 if
  76. % "backwards killed". The cdr is the actual text (a vector of strings).
  77. (let ((killed-text (cdr kill-info))
  78. (dir (car kill-info))
  79. )
  80. (if (not nmode-previous-command-killed)
  81. % If previous command wasn't a kill, then "push" the new text.
  82. (ring-buffer-push nmode-kill-ring killed-text)
  83. % Otherwise, append or prepend the text, as appropriate.
  84. (let ((text (ring-buffer-top nmode-kill-ring)))
  85. % Swap the two pieces of text if deletion was "backwards".
  86. (if (< dir 0) (psetf text killed-text killed-text text))
  87. % Replace text with the concatenation of the two.
  88. (ring-buffer-pop nmode-kill-ring)
  89. (ring-buffer-push nmode-kill-ring (text-append text killed-text))
  90. ))))
  91. (de text-append (t1 t2)
  92. % Append two text-vectors.
  93. % The last line of T1 is concatenated with the first line of T2.
  94. (let ((text (MkVect (+ (vector-upper-bound t1) (vector-upper-bound t2))))
  95. (ti 0) % index into TEXT
  96. )
  97. (for (from i 0 (- (vector-upper-bound t1) 1))
  98. (do (vector-store text ti (vector-fetch t1 i))
  99. (setf ti (+ ti 1))
  100. ))
  101. (vector-store text ti
  102. (string-concat (vector-fetch t1 (vector-upper-bound t1))
  103. (vector-fetch t2 0)))
  104. (setf ti (+ ti 1))
  105. (for (from i 1 (vector-upper-bound t2))
  106. (do (vector-store text ti (vector-fetch t2 i))
  107. (setf ti (+ ti 1))
  108. ))
  109. text))
  110. (de text-equal (t1 t2)
  111. % Compare two text vectors for equality.
  112. (let ((limit (vector-upper-bound t1)))
  113. (and (= limit (vector-upper-bound t2))
  114. (for (from i 0 limit)
  115. (always (string= (vector-fetch t1 i) (vector-fetch t2 i)))
  116. ))))
  117. (de kill-region ()
  118. % Kill (and save in kill buffer) the region between point and mark.
  119. (update-kill-buffer (extract-region T (buffer-get-position) (current-mark)))
  120. (setf nmode-command-killed T)
  121. )
  122. (de copy-region ()
  123. (update-kill-buffer (extract-region NIL (buffer-get-position) (current-mark)))
  124. )
  125. (de append-to-buffer-command ()
  126. (let* ((text (cdr (extract-region NIL (buffer-get-position) (current-mark))))
  127. (b (prompt-for-buffer "Append Region to Buffer: " NIL))
  128. )
  129. (=> b insert-text text)
  130. ))
  131. (de prompt-for-register-name (prompt)
  132. % Prompt for the name of a "Register", which must be a letter
  133. % or a digit. Return the corresponding Lisp Symbol. Return NIL
  134. % if an invalid name is given.
  135. (nmode-set-delayed-prompt prompt)
  136. (let ((ch (input-base-character)))
  137. (cond ((AlphaNumericP ch)
  138. (intern (string-concat "nmode-register-" (string ch))))
  139. (t (Ding) NIL))))
  140. (de put-register-command ()
  141. (let ((register (prompt-for-register-name
  142. (if nmode-command-argument-given
  143. "Withdraw Region to Register: "
  144. "Copy Region to Register: "))))
  145. (cond (register
  146. (set register (cdr (extract-region nmode-command-argument-given
  147. (buffer-get-position)
  148. (current-mark))))
  149. ))))
  150. (de get-register-command ()
  151. (let ((register (prompt-for-register-name "Insert from Register: "))
  152. (old-pos (buffer-get-position))
  153. )
  154. (cond (register
  155. (cond ((BoundP register)
  156. (insert-text (ValueCell register))
  157. (set-mark-from-point)
  158. (buffer-set-position old-pos)
  159. (if nmode-command-argument-given
  160. (exchange-point-and-mark))
  161. )
  162. (t (Ding))
  163. )))))
  164. (de append-next-kill-command ()
  165. (if (ring-buffer-top nmode-kill-ring) % If there is a kill buffer...
  166. (setf nmode-command-killed T)
  167. ))
  168. (de kill-line ()
  169. (let ((old-pos (buffer-get-position)))
  170. (if nmode-command-argument-given
  171. (cond ((> nmode-command-argument 0)
  172. % Kill through that many line terminators
  173. (for (from i 1 nmode-command-argument)
  174. (do (move-to-next-line)))
  175. )
  176. ((= nmode-command-argument 0)
  177. % Kill preceding text on this line
  178. (move-to-start-of-line)
  179. )
  180. (t
  181. % Kill through that many previous line starts
  182. % This line counts only if we are not at the beginning of it.
  183. (if (not (at-line-start?))
  184. (progn
  185. (move-to-start-of-line)
  186. (setf nmode-command-argument (+ nmode-command-argument 1))
  187. ))
  188. (for (from i 1 (- nmode-command-argument))
  189. (do (move-to-previous-line)))
  190. ))
  191. % else (no argument given)
  192. (while (char-blank? (next-character))
  193. (move-forward))
  194. (if (at-line-end?)
  195. (move-to-next-line)
  196. (move-to-end-of-line)
  197. )
  198. )
  199. (update-kill-buffer (extract-region T old-pos (buffer-get-position)))
  200. (setf nmode-command-killed T)
  201. ))
  202. (de kill-forward-word-command ()
  203. (delete-words nmode-command-argument)
  204. (setf nmode-command-killed T)
  205. )
  206. (de kill-backward-word-command ()
  207. (delete-words (- nmode-command-argument))
  208. (setf nmode-command-killed T)
  209. )
  210. (de kill-forward-form-command ()
  211. (delete-forms nmode-command-argument)
  212. (setf nmode-command-killed T)
  213. )
  214. (de kill-backward-form-command ()
  215. (delete-forms (- nmode-command-argument))
  216. (setf nmode-command-killed T)
  217. )
  218. (de delete-backward-character-command ()
  219. (cond
  220. (nmode-command-argument-given
  221. (delete-characters (- nmode-command-argument))
  222. (setf nmode-command-killed T))
  223. (t
  224. (if (at-buffer-start?)
  225. (Ding)
  226. (delete-previous-character)
  227. ))))
  228. (de delete-forward-character-command ()
  229. (cond
  230. (nmode-command-argument-given
  231. (delete-characters nmode-command-argument)
  232. (setf nmode-command-killed T))
  233. (t
  234. (if (at-buffer-end?)
  235. (Ding)
  236. (delete-next-character)
  237. ))))
  238. (de delete-backward-hacking-tabs-command ()
  239. (cond
  240. (nmode-command-argument-given
  241. (delete-characters-hacking-tabs (- nmode-command-argument))
  242. (setf nmode-command-killed T))
  243. (t
  244. (if (at-buffer-start?)
  245. (Ding)
  246. (move-backward-character-hacking-tabs)
  247. (delete-next-character)
  248. ))))
  249. (de transpose-words ()
  250. (let ((old-pos (buffer-get-position)))
  251. (cond ((not (attempt-to-transpose-words nmode-command-argument))
  252. (Ding)
  253. (buffer-set-position old-pos)
  254. ))))
  255. (de attempt-to-transpose-words (n)
  256. % Returns non-NIL if successful.
  257. (prog (bp1 bp2 bp3 bp4 word1 word2)
  258. (cond ((= n 0)
  259. (setf bp1 (buffer-get-position))
  260. (if (not (move-forward-word)) (return NIL))
  261. (setf bp2 (buffer-get-position))
  262. (buffer-set-position (current-mark))
  263. (setf bp3 (buffer-get-position))
  264. (if (not (move-forward-word)) (return NIL))
  265. (setf bp4 (buffer-get-position))
  266. (exchange-regions bp3 bp4 bp1 bp2)
  267. (move-backward-word)
  268. )
  269. (t
  270. (if (not (move-backward-word)) (return NIL))
  271. (setf bp1 (buffer-get-position))
  272. (if (not (move-forward-word)) (return NIL))
  273. (setf bp2 (buffer-get-position))
  274. (if (not (move-over-words (if (< n 0) (- n 1) n))) (return NIL))
  275. (setf bp4 (buffer-get-position))
  276. (if (not (move-over-words (- 0 n))) (return NIL))
  277. (setf bp3 (buffer-get-position))
  278. (exchange-regions bp1 bp2 bp3 bp4)
  279. ))
  280. (return T)
  281. ))
  282. (de transpose-lines ()
  283. (let ((old-pos (buffer-get-position)))
  284. (cond ((not (attempt-to-transpose-lines nmode-command-argument))
  285. (Ding)
  286. (buffer-set-position old-pos)
  287. ))))
  288. (de attempt-to-transpose-lines (n)
  289. % Returns non-NIL if successful.
  290. (prog (bp1 bp2 bp3 bp4 line1 line2 current marked last)
  291. (setf current (current-line-pos))
  292. (setf last (- (current-buffer-size) 1))
  293. % The last line doesn't count, because it is unterminated.
  294. (setf marked (buffer-position-line (current-mark)))
  295. (cond ((= n 0)
  296. (if (or (>= current last) (>= marked last)) (return NIL))
  297. (setf bp1 (buffer-position-create current 0))
  298. (setf bp2 (buffer-position-create (+ current 1) 0))
  299. (setf bp3 (buffer-position-create marked 0))
  300. (setf bp4 (buffer-position-create (+ marked 1) 0))
  301. (exchange-regions bp3 bp4 bp1 bp2)
  302. (move-to-previous-line)
  303. )
  304. (t
  305. % Dragged line is the previous one.
  306. (if (= current 0) (return NIL))
  307. (setf bp1 (buffer-position-create (- current 1) 0))
  308. (setf bp2 (buffer-position-create current 0))
  309. (setf marked (- (+ current n) 1))
  310. (if (or (< marked 0) (>= marked last)) (return NIL))
  311. (setf bp3 (buffer-position-create marked 0))
  312. (setf bp4 (buffer-position-create (+ marked 1) 0))
  313. (exchange-regions bp1 bp2 bp3 bp4)
  314. ))
  315. (return T)
  316. ))
  317. (de transpose-forms ()
  318. (let ((old-pos (buffer-get-position)))
  319. (cond ((not (attempt-to-transpose-forms nmode-command-argument))
  320. (Ding)
  321. (buffer-set-position old-pos)
  322. ))))
  323. (de attempt-to-transpose-forms (n)
  324. % Returns non-NIL if successful.
  325. (prog (bp1 bp2 bp3 bp4 form1 form2)
  326. (cond ((= n 0)
  327. (setf bp1 (buffer-get-position))
  328. (if (not (move-forward-form)) (return NIL))
  329. (setf bp2 (buffer-get-position))
  330. (buffer-set-position (current-mark))
  331. (setf bp3 (buffer-get-position))
  332. (if (not (move-forward-form)) (return NIL))
  333. (setf bp4 (buffer-get-position))
  334. (exchange-regions bp3 bp4 bp1 bp2)
  335. (move-backward-form)
  336. )
  337. (t
  338. (if (not (move-backward-form)) (return NIL))
  339. (setf bp1 (buffer-get-position))
  340. (if (not (move-forward-form)) (return NIL))
  341. (setf bp2 (buffer-get-position))
  342. (if (not (move-over-forms (if (< n 0) (- n 1) n))) (return NIL))
  343. (setf bp4 (buffer-get-position))
  344. (if (not (move-over-forms (- 0 n))) (return NIL))
  345. (setf bp3 (buffer-get-position))
  346. (exchange-regions bp1 bp2 bp3 bp4)
  347. ))
  348. (return T)
  349. ))
  350. (de transpose-regions ()
  351. (let ((old-pos (buffer-get-position)))
  352. (cond ((not (attempt-to-transpose-regions nmode-command-argument))
  353. (Ding)
  354. (buffer-set-position old-pos)
  355. ))))
  356. (de attempt-to-transpose-regions (n)
  357. % Returns non-NIL if successful.
  358. % Transpose regions defined by cursor and three most recent marks.
  359. % EMACS resets all of the marks; we just reset the cursor to the
  360. % end of the higher region.
  361. (prog (bp1 bp2 bp3 bp4 bp-list)
  362. (setf bp1 (buffer-get-position))
  363. (setf bp2 (current-mark))
  364. (setf bp3 (previous-mark))
  365. (setf bp4 (previous-mark))
  366. (previous-mark)
  367. (setf bp-list (list bp1 bp2 bp3 bp4))
  368. (gsort bp-list (function buffer-position-lessp))
  369. (exchange-regions (first bp-list)
  370. (second bp-list)
  371. (third bp-list)
  372. (fourth bp-list))
  373. (buffer-set-position (fourth bp-list))
  374. (return T)
  375. ))
  376. % Support functions:
  377. (de delete-characters (n)
  378. (let ((old-pos (buffer-get-position)))
  379. (move-over-characters n)
  380. (update-kill-buffer
  381. (extract-region T old-pos (buffer-get-position)))
  382. ))
  383. (de delete-characters-hacking-tabs (n)
  384. % Note: EMACS doesn't try to hack tabs when deleting forward.
  385. % We do, but it's a crock. What should really happen is that all
  386. % consecutive tabs are converted to spaces.
  387. (cond ((< n 0)
  388. % Deleting backwards is tricky because the conversion of tabs to
  389. % spaces may change the numeric value of the original "position".
  390. % Our solution is to first move backwards the proper number of
  391. % characters (converting tabs to spaces), and then move back over them.
  392. (let ((count (- n)))
  393. (setf n 0)
  394. (while (and (> count 0)
  395. (move-backward-character-hacking-tabs))
  396. (setf count (- count 1))
  397. (setf n (- n 1))
  398. )
  399. (move-over-characters (- n))
  400. )))
  401. (let ((old-pos (buffer-get-position)))
  402. (move-over-characters-hacking-tabs n)
  403. (update-kill-buffer
  404. (extract-region T old-pos (buffer-get-position)))
  405. ))
  406. (de delete-words (n)
  407. (let ((old-pos (buffer-get-position)))
  408. (move-over-words n)
  409. (update-kill-buffer
  410. (extract-region T old-pos (buffer-get-position)))
  411. ))
  412. (de delete-forms (n)
  413. (let ((old-pos (buffer-get-position)))
  414. (move-over-forms n)
  415. (update-kill-buffer
  416. (extract-region T old-pos (buffer-get-position)))
  417. ))
  418. (de exchange-regions (bp1 bp2 bp3 bp4)
  419. % The specified positions define two regions: R1=<BP1,BP2> and
  420. % R2=<BP3,BP4>. These regions should not overlap, unless they
  421. % are identical. The contents of the two regions will be exchanged.
  422. % The cursor will be moved to the right of the region R1 (in its new
  423. % position).
  424. (let ((dir (buffer-position-compare bp1 bp3))
  425. (r1 (cdr (extract-region NIL bp1 bp2)))
  426. (r2 (cdr (extract-region NIL bp3 bp4)))
  427. )
  428. (cond ((< dir 0) % R1 is before R2
  429. (extract-region T bp3 bp4)
  430. (insert-text r1)
  431. (extract-region T bp1 bp2)
  432. (insert-text r2)
  433. (buffer-set-position bp4)
  434. )
  435. ((> dir 0) % R2 is before R1
  436. (extract-region T bp1 bp2)
  437. (insert-text r2)
  438. (extract-region T bp3 bp4)
  439. (insert-text r1)
  440. ))
  441. ))