@kyanny's blog

My thoughts, my life. Views/opinions are my own.


eshell 組み込みの cat, eshell/cat

なんか EUC-JP なファイルを eshell で cat すると、 UTF-8 な端末でも文字化けせずに表示される。どっかで出力時にエンコーディングをみて勝手に文字コード変換してるような。 head とか *cat とかすると化けるのでやっぱりここみたいだ。 em-unix.el てのに定義されてるらしい。 emulate の略かな。ファイルには aliases って書いてある。 M-x find-library em-unix.el でソース読める。

(defun eshell/cat (&rest args)
  "Implementation of cat in Lisp.
If in a pipeline, or the file is not a regular file, directory or
symlink, then revert to the system's definition of cat."
  (setq args (eshell-stringify-list (eshell-flatten-list args)))
  (if (or eshell-in-pipeline-p
	  (catch 'special
	    (eshell-for arg args
	      (unless (or (and (stringp arg)
			       (> (length arg) 0)
			       (eq (aref arg 0) ?-))
			  (let ((attrs (eshell-file-attributes arg)))
			    (and attrs (memq (aref (nth 8 attrs) 0)
					     '(?d ?l ?-)))))
		(throw 'special t)))))
      (let ((ext-cat (eshell-search-path "cat")))
	(if ext-cat
	    (throw 'eshell-replace-command
		   (eshell-parse-command ext-cat args))
	  (if eshell-in-pipeline-p
	      (error "Eshell's `cat' does not work in pipelines")
	    (error "Eshell's `cat' cannot display one of the files given"))))
     "cat" args
     '((?h "help" nil nil "show this usage screen")
       :external "cat"
       :usage "[OPTION] FILE...
Concatenate FILE(s), or standard input, to standard output.")
     (eshell-for file args
       (if (string= file "-")
	   (throw 'eshell-external
		  (eshell-external-command "cat" args))))
     (let ((curbuf (current-buffer)))
       (eshell-for file args
	   (insert-file-contents file)
	   (goto-char (point-min))
	   (while (not (eobp))
	     (let ((str (buffer-substring
			 (point) (min (1+ (line-end-position))
	       (with-current-buffer curbuf
		 (eshell-buffered-print str)))
     ;; if the file does not end in a newline, do not emit one
     (setq eshell-ensure-newline-p nil))))

(put 'eshell/cat 'eshell-no-numeric-conversions t)

emacs lisp の関数は他の関数をむちゃくちゃ使いまくるのでタグジャンプとか使わないととても読めないな。