読者です 読者をやめる 読者になる 読者になる

blechmusikの日記

キー・カスタマイズ・ソフトウェア "DvorakJ" の覚え書きをはじめとして様々なことを書いています。

print-mode-line mode(モードライン拡張minor-mode)に機能を追加してみた

「print-mode-line mode(モードライン拡張minor-mode)」が便利だ - blechmusik2の日記の続きである。
現在選択しているリージョンまたはセレクション内に関し、文字数と行数を常に表示するようにした*1。つぎの画像のように情報が表示されることになる。

後日追記:加除訂正を施して処理を高速化させた結果、次のように表示されるようになった。

print-mode-line-mode.lの末尾に以下の設定を追加すること。

; http://www2.ocn.ne.jp/~cheerful/script/xyzzy/mode/printmodelinemode.html

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


(defun selection-p ()
  (if (eql (get-selection-type) 2)
      t
    nil))

(defun region-p ()
  (if (mark t)
      t
    nil))

(defun count-chars-ax (kind)
  (interactive)
  (count-chars-words-lines-ax :kind kind :target 'chars))

(defun count-words-ax (kind)
  (interactive)
  (count-chars-words-lines-ax :kind kind :target 'words))

(defun count-lines-ax (kind)
  (interactive)
  (count-chars-words-lines-ax :kind kind :target 'lines))

(defun count-chars-words-lines-ax (&key kind target)
  (interactive)
  (cond
   ((or (and (string= kind 'selection) (selection-p))
        (and (string= kind 'both)      (selection-p)))
    (count-chars-words-lines (selection-mark) (selection-point) target))
   ((or (and (string= kind 'region) (region-p))
        (and (string= kind 'both)   (region-p)))
    (count-chars-words-lines (region-beginning) (region-end) target))
   (t 0)))

(defun count-chars-words-lines (start end target)
  (case target
    ('chars (count-chars start end))
    ('words (count-words start end))
    ('lines (count-lines start end))))

(defun count-chars (start end)
  (interactive)
  (when (> start end)
    (rotatef start end))
  (let ((chars (- (abs (- end start))
                  (count-lines start end))))
    chars))

(defun count-words (start end)
  (interactive)
  (when (> start end)
    (rotatef start end))
  (let ((words 0))
    (save-excursion
      (save-restriction
        (narrow-to-region start end)
        (goto-char start)
        (while (< (point) end)
          (forward-word 1)
          (setf words (1+ words)))
        (widen)))
    words))

(defun count-lines (start end)
  (interactive)
  (let (from to)
    (save-excursion
      (save-restriction
        (narrow-to-region start end)
        (goto-char start)
        (setf from (current-line-number))
        (goto-char end)
        (setf to (current-line-number))
        (widen)))
    (abs (- to from))))

(compile 'count-chars)
(compile 'count-words)
(compile 'count-lines)


(defun string-region-or-selection ()
  (interactive)
  (cond
   ((selection-p) (format nil "~A" "selection"))
   ((region-p)    (format nil "~A" "region"))
   (t             (format nil "~A" "--"))))


(defun string-count-chars-ax ()
  (format nil "~D" (count-chars-ax 'both)))
(defun string-count-words-ax ()
  (format nil "~D" (count-words-ax 'both)))
(defun string-count-lines-ax ()
  (format nil "~D" (count-lines-ax 'both)))


(defmacro dolist-and-push (alst lst)
  `(dolist (x ,alst)
     (push (list (car x) (cdr x)) ,lst)))


(dolist-and-push '(("%rs-" . string-region-or-selection)
		   ("%rsc" . string-count-chars-ax)
		   ("%rsw" . string-count-words-ax)
		   ("%rsn" . string-count-lines-ax))
		 *print-mode-line-mode-list*)

.xyzzyには以下の三行を書けばよい。

(load-library "print-mode-line-mode")
(setq mode-line-format "[%i] %* %b (%M) | WC:%c/%w/%n (%rs-: %rsc/%rsw/%rsn) | place:%/%% |  [%k:%l] %P %f")
(print-mode-line-mode)