2009年1月8日木曜日

【ELp入門】8 テキストのカットと保存


  • 前説

    • バッファからテキストをkillするとkill ringというリストに格納される。yankするとkill ringからテキスト要素が返される。
    • 本章では、kill ringとzap-to-char関数について説明する。

  • 8.1 zap-to-char

    • 第22版での関数の実装

      (defun zap-to-char (arg char)
      "Kill up to and including ARG'th occurrence of CHAR.
      Case is ignored if `case-fold-search' is non-nil in the current buffer.
      Goes backward if ARG is negative; error if CHAR not found."
      (interactive "p\ncZap to char: ")
      (if (char-table-p translation-table-for-input)
      (setq char (or (aref translation-table-for-input char) char)))
      (kill-region (point) (progn
      (search-forward (char-to-string char) nil nil arg)
      ; (goto-char (if (> arg 0) (1- (point)) (1+ (point))))
      (point))))

    • 関数の本体は(kill-region point-a point-b)。point-aからpoint-bまでの領域をkillする。
    • search-forwardは、pointを移動するという副作用を目的とした関数である。

  • 8.2 kill-region

    • 第22版での実装は多少長くなっているようだ。

      (defun kill-region (beg end &optional yank-handler)
      "Kill (\"cut\") text between point and mark.
      This deletes the text from the buffer and saves it in the kill ring.
      The command \\[yank] can retrieve it from there.
      \(If you want to kill and then yank immediately, use \\[kill-ring-save].)

      If you want to append the killed region to the last killed text,
      use \\[append-next-kill] before \\[kill-region].

      If the buffer is read-only, Emacs will beep and refrain from deleting
      the text, but put the text in the kill ring anyway. This means that
      you can use the killing commands to copy text from a read-only buffer.

      This is the primitive for programs to kill text (as opposed to deleting it).
      Supply two arguments, character positions indicating the stretch of text
      to be killed.
      Any command that calls this function is a \"kill command\".
      If the previous command was also a kill command,
      the text killed this time appends to the text killed last time
      to make one entry in the kill ring.

      In Lisp code, optional third arg YANK-HANDLER, if non-nil,
      specifies the yank-handler text property to be set on the killed
      text. See `insert-for-yank'."
      ;; Pass point first, then mark, because the order matters
      ;; when calling kill-append.
      (interactive (list (point) (mark)))
      (unless (and beg end)
      (error "The mark is not set now, so there is no region"))
      (condition-case nil
      (let ((string (filter-buffer-substring beg end t)))
      (when string ;STRING is nil if BEG = END
      ;; Add that string to the kill ring, one way or another.
      (if (eq last-command 'kill-region)
      (kill-append string (< end beg) yank-handler)
      (kill-new string nil yank-handler)))
      (when (or string (eq last-command 'kill-region))
      (setq this-command 'kill-region))
      nil)
      ((buffer-read-only text-read-only)
      ;; The code above failed because the buffer, or some of the characters
      ;; in the region, are read-only.
      ;; We should beep, in case the user just isn't aware of this.
      ;; However, there's no harm in putting
      ;; the region's text in the kill ring, anyway.
      (copy-region-as-kill beg end)
      ;; Set this-command now, so it will be set even if we get an error.
      (setq this-command 'kill-region)
      ;; This should barf, if appropriate, and give us the correct error.
      (if kill-read-only-ok
      (progn (message "Read only text copied to kill ring") nil)
      ;; Signal an error if the buffer is read-only.
      (barf-if-buffer-read-only)
      ;; If the buffer isn't read-only, the text is.
      (signal 'text-read-only (list (current-buffer)))))))

    • kill-regionのある意味本体は、filter-buffer-stringとkill-newに移ったようだ。

      (defun filter-buffer-substring (beg end &optional delete noprops)
      "Return the buffer substring between BEG and END, after filtering.
      The buffer substring is passed through each of the filter
      functions in `buffer-substring-filters', and the value from the
      last filter function is returned. If `buffer-substring-filters'
      is nil, the buffer substring is returned unaltered.

      If DELETE is non-nil, the text between BEG and END is deleted
      from the buffer.

      If NOPROPS is non-nil, final string returned does not include
      text properties, while the string passed to the filters still
      includes text properties from the buffer text.

      Point is temporarily set to BEG before calling
      `buffer-substring-filters', in case the functions need to know
      where the text came from.

      This function should be used instead of `buffer-substring',
      `buffer-substring-no-properties', or `delete-and-extract-region'
      when you want to allow filtering to take place. For example,
      major or minor modes can use `buffer-substring-filters' to
      extract characters that are special to a buffer, and should not
      be copied into other buffers."
      (cond
      ((or delete buffer-substring-filters)
      (save-excursion
      (goto-char beg)
      (let ((string (if delete (delete-and-extract-region beg end)
      (buffer-substring beg end))))
      (dolist (filter buffer-substring-filters)
      (setq string (funcall filter string)))
      (if noprops
      (set-text-properties 0 (length string) nil string))
      string)))
      (noprops
      (buffer-substring-no-properties beg end))
      (t
      (buffer-substring beg end))))


      (defun kill-new (string &optional replace yank-handler)
      "Make STRING the latest kill in the kill ring.
      Set `kill-ring-yank-pointer' to point to it.
      If `interprogram-cut-function' is non-nil, apply it to STRING.
      Optional second argument REPLACE non-nil means that STRING will replace
      the front of the kill ring, rather than being added to the list.

      Optional third arguments YANK-HANDLER controls how the STRING is later
      inserted into a buffer; see `insert-for-yank' for details.
      When a yank handler is specified, STRING must be non-empty (the yank
      handler, if non-nil, is stored as a `yank-handler' text property on STRING).

      When the yank handler has a non-nil PARAM element, the original STRING
      argument is not used by `insert-for-yank'. However, since Lisp code
      may access and use elements from the kill ring directly, the STRING
      argument should still be a \"useful\" string for such uses."
      (if (> (length string) 0)
      (if yank-handler
      (put-text-property 0 (length string)
      'yank-handler yank-handler string))
      (if yank-handler
      (signal 'args-out-of-range
      (list string "yank-handler specified for empty string"))))
      (if (fboundp 'menu-bar-update-yank-menu)
      (menu-bar-update-yank-menu string (and replace (car kill-ring))))
      (if (and replace kill-ring)
      (setcar kill-ring string)
      (push string kill-ring)
      (if (> (length kill-ring) kill-ring-max)
      (setcdr (nthcdr (1- kill-ring-max) kill-ring) nil)))
      (setq kill-ring-yank-pointer kill-ring)
      (if interprogram-cut-function
      (funcall interprogram-cut-function string (not replace))))

    • そして、C関数として、delete-and-extract-regionを使うようだ。(delete-regionではない)

  • 8.3 delete-region : Cへの回り道

    • さはさりなんで、delete-regionをみてみる。
    • editfns.cに含まれている。
    • そうか。EmacsというのはElispインタプリタの上に書かれているというのがちょっとはばかられるほど、Cで書かれている部分がありそうだ。

  • 8.4 defvarによる変数の初期化

    • defvarの紹介。
    • elispは動的スコープしかないので、あっさり。

  • 8.5 copy-region-as-kill

    • kill-apped, kill-newのことは、上記のとおり、kill-regionにも含まれている。

      (defun copy-region-as-kill (beg end)
      "Save the region as if killed, but don't kill it.
      In Transient Mark mode, deactivate the mark.
      If `interprogram-cut-function' is non-nil, also save the text for a window
      system cut and paste."
      (interactive "r")
      (if (eq last-command 'kill-region)
      (kill-append (filter-buffer-substring beg end) (< end beg))
      (kill-new (filter-buffer-substring beg end)))
      (if transient-mark-mode
      (setq deactivate-mark t))
      nil)

    • そしてkill-ringに関する処理は、kill-newに移っている。


こつこつ。

0 件のコメント: